Skip to content

Commit

Permalink
Move ImmutableMeasurement to measurement.py.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 595487711
  • Loading branch information
OpenHTF Owners authored and copybara-github committed Jan 4, 2024
1 parent e4a844c commit d2ce3c7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 51 deletions.
38 changes: 37 additions & 1 deletion openhtf/core/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ def WidgetTestPhase(test):
"""

import collections
import copy
import enum
import functools
import logging
import typing
from typing import Any, Callable, Dict, Iterator, List, Optional, Text, Tuple, Union

import attr

from openhtf import util
from openhtf.util import data
from openhtf.util import units as util_units
Expand Down Expand Up @@ -735,6 +735,42 @@ def to_dataframe(self, columns: Any = None) -> Any:
return pandas.DataFrame.from_records(self.value, columns=columns)


@attr.s(slots=True, frozen=True)
class ImmutableMeasurement(object):
"""Immutable copy of a measurement."""

name = attr.ib(type=Text)
value = attr.ib(type=Any)
units = attr.ib(type=Optional[util_units.UnitDescriptor])
dimensions = attr.ib(type=Optional[List[Dimension]])
outcome = attr.ib(type=Optional[Outcome])
docstring = attr.ib(type=Optional[Text], default=None)

@classmethod
def from_measurement(cls, measurement: Measurement) -> 'ImmutableMeasurement':
"""Convert a Measurement into an ImmutableMeasurement."""
measured_value = measurement.measured_value
if isinstance(measured_value, 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,
docstring=measurement.docstring,
)


@attr.s(slots=True)
class Collection(object):
"""Encapsulates a collection of measurements.
Expand Down
21 changes: 10 additions & 11 deletions openhtf/core/test_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,16 @@

import attr
import colorama

from openhtf import util
from openhtf.core import base_plugs
from openhtf.core import diagnoses_lib
from openhtf.core import measurements
from openhtf.core import measurements as htf_measurements
from openhtf.core import phase_collections
from openhtf.core import phase_descriptor
from openhtf.core import phase_executor
from openhtf.core import test_executor
from openhtf.core import test_record as htf_test_record
from openhtf.core import test_state

from openhtf.util import configuration
from openhtf.util import console_output
from openhtf.util import logs
Expand Down Expand Up @@ -462,10 +460,10 @@ class TestApi(object):
stdout (configurable) and the frontend via the Station API, if it's
enabled, in addition to the 'log_records' attribute of the final
TestRecord output by the running test.
measurements: A measurements.Collection object used to get/set measurement
values. See util/measurements.py for more implementation details, but in
the simple case, set measurements directly as attributes on this object
(see examples/measurements.py for examples).
measurements: A htf_measurements.Collection object used to get/set
measurement values. See util/measurements.py for more implementation
details, but in the simple case, set measurements directly as attributes
on this object (see examples/measurements.py for examples).
attachments: Dict mapping attachment name to test_record.Attachment instance
containing the data that was attached (and the MIME type that was assumed
based on extension, if any). Only attachments that have been attached in
Expand All @@ -486,7 +484,7 @@ class TestApi(object):
https://github.com/google/openhtf/issues/new
"""

measurements = attr.ib(type=measurements.Collection)
measurements = attr.ib(type=htf_measurements.Collection)

# Internal state objects. If you find yourself needing to use these, please
# use required_state=True for the phase to use the test_state object instead.
Expand Down Expand Up @@ -568,8 +566,8 @@ def attach_from_file(
filename, name=name, mimetype=mimetype)

def get_measurement(
self,
measurement_name: Text) -> Optional[test_state.ImmutableMeasurement]:
self, measurement_name: Text
) -> Optional[htf_measurements.ImmutableMeasurement]:
"""Get a copy of a measurement value from current or previous phase.
Measurement and phase name uniqueness is not enforced, so this method will
Expand All @@ -584,7 +582,8 @@ def get_measurement(
return self._running_test_state.get_measurement(measurement_name)

def get_measurement_strict(
self, measurement_name: Text) -> test_state.ImmutableMeasurement:
self, measurement_name: Text
) -> htf_measurements.ImmutableMeasurement:
"""Get a copy of the test measurement from current or previous phase.
Measurement and phase name uniqueness is not enforced, so this method will
Expand Down
47 changes: 8 additions & 39 deletions openhtf/core/test_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@
import os
import socket
import sys
from typing import Any, Dict, Iterator, List, Optional, Set, Text, Tuple, TYPE_CHECKING, Union
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Text, Tuple, Union

import attr

import openhtf
from openhtf import plugs
from openhtf import util
Expand All @@ -48,7 +47,6 @@
from openhtf.util import configuration
from openhtf.util import data
from openhtf.util import logs
from openhtf.util import units
from typing_extensions import Literal

CONF = configuration.CONF
Expand Down Expand Up @@ -96,37 +94,6 @@ class InternalError(Exception):
"""An internal error."""


@attr.s(slots=True, frozen=True)
class ImmutableMeasurement(object):
"""Immutable copy of a measurement."""

name = attr.ib(type=Text)
value = attr.ib(type=Any)
units = attr.ib(type=Optional[units.UnitDescriptor])
dimensions = attr.ib(type=Optional[List[measurements.Dimension]])
outcome = attr.ib(type=Optional[measurements.Outcome])

@classmethod
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)


class TestState(util.SubscribableStateMixin):
"""This class handles tracking the state of a running Test.
Expand Down Expand Up @@ -263,8 +230,9 @@ def get_attachment(self,
self.state_logger.warning('Could not find attachment: %s', attachment_name)
return None

def get_measurement(self,
measurement_name: Text) -> Optional[ImmutableMeasurement]:
def get_measurement(
self, measurement_name: Text
) -> Optional[measurements.ImmutableMeasurement]:
"""Get a copy of a measurement value from current or previous phase.
Measurement and phase name uniqueness is not enforced, so this method will
Expand All @@ -282,16 +250,17 @@ def get_measurement(self,
# Check current running phase state
if self.running_phase_state:
if measurement_name in self.running_phase_state.measurements:
return ImmutableMeasurement.from_measurement(
self.running_phase_state.measurements[measurement_name])
return measurements.ImmutableMeasurement.from_measurement(
self.running_phase_state.measurements[measurement_name]
)

# Iterate through phases in reversed order to return most recent (necessary
# because measurement and phase names are not necessarily unique)
for phase_record in reversed(self.test_record.phases):
if (phase_record.result not in ignore_outcomes and
measurement_name in phase_record.measurements):
measurement = phase_record.measurements[measurement_name]
return ImmutableMeasurement.from_measurement(measurement)
return measurements.ImmutableMeasurement.from_measurement(measurement)

self.state_logger.warning('Could not find measurement: %s',
measurement_name)
Expand Down

0 comments on commit d2ce3c7

Please sign in to comment.