예제 #1
0
 def __init__(self, *args, **kwargs):
   super(TestRecord, self).__init__(*args, **kwargs)
   # Cache data that does not change during execution.
   # Cache the metadata config so it does not recursively copied over and over
   # again.
   self._cached_config_from_metadata = self.metadata.get('config')
   self._cached_record = {
       'station_id': data.convert_to_base_types(self.station_id),
       'code_info': data.convert_to_base_types(self.code_info),
   }
예제 #2
0
 def convert_to_dict(self, test_record):
   if self.inline_attachments:
     as_dict = data.convert_to_base_types(test_record)
     for phase in as_dict['phases']:
       for value in phase['attachments'].itervalues():
         value['data'] = base64.standard_b64encode(value['data'])
   else:
     as_dict = data.convert_to_base_types(test_record,
                                          ignore_keys=('attachments',))
   return as_dict
예제 #3
0
 def as_base_types(self):
   """Convert to a dict representation composed exclusively of base types."""
   base_types_dict = {
       k: data.convert_to_base_types(getattr(self, k))
       for k in self.optional_attributes
   }
   base_types_dict.update(
       descriptor_id=self.descriptor_id,
       name=self.name,
       codeinfo=data.convert_to_base_types(self.codeinfo),
   )
   return base_types_dict
예제 #4
0
  def _summary_for_state_dict(state_dict):
    """Return a dict for state with counts swapped in for phase/log records."""
    state_dict_summary = {
        k: v for k, v in six.iteritems(state_dict) if k != 'plugs'}
    state_dict_summary['test_record'] = data.convert_to_base_types(
        state_dict_summary['test_record'])
    state_dict_summary['test_record']['phases'] = len(
        state_dict_summary['test_record']['phases'])
    state_dict_summary['test_record']['log_records'] = len(
        state_dict_summary['test_record']['log_records'])
    state_dict_summary['running_phase_state'] = data.convert_to_base_types(
        state_dict_summary['running_phase_state'], tuple_type=list)

    return state_dict_summary
예제 #5
0
 def _asdict(self):
   asdict = {
       key: data.convert_to_base_types(getattr(self, key), ignore_keys=('cls',))
       for key in self.optional_attributes
   }
   asdict.update(name=self.name, doc=self.doc)
   return asdict
예제 #6
0
    def cached_state_summary(self):
        """Get our cached state as a dict, with phases/records swapped out.

    Returns:
      Cached state used to generate the dict, and a dict representation
    of that state, with phases/records swapped out for respective counts.
    This is used to send to a running test so only have to send back new
    phases and log records.
    """
        cached_state = self.cached_state

        if not cached_state:
            return None, None

        test_record = mutablerecords.CopyRecord(
            cached_state.test_record,
            phases=len(cached_state.test_record.phases),
            log_records=len(cached_state.test_record.log_records),
        )

        return (
            cached_state,
            {
                "status": cached_state.status.name,
                "running_phase_state": data.convert_to_base_types(cached_state.running_phase_state),
                "test_record": xmlrpclib.Binary(pickle.dumps(test_record)),
            },
        )
예제 #7
0
 def __init__(self, *args, **kwargs):
   super(PhaseState, self).__init__(*args, **kwargs)
   for m in six.itervalues(self.measurements):
     # Using functools.partial to capture the value of the loop variable.
     m.set_notification_callback(functools.partial(self._notify, m.name))
   self._cached = {
       'name': self.name,
       'codeinfo': data.convert_to_base_types(self.phase_record.codeinfo),
       'descriptor_id': data.convert_to_base_types(
           self.phase_record.descriptor_id),
       # Options are not set until the phase is finished.
       'options': None,
       'measurements': {
           k: m.as_base_types() for k, m in six.iteritems(self.measurements)},
       'attachments': {},
   }
예제 #8
0
 def get_history_after(self, test_uid, start_time_millis):
   """Get a list of TestRecords for test_uid from the History."""
   _LOG.debug('RPC:get_history_after(%s)', start_time_millis)
   # TODO(madsci): We really should pull attachments out of band here.
   return [data.convert_to_base_types(test_record)
           for test_record in history.for_test_uid(
               test_uid, start_after_millis=start_time_millis)]
