rtags.py
author sylvain.thenault@logilab.fr
Mon, 11 May 2009 11:20:38 +0200
branchtls-sprint
changeset 1721 694f6a50e138
parent 1548 bd225e776739
child 1723 30c3a713ab61
permissions -rw-r--r--
final rtags api (eventually :$)

"""relation tags store

:organization: Logilab
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"


class RelationTags(object):
    """a tag store for full relation definitions :

         (subject type, relation type, object type, tagged)

    allowing to set tags using wildcard (eg '*') as subject type / object type

    This class associates a single tag to each key.
    """

    def __init__(self):
        self._tagdefs = {}

    def __repr__(self):
        return repr(self._tagdefs)

    # dict compat
    def __getitem__(self, key):
        return self.get(*key)
    __contains__ = __getitem__

    def _get_tagged(self, stype, otype, tagged=None):
        stype, otype = str(stype), str(otype)
        if tagged is None:
            if stype[0] == '!':
                tagged = 'subject'
                stype = stype[1:]
            elif otype[0] == '!':
                tagged = 'object'
                otype = otype[1:]
            else:
                raise AssertionError('either stype or rtype should have the '
                                     'role mark ("!")')
        else:
            assert tagged in ('subject', 'object'), tagged
        return stype, otype, tagged

    def _get_keys(self, stype, rtype, otype, tagged=None):
        stype, otype, tagged = self._get_tagged(stype, otype, tagged)
        keys = [(rtype, tagged, '*', '*'),
                (rtype, tagged, '*', otype),
                (rtype, tagged, stype, '*'),
                (rtype, tagged, stype, otype)]
        if stype == '*' or otype == '*':
            keys.remove((rtype, tagged, '*', '*'))
            if stype == '*':
                keys.remove((rtype, tagged, '*', otype))
            if otype == '*':
                keys.remove((rtype, tagged, stype, '*'))
        return keys

    def tag_relation(self, stype, rtype, otype, tag, tagged=None):
        stype, otype, tagged = self._get_tagged(stype, otype, tagged)
        self._tagdefs[(str(rtype), tagged, stype, otype)] = tag

    def tag_attribute(self, stype, attr, tag):
        self.tag_relation(stype, attr, '*', tag, tagged)

    def del_rtag(self, stype, rtype, otype):
        stype, otype, tagged = self._get_tagged(stype, otype)
        del self._tagdefs[(str(rtype), tagged, stype, otype)]

    def get(self, stype, rtype, otype, tagged=None):
        for key in reversed(self._get_keys(stype, rtype, otype, tagged)):
            try:
                return self._tagdefs[key]
            except KeyError:
                continue
        return None

    def etype_get(self, etype, rtype, role, ttype='*'):
        if role == 'subject':
            return self.get(etype, rtype, ttype, role)
        return self.get(ttype, rtype, etype, role)



class RelationTagsSet(RelationTags):
    """This class associates a set of tags to each key."""

    def tag_relation(self, stype, rtype, otype, tag, tagged=None):
        stype, otype, tagged = self._get_tagged(stype, otype, tagged)
        rtags = self._tagdefs.setdefault((rtype, tagged, stype, otype), set())
        rtags.add(tag)

    def get(self, stype, rtype, otype, tagged=None):
        rtags = set()
        for key in self._get_keys(stype, rtype, otype, tagged):
            try:
                rtags.update(self._tagdefs[key])
            except KeyError:
                continue
        return rtags