Return a new PhaseDescriptor from the given function or instance.

    We want to return a new copy so that you can reuse a phase with different
    options, plugs, measurements, etc.

    Args:
      func: A phase function or PhaseDescriptor instance.
      **options: Options to update on the result.

    Raises:
      PhaseWrapError: if func is a openhtf.PhaseGroup.

    Returns:
      A new PhaseDescriptor object.

def wrap_or_copy(cls, func, **options):
    """Return a new PhaseDescriptor from the given function or instance.

    We want to return a new copy so that you can reuse a phase with different
    options, plugs, measurements, etc.

    Args:
      func: A phase function or PhaseDescriptor instance.
      **options: Options to update on the result.

    Raises:
      PhaseWrapError: if func is a openhtf.PhaseGroup.

    Returns:
      A new PhaseDescriptor object.
    """
    if isinstance(func, openhtf.PhaseGroup):
      raise PhaseWrapError('Cannot wrap PhaseGroup <%s> as a phase.' % (
          func.name or 'Unnamed'))
    if isinstance(func, cls):
      # We want to copy so that a phase can be reused with different options
      # or kwargs.  See with_args() below for more details.
      retval = mutablerecords.CopyRecord(func)
    else:
      retval = cls(func)
    retval.options.update(**options)
    return retval