def __init__(self, source, name=None, index=None): """A selection from 'source' by a string or numeric 'name_or_index'. Exactly one of 'name' or 'index' must be specified (not None). Args: source: The source value to select from (an instance of ComputationBuildingBlock). name: A string name of the element to be selected. index: A numeric index of the element to be selected. Raises: TypeError: if arguments are of the wrong types. ValueError: if the name is empty or index is negative, or the name/index is not compatible with the type signature of the source, or neither or both are defined (not None). """ if name is None and index is None: raise ValueError( 'Must define either a name or index, and neither was specified.' ) if name is not None and index is not None: raise ValueError( 'Cannot simultaneously specify a name and an index, choose one.' ) py_typecheck.check_type(source, ComputationBuildingBlock) self._source = source source_type = self._source.type_signature if not isinstance(source_type, computation_types.NamedTupleType): raise TypeError( 'Expected the source of selection to be a TFF named tuple, ' 'instead found it to be of type {}.'.format(str(source_type))) if name is not None: py_typecheck.check_type(name, six.string_types) if not name: raise ValueError( 'The name of the selected element cannot be empty.') else: # Normalize, in case we are dealing with a Unicode type or some such. name = str(name) super(Selection, self).__init__( type_utils.get_named_tuple_element_type(source_type, name)) self._name = name self._index = None else: # Index must have been specified, since name is None. py_typecheck.check_type(index, int) elements = anonymous_tuple.to_elements(source_type) if index >= 0 and index < len(elements): super(Selection, self).__init__(elements[index][1]) self._name = None self._index = index else: raise ValueError( 'The index of the selected element {} does not fit into the ' 'valid range 0..{} determined by the source type ' 'signature.'.format(index, str(len(elements) - 1)))
def test_get_named_tuple_element_type(self): type_spec = [('a', tf.int32), ('b', tf.bool)] self.assertEqual( str(type_utils.get_named_tuple_element_type(type_spec, 'a')), 'int32') self.assertEqual( str(type_utils.get_named_tuple_element_type(type_spec, 'b')), 'bool') with self.assertRaises(ValueError): type_utils.get_named_tuple_element_type(type_spec, 'c') with self.assertRaises(TypeError): type_utils.get_named_tuple_element_type(tf.int32, 'a') with self.assertRaises(TypeError): type_utils.get_named_tuple_element_type(type_spec, 10)