예제 #9
0
  def __setitem__(self, coordinates, value):  # pylint: disable=invalid-name
    coordinates_len = len(coordinates) if hasattr(coordinates, '__len__') else 1
    if coordinates_len != self.num_dimensions:
      raise InvalidDimensionsError(
          'Expected %s-dimensional coordinates, got %s' % (self.num_dimensions,
                                                           coordinates_len))

    # Wrap single dimensions in a tuple so we can assume value_dict keys are
    # always tuples later.
    if self.num_dimensions == 1:
      coordinates = (coordinates,)

    if coordinates in self.value_dict:
      _LOG.warning(
          'Overriding previous measurement %s[%s] value of %s with %s',
          self.name, coordinates, self.value_dict[coordinates], value)
      self._cached_basetype_values = None
    elif self._cached_basetype_values is not None:
      self._cached_basetype_values.append(data.convert_to_base_types(
          coordinates + (value,)))

    self.value_dict[coordinates] = value

    if self.notify_value_set:
      self.notify_value_set()
예제 #10
0
 def as_base_types(self):
   """Convert to a dict representation composed exclusively of base types."""
   metadata = data.convert_to_base_types(self.metadata,
                                         ignore_keys=('config',))
   metadata['config'] = self._cached_config_from_metadata
   ret = {
       'dut_id': data.convert_to_base_types(self.dut_id),
       'start_time_millis': self.start_time_millis,
       'end_time_millis': self.end_time_millis,
       'outcome': data.convert_to_base_types(self.outcome),
       'outcome_details': data.convert_to_base_types(self.outcome_details),
       'metadata': metadata,
       'phases': self._cached_phases,
       'log_records': self._cached_log_records,
   }
   ret.update(self._cached_record)
   return ret
예제 #11
0
  def _serialize_state_dict(state_dict, remote_record=None):
    if (remote_record and
        remote_record['start_time_millis'] ==
        state_dict['test_record'].start_time_millis):
      # Make a copy and delete phases/logs that are already known remotely.
      state_dict['test_record'] = mutablerecords.CopyRecord(
          state_dict['test_record'])
      del state_dict['test_record'].phases[:remote_record['phases']]
      del state_dict['test_record'].log_records[:remote_record['log_records']]

    return {
        'status': state_dict['status'].name,
        'test_record': data.convert_to_base_types(state_dict['test_record']),
        'plugs': state_dict['plugs'],
        'running_phase_state':
            data.convert_to_base_types(state_dict['running_phase_state'])
    }
예제 #12
0
 def __init__(self, description='', unit=units.NO_DIMENSION):
   self._description = description
   self._unit = unit
   self._cached_dict = data.convert_to_base_types({
       'code': self.code,
       'description': self.description,
       'name': self.name,
       'suffix': self.suffix,
   })
예제 #13
0
  def _to_dict_with_event(cls, test_state):
    """Process a test state into the format we want to send to the frontend."""
    original_dict, event = test_state.asdict_with_event()

    # This line may produce a 'dictionary changed size during iteration' error.
    test_state_dict = data.convert_to_base_types(original_dict)

    test_state_dict['execution_uid'] = test_state.execution_uid
    return test_state_dict, event
예제 #14
0
 def convert_to_dict(self, test_record):
   as_dict = data.convert_to_base_types(test_record,
                                        json_safe=(not self.allow_nan))
   if self.inline_attachments:
     for phase, original_phase in zip(as_dict['phases'], test_record.phases):
       for name, attachment in six.iteritems(phase['attachments']):
         original_data = original_phase.attachments[name].data
         attachment['data'] = base64.standard_b64encode(original_data).decode('utf-8')
   return as_dict
예제 #15
0
 def as_base_types(self):
   """Convert to a dict representation composed exclusively of base types."""
   running_phase_state = None
   if self.running_phase_state:
     running_phase_state = self.running_phase_state.as_base_types()
   return {
       'status': data.convert_to_base_types(self._status),
       'test_record': self.test_record.as_base_types(),
       'plugs': self.plug_manager.as_base_types(),
       'running_phase_state': running_phase_state,
   }
