def test_shape(self): good = [ ([1, 2], int, (2,)), ([[1, 2, 3], [4, 5, 6.0]], (int, float), (2, 3)), ([[[1]]], int, (1, 1, 1)), ([[1], [2]], None, (2, 1)), # if you didn't have `list` as a type, the shape of this one # would be (2, 2) - that's tested in bad below ([[1, 2], [3, 4]], list, (2,)), (((0, 1, 2), ((0, 1), (0, 1), (0, 1))), tuple, (2,)), (((0, 1, 2), ((0, 1), (0, 1), (0, 1))), (tuple, int), (2, 3)) ] for obj, types, shape in good: with self.subTest(obj=obj): self.assertTrue(is_sequence_of(obj, types, shape=shape)) bad = [ ([1], int, (2,)), ([[1]], int, (1,)), ([[1, 2], [1]], int, (2, 2)), ([[1]], float, (1, 1)), ([[1, 2], [3, 4]], int, (2, )), (((0, 1, 2), ((0, 1), (0, 1))), (tuple, int), (2, 3)) ] for obj, types, shape in bad: with self.subTest(obj=obj): self.assertFalse(is_sequence_of(obj, types, shape=shape))
def test_shape_depth(self): # there's no reason to provide both shape and depth, but # we allow it if they are self-consistent with self.assertRaises(ValueError): is_sequence_of([], int, depth=1, shape=(2, 2)) self.assertFalse(is_sequence_of([1], int, depth=1, shape=(2, ))) self.assertTrue(is_sequence_of([1], int, depth=1, shape=(1, )))
def test_shape_depth(): # there's no reason to provide both shape and depth, but # we allow it if they are self-consistent with pytest.raises(ValueError): is_sequence_of([], int, depth=1, shape=(2, 2)) assert not is_sequence_of([1], int, depth=1, shape=(2,)) assert is_sequence_of([1], int, depth=1, shape=(1,))
def test_depth(self): good = [([1, 2], int, 1), ([[1, 2], [3, 4]], int, 2), ([[1, 2.0], []], (int, float), 2), ([[[1]]], int, 3)] for args in good: with self.subTest(args=args): self.assertTrue(is_sequence_of(*args)) bad = [([1], int, 2), ([[1]], int, 1), ([[1]], float, 2)] for args in bad: with self.subTest(args=args): self.assertFalse(is_sequence_of(*args))
def _is_nested_sequence_or_none(obj, types, shapes): """Validator for MultiParameter setpoints/names/labels""" if obj is None: return True if not is_sequence_of(obj, tuple, shape=(len(shapes),)): return False for obji, shapei in zip(obj, shapes): if not is_sequence_of(obji, types, shape=(len(shapei),)): return False return True
def test_simple(self): good = [ # empty lists pass without even checking that we provided a # valid type spec ([], None), ((), None), ([1, 2, 3], int), ((1, 2, 3), int), ([1, 2.0], (int, float)), ([{}, None], (type(None), dict)) ] for args in good: with self.subTest(args=args): self.assertTrue(is_sequence_of(*args)) bad = [(1, int), ([1, 2.0], int), ([1, 2], float), ([1, 2], (float, dict))] for args in bad: with self.subTest(args=args): self.assertFalse(is_sequence_of(*args)) # second arg must be a type or tuple of types - failing this doesn't # return False, it raises an error with self.assertRaises(TypeError): is_sequence_of([1], 1) with self.assertRaises(TypeError): is_sequence_of([1], (1, 2)) with self.assertRaises(TypeError): is_sequence_of([1])
def __init__(self, name=None, names=None, label=None, labels=None, units=None, shape=None, shapes=None, setpoints=None, setpoint_names=None, setpoint_labels=None, vals=None, docstring=None, snapshot_get=True, **kwargs): super().__init__(**kwargs) self._snapshot_get = snapshot_get self.has_get = hasattr(self, 'get') self.has_set = hasattr(self, 'set') self._meta_attrs = ['setpoint_names', 'setpoint_labels'] # always let the parameter have a single name (in fact, require this!) # even if it has names too self.name = str(name) if names is not None: # check for names first - that way you can provide both name # AND names for instrument parameters - name is how you get the # object (from the parameters dict or the delegated attributes), # and names are the items it returns self.names = names self.labels = names if labels is None else names self.units = units if units is not None else [''] * len(names) self.set_validator(vals or Anything()) self.__doc__ = os.linesep.join( ('Parameter class:', '* `names` %s' % ', '.join(self.names), '* `labels` %s' % ', '.join(self.labels), '* `units` %s' % ', '.join(self.units))) self._meta_attrs.extend(['names', 'labels', 'units']) elif name is not None: self.label = name if label is None else label self.units = units if units is not None else '' # vals / validate only applies to simple single-value parameters self.set_validator(vals) # generate default docstring self.__doc__ = os.linesep.join(( 'Parameter class:', '* `name` %s' % self.name, '* `label` %s' % self.label, # TODO is this unit s a typo? shouldnt that be unit? '* `units` %s' % self.units, '* `vals` %s' % repr(self._vals))) self._meta_attrs.extend(['name', 'label', 'units', 'vals']) else: raise ValueError('either name or names is required') if shape is not None or shapes is not None: nt = type(None) if shape is not None: if not is_sequence_of(shape, int): raise ValueError('shape must be a tuple of ints, not ' + repr(shape)) self.shape = shape depth = 1 container_str = 'tuple' else: if not is_sequence_of(shapes, int, depth=2): raise ValueError('shapes must be a tuple of tuples ' 'of ints, not ' + repr(shape)) self.shapes = shapes depth = 2 container_str = 'tuple of tuples' sp_types = (nt, DataArray, collections.Sequence, collections.Iterator) if (setpoints is not None and not is_sequence_of(setpoints, sp_types, depth)): raise ValueError( 'setpoints must be a {} of arrays'.format(container_str)) if (setpoint_names is not None and not is_sequence_of(setpoint_names, (nt, str), depth)): raise ValueError('setpoint_names must be a {} ' 'of strings'.format(container_str)) if (setpoint_labels is not None and not is_sequence_of(setpoint_labels, (nt, str), depth)): raise ValueError('setpoint_labels must be a {} ' 'of strings'.format(container_str)) self.setpoints = setpoints self.setpoint_names = setpoint_names self.setpoint_labels = setpoint_labels # record of latest value and when it was set or measured # what exactly this means is different for different subclasses # but they all use the same attributes so snapshot is consistent. self._latest_value = None self._latest_ts = None if docstring is not None: self.__doc__ = docstring + os.linesep + self.__doc__ self.get_latest = GetLatest(self)
def __init__(self, name, names, shapes, instrument=None, labels=None, units=None, setpoints=None, setpoint_names=None, setpoint_labels=None, setpoint_units=None, docstring=None, snapshot_get=True, snapshot_value=True, metadata=None): super().__init__(name, instrument, snapshot_get, metadata, snapshot_value=snapshot_value) if self.has_set: # TODO (alexcjohnson): can we support, ala Combine? warnings.warn('MultiParameters do not fully support set ' 'at this time.') self._meta_attrs.extend(['setpoint_names', 'setpoint_labels', 'setpoint_units', 'names', 'labels', 'units']) if not is_sequence_of(names, str): raise ValueError('names must be a tuple of strings, not' + repr(names)) self.names = names self.labels = labels if labels is not None else names self.units = units if units is not None else [''] * len(names) nt = type(None) if (not is_sequence_of(shapes, int, depth=2) or len(shapes) != len(names)): raise ValueError('shapes must be a tuple of tuples ' 'of ints, not ' + repr(shapes)) self.shapes = shapes sp_types = (nt, DataArray, collections.Sequence, collections.Iterator) if not _is_nested_sequence_or_none(setpoints, sp_types, shapes): raise ValueError('setpoints must be a tuple of tuples of arrays') if not _is_nested_sequence_or_none(setpoint_names, (nt, str), shapes): raise ValueError( 'setpoint_names must be a tuple of tuples of strings') if not _is_nested_sequence_or_none(setpoint_labels, (nt, str), shapes): raise ValueError( 'setpoint_labels must be a tuple of tuples of strings') if not _is_nested_sequence_or_none(setpoint_units, (nt, str), shapes): raise ValueError( 'setpoint_units must be a tuple of tuples of strings') self.setpoints = setpoints self.setpoint_names = setpoint_names self.setpoint_labels = setpoint_labels self.setpoint_units = setpoint_units self.__doc__ = os.linesep.join(( 'MultiParameter class:', '', '* `name` %s' % self.name, '* `names` %s' % ', '.join(self.names), '* `labels` %s' % ', '.join(self.labels), '* `units` %s' % ', '.join(self.units))) if docstring is not None: self.__doc__ = os.linesep.join(( docstring, '', self.__doc__))
def __init__(self, name, shape, instrument=None, label=None, unit=None, units=None, setpoints=None, setpoint_names=None, setpoint_labels=None, setpoint_units=None, docstring=None, snapshot_get=True, snapshot_value=True, metadata=None): super().__init__(name, instrument, snapshot_get, metadata, snapshot_value=snapshot_value) if self.has_set: # TODO (alexcjohnson): can we support, ala Combine? raise AttributeError('ArrayParameters do not support set ' 'at this time.') self._meta_attrs.extend(['setpoint_names', 'setpoint_labels', 'setpoint_units', 'label', 'unit']) self.label = name if label is None else label if units is not None: warn_units('ArrayParameter', self) if unit is None: unit = units self.unit = unit if unit is not None else '' nt = type(None) if not is_sequence_of(shape, int): raise ValueError('shapes must be a tuple of ints, not ' + repr(shape)) self.shape = shape # require one setpoint per dimension of shape sp_shape = (len(shape),) sp_types = (nt, DataArray, collections.Sequence, collections.Iterator) if (setpoints is not None and not is_sequence_of(setpoints, sp_types, shape=sp_shape)): raise ValueError('setpoints must be a tuple of arrays') if (setpoint_names is not None and not is_sequence_of(setpoint_names, (nt, str), shape=sp_shape)): raise ValueError('setpoint_names must be a tuple of strings') if (setpoint_labels is not None and not is_sequence_of(setpoint_labels, (nt, str), shape=sp_shape)): raise ValueError('setpoint_labels must be a tuple of strings') if (setpoint_units is not None and not is_sequence_of(setpoint_units, (nt, str), shape=sp_shape)): raise ValueError('setpoint_units must be a tuple of strings') self.setpoints = setpoints self.setpoint_names = setpoint_names self.setpoint_labels = setpoint_labels self.setpoint_units = setpoint_units self.__doc__ = os.linesep.join(( 'Parameter class:', '', '* `name` %s' % self.name, '* `label` %s' % self.label, '* `unit` %s' % self.unit, '* `shape` %s' % repr(self.shape))) if docstring is not None: self.__doc__ = os.linesep.join(( docstring, '', self.__doc__))
def test_shape_good(args): obj, types, shape = args assert is_sequence_of(obj, types, shape=shape)
def test_depth_bad(args): assert not is_sequence_of(*args)
def test_depth_good(args): assert is_sequence_of(*args)
def test_examples_raises(): with pytest.raises(TypeError): is_sequence_of([1], 1) with pytest.raises(TypeError): is_sequence_of([1], (1, 2))
def test_simple_bad(args): assert not is_sequence_of(*args)
def test_simple_good(args): assert is_sequence_of(*args)