Beispiel #1
0
    def with_plugs(self,
                   **subplugs: Type[base_plugs.BasePlug]) -> 'PhaseDescriptor':
        """Substitute plugs for placeholders for this phase.

    Args:
      **subplugs: dict of plug name to plug class, plug classes to replace;
        unknown plug names are ignored.  A base_plugs.InvalidPlugError is raised
        when a test includes a phase that still has a placeholder plug.

    Raises:
      base_plugs.InvalidPlugError: if for one of the plug names one of the
        following is true:
        - The new plug subclass is not a subclass of the original.
        - The original plug class is not a placeholder or automatic placeholder.

    Returns:
      PhaseDescriptor with updated plugs.
    """
        plugs_by_name = {plug.name: plug for plug in self.plugs}
        new_plugs = {}

        for name, sub_class in six.iteritems(subplugs):
            original_plug = plugs_by_name.get(name)
            accept_substitute = True
            if original_plug is None:
                continue
            elif isinstance(original_plug.cls, base_plugs.PlugPlaceholder):
                accept_substitute = issubclass(sub_class,
                                               original_plug.cls.base_class)
            else:
                # Check __dict__ to see if the attribute is explicitly defined in the
                # class, rather than being defined in a parent class.
                accept_substitute = (
                    'auto_placeholder' in original_plug.cls.__dict__
                    and original_plug.cls.auto_placeholder
                    and issubclass(sub_class, original_plug.cls))

            if not accept_substitute:
                raise base_plugs.InvalidPlugError(
                    'Could not find valid placeholder for substitute plug %s '
                    'required for phase %s' % (name, self.name))
            new_plugs[name] = data.attr_copy(original_plug, cls=sub_class)

        if not new_plugs:
            return self

        plugs_by_name.update(new_plugs)

        return data.attr_copy(
            self,
            plugs=list(plugs_by_name.values()),
            options=self.options.format_strings(**subplugs),
            measurements=[m.with_args(**subplugs) for m in self.measurements])
Beispiel #2
0
  def with_args(self, **kwargs: Any) -> 'PhaseDescriptor':
    """Send keyword-arguments to the phase when called.

    Args:
      **kwargs: mapping of argument name to value to be passed to the phase
        function when called.  Unknown arguments are ignored.

    Returns:
      Updated PhaseDescriptor.
    """
    if six.PY3:
      argspec = inspect.getfullargspec(self.func)
      argspec_keywords = argspec.varkw
    else:
      argspec = inspect.getargspec(self.func)  # pylint: disable=deprecated-method
      argspec_keywords = argspec.keywords
    known_arguments = {}
    for key, arg in six.iteritems(kwargs):
      if key in argspec.args or argspec_keywords:
        known_arguments[key] = arg

    new_info = data.attr_copy(self)
    new_info.options = new_info.options.format_strings(**kwargs)
    new_info.extra_kwargs.update(known_arguments)
    new_info.measurements = [m.with_args(**kwargs) for m in self.measurements]
    return new_info
Beispiel #3
0
  def wrap_or_copy(cls, func: PhaseT, **options: Any) -> 'PhaseDescriptor':
    """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.
    """
    # TODO(arsharma): Remove when type annotations are more enforced.
    if isinstance(func, openhtf.PhaseGroup):
      raise PhaseWrapError('Cannot wrap PhaseGroup <%s> as a phase.' %
                           (func.name or 'Unnamed'))  # pytype: disable=attribute-error
    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 = data.attr_copy(func)
    else:
      retval = cls(func)
    retval.options.update(**options)
    return retval
Beispiel #4
0
 def with_args(self, **kwargs: Any) -> 'Measurement':
     """String substitution for names and docstrings."""
     new_validators = [
         v.with_args(**kwargs) if hasattr(v, 'with_args') else v
         for v in self.validators
     ]
     new_conditional_validators = [
         cv.with_args(**kwargs) for cv in self.conditional_validators
     ]
     return data.attr_copy(
         self,
         name=util.format_string(self.name, kwargs),
         docstring=util.format_string(self.docstring, kwargs),
         validators=new_validators,
         conditional_validators=new_conditional_validators,
         cached=None,
     )
Beispiel #5
0
    def from_measurement(
            cls,
            measurement: measurements.Measurement) -> 'ImmutableMeasurement':
        """Convert a Measurement into an ImmutableMeasurement."""
        measured_value = measurement.measured_value
        if isinstance(measured_value, measurements.DimensionedMeasuredValue):
            value = data.attr_copy(measured_value,
                                   value_dict=copy.deepcopy(
                                       measured_value.value_dict))
        else:
            value = (copy.deepcopy(measured_value.value)
                     if measured_value.is_value_set else None)

        return cls(name=measurement.name,
                   value=value,
                   units=measurement.units,
                   dimensions=measurement.dimensions,
                   outcome=measurement.outcome)
Beispiel #6
0
 def copy(self: WithModifierT) -> WithModifierT:
   """Create a copy of the PhaseNode."""
   return data.attr_copy(self)
Beispiel #7
0
 def with_plugs(self, **subplugs: Any) -> 'Checkpoint':
   return data.attr_copy(self, name=util.format_string(self.name, subplugs))
Beispiel #8
0
 def with_args(self, **kwargs: Any) -> 'Checkpoint':
   return data.attr_copy(self, name=util.format_string(self.name, kwargs))
Beispiel #9
0
 def load_code_info(self) -> 'PhaseDescriptor':
   """Load code info for this phase."""
   return data.attr_copy(
       self, code_info=test_record.CodeInfo.for_function(self.func))
Beispiel #10
0
 def format_strings(self, **kwargs: Any) -> 'PhaseOptions':
   """String substitution of name."""
   return data.attr_copy(self, name=util.format_string(self.name, kwargs))
Beispiel #11
0
 def _context_wrapper(
         *phases: phase_descriptor.PhaseCallableOrNodeT
 ) -> 'PhaseGroup':
     return cls(setup=data.attr_copy(setup) if setup else None,
                main=phase_collections.PhaseSequence(phases),
                teardown=data.attr_copy(teardown) if teardown else None)