예제 #16
0
 def as_base_types(self):
   """Convert this measurement to a dict of basic types."""
   if not self._cached:
     # Create the single cache file the first time this is called.
     self._cached = {
         'name': self.name,
         'outcome': self.outcome.name,
     }
     if self.validators:
       self._cached['validators'] = data.convert_to_base_types(
           tuple(str(v) for v in self.validators))
     if self.dimensions:
       self._cached['dimensions'] = data.convert_to_base_types(self.dimensions)
     if self.units:
       self._cached['units'] = data.convert_to_base_types(self.units)
     if self.docstring:
       self._cached['docstring'] = self.docstring
   if self.measured_value.is_value_set:
     self._cached['measured_value'] = self.measured_value.basetype_value()
   return self._cached
예제 #17
0
    def _summary_for_state_dict(state_dict):
        """Return a dict for state with counts swapped in for phase/log records."""
        state_dict_summary = {k: v for k, v in state_dict.iteritems() if k != "plugs"}
        state_dict_summary["test_record"] = mutablerecords.CopyRecord(state_dict_summary["test_record"])
        state_dict_summary["test_record"].phases = len(state_dict_summary["test_record"].phases)
        state_dict_summary["test_record"].log_records = len(state_dict_summary["test_record"].log_records)
        state_dict_summary["running_phase_state"] = data.convert_to_base_types(
            state_dict_summary["running_phase_state"], tuple_type=list
        )

        return state_dict_summary
예제 #18
0
  def get_phase_descriptors(self, test_uid):
    """Get phase descriptor fields for the given test UID.

    Returns:
      List of dicts of RemotePhaseDescriptor fields.

    Raises:
      UnrecognizedTestUidError: The test_uid is not recognized.
    """
    phases = openhtf.Test.from_uid(test_uid).descriptor.phases
    return [dict(id=id(phase), **data.convert_to_base_types(phase))
            for phase in phases]
예제 #19
0
  def get(self, test_uid):
    test, _ = self.get_test(test_uid)

    if test is None:
      return

    phase_descriptors = [
        dict(id=id(phase), **data.convert_to_base_types(phase))
        for phase in test.descriptor.phase_group]

    # Wrap value in a dict because writing a list directly is prohibited.
    self.write({'data': phase_descriptors})
예제 #20
0
    def _serialize_state_dict(state_dict, remote_record=None):
        if remote_record and remote_record.start_time_millis == state_dict["test_record"].start_time_millis:
            # Make a copy and delete phases/logs that are already known remotely.
            state_dict["test_record"] = mutablerecords.CopyRecord(state_dict["test_record"])
            del state_dict["test_record"].phases[: remote_record.phases]
            del state_dict["test_record"].log_records[: remote_record.log_records]

        return {
            "status": state_dict["status"].name,
            "test_record": xmlrpclib.Binary(pickle.dumps(state_dict["test_record"])),
            "plugs": state_dict["plugs"],
            "running_phase_state": data.convert_to_base_types(state_dict["running_phase_state"]),
        }
예제 #21
0
 def open_output_file(self, test_record):
   """Open file based on pattern."""
   record_dict = data.convert_to_base_types(test_record)
   pattern = self.filename_pattern
   if isinstance(pattern, basestring) or callable(pattern):
     output_file = self.open_file(util.format_string(pattern, **record_dict))
     try:
       yield output_file
     finally:
       output_file.close()
   elif hasattr(self.filename_pattern, 'write'):
     yield self.filename_pattern
   else:
     raise ValueError(
         'filename_pattern must be string, callable, or File-like object')
예제 #22
0
 def set(self, value):
   """Set the value for this measurement, with some sanity checks."""
   if self.is_value_set:
     # While we want to *allow* re-setting previously set measurements, we'd
     # rather promote the use of multidimensional measurements instead of
     # discarding data, so we make this somewhat chatty.
     _LOG.warning(
         'Overriding previous measurement %s value of %s with %s, the old '
         'value will be lost.  Use a dimensioned measurement if you need to '
         'save multiple values.', self.name, self.stored_value, value)
   if value is None:
     _LOG.warning('Measurement %s is set to None', self.name)
   self.stored_value = value
   self._cached_value = data.convert_to_base_types(value)
   self.is_value_set = True
