Decorator-maker used to declare measurements for phases.

  See the measurements module docstring for examples of usage.

  Args:
    measurements: Measurement objects to declare, or a string name from which
        to create a Measurement.
    kwargs: Keyword arguments to pass to Measurement constructor if we're
        constructing one.  Note that if kwargs are provided, the length
        of measurements must be 1, and that value must be a string containing
        the measurement name.  For valid kwargs, see the definition of the
        Measurement class.

  Returns:
    A decorator that declares the measurement(s) for the decorated phase.

def measures(*measurements, **kwargs):
  """Decorator-maker used to declare measurements for phases.

  See the measurements module docstring for examples of usage.

  Args:
    measurements: Measurement objects to declare, or a string name from which
        to create a Measurement.
    kwargs: Keyword arguments to pass to Measurement constructor if we're
        constructing one.  Note that if kwargs are provided, the length
        of measurements must be 1, and that value must be a string containing
        the measurement name.  For valid kwargs, see the definition of the
        Measurement class.

  Returns:
    A decorator that declares the measurement(s) for the decorated phase.
  """
  def _maybe_make(meas):
    """Turn strings into Measurement objects if necessary."""
    if isinstance(meas, Measurement):
      return meas
    elif isinstance(meas, six.string_types):
      return Measurement(meas, **kwargs)
    raise InvalidMeasurementType('Expected Measurement or string', meas)

  # In case we're declaring a measurement inline, we can only declare one.
  if kwargs and len(measurements) != 1:
    raise InvalidMeasurementType(
        'If @measures kwargs are provided, a single measurement name must be '
        'provided as a positional arg first.')

  # Unlikely, but let's make sure we don't allow overriding initial outcome.
  if 'outcome' in kwargs:
    raise ValueError('Cannot specify outcome in measurement declaration!')

  measurements = [_maybe_make(meas) for meas in measurements]

  # 'measurements' is guaranteed to be a list of Measurement objects here.
  def decorate(wrapped_phase):
    """Phase decorator to be returned."""
    phase = phase_descriptor.PhaseDescriptor.wrap_or_copy(wrapped_phase)
    duplicate_names = (set(m.name for m in measurements) &
                       set(m.name for m in phase.measurements))
    if duplicate_names:
      raise DuplicateNameError('Measurement names duplicated', duplicate_names)

    phase.measurements.extend(measurements)
    return phase
  return decorate