Source code for vocab.vocab

"""
note that this requires python v3.6 or higher to preserve the order of the fields input
this is b/c keyword arguments in this version or higher are now defaulted to
ordered dicts
"""
import sys
import warnings

if sys.version_info.major < 3 or sys.version_info.minor < 6:
    warnings.warn('requires python 3.6+ to preserve key order of inputs')


class Vocab:
    """
    >>> TERM = Vocab(a='a', b=2, c='c')
    >>> TERM.a
    'a'
    >>> TERM.b
    2
    >>> 2 in TERM
    True
    >>> TERM.fields
    ['a', 'b', 'c']
    >>> TERM.values()
    ['a', 2, 'c']
    >>> TERM['b']
    2
    >>> TERM.reverse(2)
    'b'
    """
    def __init__(self, **kw):
        """
        for a set of keyword arguments returns an object with
        the key names as attributes set to their input values
        can test for membership
        """
        if 'fields' in kw:
            raise AttributeError('fields cannot be specified. It is a reserved name')
        fields = []
        for name, value in kw.items():
            fields.append(name)
            setattr(self, name, value)
        if sys.version_info.major < 3 or sys.version_info.minor < 6:
            self.fields = sorted(fields)
        else:
            self.fields = fields

    def __contains__(self, value):
        """
        test for membership
        """
        for f in self.fields:
            if value == getattr(self, f):
                return True
        return False

    def __getitem__(self, key):
        if not hasattr(self, key):
            raise KeyError(key)
        return getattr(self, key)
    
    def values(self):
        values = []
        for f in self.fields:
            values.append( getattr(self, f) )
        return values

    def enforce(self, value):
        if value not in self:
            raise KeyError('value {0} is not a valid member of the vocabulary object'.format(value), self.values() )
        return value

    def items(self):
        items = []
        for f in self.fields:
            items.append((f, getattr(self, f)))
        return items

    def reverse(self, value, unique=True):
        result = []
        for f, v in self.items():
            if v == value:
                result.append(f)
        if len(result) < 1:
            raise KeyError('could not reverse mapping. the value {0} is not valid'.format(value))
        if unique:
            if len(result) > 1:
                raise KeyError('mapping to value is not unique. specify unique=False to return a list')
            return result[0]
        return result


if __name__ == '__main__':
    import doctest
    doctest.testmod()