예제 #23
0
 def open_output_file(self, test_record):
   """Open file based on pattern."""
   # Ignore keys for the log filename to not convert larger data structures.
   record_dict = data.convert_to_base_types(
       test_record, ignore_keys=('code_info', 'phases', 'log_records'))
   pattern = self.filename_pattern
   if isinstance(pattern, six.string_types) or callable(pattern):
     output_file = self.open_file(util.format_string(pattern, record_dict))
     try:
       yield output_file
     finally:
       output_file.close()
   elif hasattr(self.filename_pattern, 'write'):
     yield self.filename_pattern
   else:
     raise ValueError(
         'filename_pattern must be string, callable, or File-like object')
예제 #24
0
  def cached_state_summary(self):
    """Get our cached state as a dict, with phases/records swapped out.

    Returns:
      Cached state used to generate the dict, and a dict representation
    of that state, with phases/records swapped out for respective counts.
    This is used to send to a running test so only have to send back new
    phases and log records.
    """
    cached_state = self.cached_state

    if not cached_state:
      return None, None

    test_record = dict(cached_state.test_record)
    test_record['phases'] = len(test_record['phases'])
    test_record['log_records'] = len(test_record['log_records'])

    return cached_state, {
        'status': cached_state.status.name,
        'running_phase_state': data.convert_to_base_types(
            cached_state.running_phase_state),
        'test_record': test_record
    }
예제 #25
0
 def write_result(self, test):
   # Wrap value in a dict because a list is not allowed.
   self.write({'data': data.convert_to_base_types(test.history)})
예제 #26
0
 def make_msg(cls, test_uid, remote_state):
   """Construct a message for publishing."""
   return json.dumps({
       'test_uid': test_uid,
       'state': data.convert_to_base_types(remote_state)
   })
예제 #27
0
 def publish_test_record(cls, test_record):
   test_record_dict = data.convert_to_base_types(test_record)
   test_state_dict = _test_state_from_record(test_record_dict,
                                             cls._last_execution_uid)
   cls._publish_test_state(test_state_dict, 'record')
예제 #28
0
 def make_message(cls):
   with cls.station_map_lock:
     return data.convert_to_base_types(cls.station_map)
예제 #29
0
  def test_convert_to_base_types(self):
    class FloatSubclass(float):
      pass

    class SpecialBaseTypes(
        collections.namedtuple('SpecialBaseTypes', ['unsafe_value'])):

      def as_base_types(self):
        return {'safe_value': True}

    class AsDict(object):
      def _asdict(self):
        return None

    class NotRecursivelyCopied(object):

      def __init__(self):
        self.value = []

      def as_base_types(self):
        return self.value

    not_copied = NotRecursivelyCopied()

    example_data = {
        'list': [10],
        'tuple': (10,),
        'str': '10',
        'unicode': '10',
        'int': 2 ** 40,
        'float': 10.0,
        'long': 2 ** 80,
        'bool': True,
        'none': None,
        'complex': 10j,
        'float_subclass': FloatSubclass(10.0),
        'special': SpecialBaseTypes('must_not_be_present'),
        'not_copied': not_copied,

        # Some plugs such as UserInputPlug will return None as a response to
        # AsDict().
        'none_dict': AsDict(),
    }
    converted = data.convert_to_base_types(example_data)


    self.assertIsInstance(converted['list'], list)
    self.assertIsInstance(converted['tuple'], tuple)
    self.assertIsInstance(converted['str'], str)
    self.assertIsInstance(converted['unicode'], str)
    self.assertIsInstance(converted['int'], int)
    self.assertIsInstance(converted['float'], float)
    self.assertIsInstance(converted['long'], long)
    self.assertIsInstance(converted['bool'], bool)
    self.assertIsNone(converted['none'])
    self.assertIsInstance(converted['complex'], str)
    self.assertIsInstance(converted['float_subclass'], float)
    self.assertIsInstance(converted['special'], dict)
    self.assertEqual(converted['special'], {'safe_value': True})
    self.assertEqual(converted['none_dict'], None)
    self.assertIs(converted['not_copied'], not_copied.value)
예제 #30
0
파일: __init__.py 프로젝트: fahhem/openhtf
 def make_msg(cls, test_uid, remote_state):
     """Construct a message for publishing."""
     return json.dumps({"test_uid": test_uid, "state": convert_to_base_types(remote_state)})