def __init__(self, common_fields: List[FieldInfo], relations: List[RelationInfo], default_identity: str): """ :param common_fields: the common fields shared among relations in this collection :type common_fields: ``list`` of :py:class:`FieldInfo` :param relations: the relations in this collection :type relations: :py:class:`RelationInfo` :param default_identity: the name of the default identity field for all defined relations :type default_identity: ``str`` :seealso: :py:func:`_RelationInfoCollection.default_identity` """ # If we didn't get any common fields... if common_fields is None: self._common_fields = {} # ...our internal index is empty. elif isinstance(common_fields, list): # If we got the type we expect... # ...create an index for the fields that uses the field name as a key. self._common_fields = CaseInsensitiveDict( {field.name: field for field in common_fields}) else: raise ValueError('common_fields must be a list.') # If we didn't get any relations... if relations is None: self._relations = {} # ...our internal index is empty. elif isinstance(relations, list): # If we got the type we expect... # ...create an index for the fields that uses the table's name as a key. self._relations = CaseInsensitiveDict( {field.name: field for field in relations}) else: raise ValueError('relations must be a list.') self._default_identity = default_identity
def __init__(self, name: str, identity: str = None, fields: List[FieldInfo] = None, nena: NenaSpec = None, i18n: I18nPack = None): """ :param name: the name of the relation :type name: ``str`` :param identity: the name of the field that contains the identity value for the relation :type identity: ``str`` :seealso: :py:func:`RelationInfo.identity` :param fields: :type fields: ``list`` of :py:class:`FieldInfo` :param nena: information about how this field relates to the NENA standard :type nena: :py:class:`NenaSpec` :param i18n: informative strings that describe the field in various languages :type i18n: :py:func:`i18n.I18nPack` """ self._name = name self._identity = identity # If we didn't get any fields... if fields is None: self._fields = {} # ...our internal index is empty. elif isinstance(fields, list): # If we got the type we expect... # ...create an index for the fields that uses the field name as a key. self._fields = CaseInsensitiveDict( {str(field.name): field for field in fields}) else: raise ValueError('common_fields must be a list.') self._nena = nena self._i18n = i18n
def test_keys_same_case(self): d = CaseInsensitiveDict(x=1, Y=2) keys = list(d) self.assertIn('x', keys) self.assertIn('Y', keys) self.assertNotIn('y', keys) self.assertNotIn('X', keys)
def from_name(enum_cls, name: str) -> Enum: """ Get an enumeration member value from its name. :param enum_cls: the :py:class:`Enum` ``class`` :type enum_cls: ``class`` :param name: the enumeration member's name :type name: ``str`` :return: the enumeration member :rtype: :py:class:`Enum` """ # Benign forgiveness: If we were actually passed a value from the enumeration instead of its name... if isinstance(name, enum_cls): # ...that's OK. Just return the enumeration value. return name # Make sure we're dealing with an Enum type. if not issubclass(enum_cls, Enum): raise ValueError( 'enum_class must be of type {typ}'.format(typ=type(Enum))) # Now let's get a reference to the index of symbols to their enumeration members. symbols2members = None # It's possible we haven't see this type before, so we may not have the index on file. try: symbols2members = Enums._names2members[enum_cls] except KeyError: # This is all right. It should only happen the first time. pass # If we haven't already done so... if symbols2members is None: # ...now's the time to create the index of symbols to the member names. symbols2members = CaseInsensitiveDict({ _name: _member for _name, _member in enum_cls.__members__.items() }) # Now save the collection we just created for next time. Enums._names2members[enum_cls] = symbols2members # Return the enumeration member indexed to the symbol that was passed in. return symbols2members[name]
def test_lower_items(self): d = CaseInsensitiveDict(x=1, Y=2) d2 = {key: value for key, value in d.lower_items()} self.assertDictEqual({'x': 1, 'y': 2}, d2)
def test_len(self): d = CaseInsensitiveDict(x=1, y=2) self.assertEqual(2, len(d))
def test_del_different_case(self): d = CaseInsensitiveDict(x=1) del d['X'] self.assertNotIn('x', d) self.assertNotIn('X', d)
def test_del_same_case(self): d = CaseInsensitiveDict(x=1) del d['x'] self.assertNotIn('x', d)
class RelationInfo(object): """ Relation information objects describe entity relations (like tables in a database). """ def __init__(self, name: str, identity: str = None, fields: List[FieldInfo] = None, nena: NenaSpec = None, i18n: I18nPack = None): """ :param name: the name of the relation :type name: ``str`` :param identity: the name of the field that contains the identity value for the relation :type identity: ``str`` :seealso: :py:func:`RelationInfo.identity` :param fields: :type fields: ``list`` of :py:class:`FieldInfo` :param nena: information about how this field relates to the NENA standard :type nena: :py:class:`NenaSpec` :param i18n: informative strings that describe the field in various languages :type i18n: :py:func:`i18n.I18nPack` """ self._name = name self._identity = identity # If we didn't get any fields... if fields is None: self._fields = {} # ...our internal index is empty. elif isinstance(fields, list): # If we got the type we expect... # ...create an index for the fields that uses the field name as a key. self._fields = CaseInsensitiveDict( {str(field.name): field for field in fields}) else: raise ValueError('common_fields must be a list.') self._nena = nena self._i18n = i18n @property def name(self) -> str: """ Get the name of the relation. :rtype: ``str`` """ return self._name @property def identity(self) -> str: """ Get the name of the field that contains the identity values for the relation. :rtype: ``str`` """ return self._identity @property def fields(self) -> iter: """ Get this relation's field information :return: this relation's fields :rtype: iter(:py:class:`FieldInfo`) """ return iter(self._fields.values()) @property def i18n(self) -> I18nPack: """ Get informative strings that describe this field in various languages. :rtype: :py:class:`I18n` """ return self._i18n @property def nena(self) -> NenaSpec: """ Get information about how this field relates to the NENA specification. :rtype: :py:class:`NenaSpec` """ return self._nena def get_identity_field(self) -> FieldInfo: """ Get the field information for the field that contains the identity values for the relation. :seealso: :py:func:`FieldInfo.identity` :rtype: :py:class:`FieldInfo` """ return self.get_field( self._identity) if self._identity is not None else None def get_field(self, name: str) -> FieldInfo: """ Get field information for the relation. :param name: the name of the relation :type name: ``str`` :return: the name of the relation :rtype: :py:class:`FieldInfo` """ return self._fields[name]
def test_repr(self): original = dict(x=1, y=2) actual = CaseInsensitiveDict(data=original) self.assertIsInstance(repr(actual), str)
def test_set_get_same_case(self): d = CaseInsensitiveDict() d['x'] = 1 self.assertEqual(1, d['x'])
def test_init_from_kwargs(self): original = dict(x=1, y=2) resp = CaseInsensitiveDict(**original) assert_dicts_equal(original, resp)
def test_init_empty__initializes_empty(self): resp = CaseInsensitiveDict() self.assertEqual(0, len(resp)) assert_dicts_equal({}, resp)
class _RelationInfoCollection(object): """ This is a base class for collections of information that define the relations (tables) in a :py:class:`ModelInfo`. """ def __init__(self, common_fields: List[FieldInfo], relations: List[RelationInfo], default_identity: str): """ :param common_fields: the common fields shared among relations in this collection :type common_fields: ``list`` of :py:class:`FieldInfo` :param relations: the relations in this collection :type relations: :py:class:`RelationInfo` :param default_identity: the name of the default identity field for all defined relations :type default_identity: ``str`` :seealso: :py:func:`_RelationInfoCollection.default_identity` """ # If we didn't get any common fields... if common_fields is None: self._common_fields = {} # ...our internal index is empty. elif isinstance(common_fields, list): # If we got the type we expect... # ...create an index for the fields that uses the field name as a key. self._common_fields = CaseInsensitiveDict( {field.name: field for field in common_fields}) else: raise ValueError('common_fields must be a list.') # If we didn't get any relations... if relations is None: self._relations = {} # ...our internal index is empty. elif isinstance(relations, list): # If we got the type we expect... # ...create an index for the fields that uses the table's name as a key. self._relations = CaseInsensitiveDict( {field.name: field for field in relations}) else: raise ValueError('relations must be a list.') self._default_identity = default_identity def __iter__(self): # Return the values in the _relations index. return iter(self._relations.values()) @property def default_identity(self) -> str: """ Get the name of the default identity field for relations in this collection. :rtype: ``str`` """ return self._default_identity @property def common_fields(self) -> Iterator[FieldInfo]: """ Get the common fields defined for the collection. :rtype: :py:class:`Iterator` """ return iter(self._common_fields) def get_common_field(self, name: str) -> FieldInfo: """ Get a common field from the collection. :param name: the field name :type name: ``str`` :return: the field :rtype: :py:class:`FieldInfo` """ if name is None: raise TypeError("name cannot be None.") elif name not in self._common_fields: raise KeyError( "Common field '{name)' is not defined.".format(name=name)) else: return self._common_fields[name] @property def relations(self) -> Iterator[RelationInfo]: """ Get the relations in this collection. :rtype: :py:class:`Iterator[RelationInfo]` """ return iter(self._relations.values()) def get_relation(self, name: str) -> RelationInfo: """ Get a relation from the collection. :param name: the relation's name :type name: ``str`` :return: the relation :rtype: :py:class:`RelationInfo` """ if name is None: raise TypeError('name cannot be None.') elif name not in self._relations: raise KeyError( "Relation '{name)' is not defined.".format(name=name)) else: return self._relations[name] def add_relation(self, relation: RelationInfo): """ Add a relation to the collection. :param relation: the relation :type relation: :py:class:`RelationInfo` :raises TypeError: if the argument is ``None`` :raises KeyError: if the another relation with the same name is already present """ if relation is None: raise TypeError('relation cannot be None.') elif relation.name in self._relations: raise KeyError( 'The collection already contains a relation named {name}'. format(name=relation.name)) else: self._relations[relation.name] = relation
def test_equal(self): d1 = CaseInsensitiveDict(x=1) d2 = CaseInsensitiveDict(x=1) assert d1 == d2 d2['x'] = 2 assert d1 != d2
def test_copy(self): d1 = CaseInsensitiveDict(x=1) d2 = d1.copy() assert d1 is not d2 assert d1 == d2
def test_set_get_different_case(self): d = CaseInsensitiveDict() d['x'] = 1 self.assertEqual(1, d['X'])
def test_eq_non_dict(self): d = CaseInsensitiveDict() self.assertRaises(ValueError, d.__eq__, 1)
def test_set_get_original_case_preserved(self): d = CaseInsensitiveDict() d['X'] = 1 d2 = {key: value for key, value in d.items()} self.assertIn('X', d2) self.assertNotIn('x', d2)