Example #1
0
 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
Example #2
0
 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
Example #3
0
 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]
Example #5
0
 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)
Example #6
0
 def test_len(self):
     d = CaseInsensitiveDict(x=1, y=2)
     self.assertEqual(2, len(d))
Example #7
0
 def test_del_different_case(self):
     d = CaseInsensitiveDict(x=1)
     del d['X']
     self.assertNotIn('x', d)
     self.assertNotIn('X', d)
Example #8
0
 def test_del_same_case(self):
     d = CaseInsensitiveDict(x=1)
     del d['x']
     self.assertNotIn('x', d)
Example #9
0
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]
Example #10
0
 def test_repr(self):
     original = dict(x=1, y=2)
     actual = CaseInsensitiveDict(data=original)
     self.assertIsInstance(repr(actual), str)
Example #11
0
 def test_set_get_same_case(self):
     d = CaseInsensitiveDict()
     d['x'] = 1
     self.assertEqual(1, d['x'])
Example #12
0
 def test_init_from_kwargs(self):
     original = dict(x=1, y=2)
     resp = CaseInsensitiveDict(**original)
     assert_dicts_equal(original, resp)
Example #13
0
 def test_init_empty__initializes_empty(self):
     resp = CaseInsensitiveDict()
     self.assertEqual(0, len(resp))
     assert_dicts_equal({}, resp)
Example #14
0
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
Example #15
0
 def test_equal(self):
     d1 = CaseInsensitiveDict(x=1)
     d2 = CaseInsensitiveDict(x=1)
     assert d1 == d2
     d2['x'] = 2
     assert d1 != d2
Example #16
0
 def test_copy(self):
     d1 = CaseInsensitiveDict(x=1)
     d2 = d1.copy()
     assert d1 is not d2
     assert d1 == d2
Example #17
0
 def test_set_get_different_case(self):
     d = CaseInsensitiveDict()
     d['x'] = 1
     self.assertEqual(1, d['X'])
Example #18
0
 def test_eq_non_dict(self):
     d = CaseInsensitiveDict()
     self.assertRaises(ValueError, d.__eq__, 1)
Example #19
0
 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)