rtags.py
author Aurelien Campeas <aurelien.campeas@logilab.fr>
Wed, 01 Jul 2009 14:56:37 +0200
branchstable
changeset 2215 b1977f5263ac
parent 1977 606923dff11b
child 2369 5a2b8ed266ca
permissions -rw-r--r--
by popular demand, let us setle on needs_xxx
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1152
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     1
"""relation tags store
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     2
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     3
:organization: Logilab
1977
606923dff11b big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1859
diff changeset
     4
:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
1152
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     5
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
1977
606923dff11b big bunch of copyright / docstring update
Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
parents: 1859
diff changeset
     6
:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
1152
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     7
"""
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
     8
__docformat__ = "restructuredtext en"
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
     9
1740
2292ae32c98f warn and drop rtags not in schema, this may be intentional; drop possibility to not specify value for bool rtags
sylvain.thenault@logilab.fr
parents: 1739
diff changeset
    10
import logging
2292ae32c98f warn and drop rtags not in schema, this may be intentional; drop possibility to not specify value for bool rtags
sylvain.thenault@logilab.fr
parents: 1739
diff changeset
    11
2292ae32c98f warn and drop rtags not in schema, this may be intentional; drop possibility to not specify value for bool rtags
sylvain.thenault@logilab.fr
parents: 1739
diff changeset
    12
from logilab.common.logging_ext import set_log_methods
2292ae32c98f warn and drop rtags not in schema, this may be intentional; drop possibility to not specify value for bool rtags
sylvain.thenault@logilab.fr
parents: 1739
diff changeset
    13
1752
4b0b912ff5b7 fix rtags initialization: do it at the registry level to avoid multiple initialization of the same rtag
sylvain.thenault@logilab.fr
parents: 1748
diff changeset
    14
RTAGS = []
4b0b912ff5b7 fix rtags initialization: do it at the registry level to avoid multiple initialization of the same rtag
sylvain.thenault@logilab.fr
parents: 1748
diff changeset
    15
def register_rtag(rtag):
4b0b912ff5b7 fix rtags initialization: do it at the registry level to avoid multiple initialization of the same rtag
sylvain.thenault@logilab.fr
parents: 1748
diff changeset
    16
    RTAGS.append(rtag)
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    17
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
    18
class RelationTags(object):
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    19
    """a tag store for full relation definitions :
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
    20
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    21
         (subject type, relation type, object type, tagged)
1152
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
    22
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
    23
    allowing to set tags using wildcard (eg '*') as subject type / object type
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
    24
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    25
    This class associates a single tag to each key.
1152
c99ef2a2535c cleanup
sylvain.thenault@logilab.fr
parents: 1148
diff changeset
    26
    """
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    27
    _allowed_values = None
1849
1901fa97f521 give a name to rtags instance to ease debugging
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1769
diff changeset
    28
    def __init__(self, name=None, initfunc=None, allowed_values=None):
1901fa97f521 give a name to rtags instance to ease debugging
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1769
diff changeset
    29
        self._name = name or '<unknown>'
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
    30
        self._tagdefs = {}
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    31
        if allowed_values is not None:
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    32
            self._allowed_values = allowed_values
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    33
        self._initfunc = initfunc
1752
4b0b912ff5b7 fix rtags initialization: do it at the registry level to avoid multiple initialization of the same rtag
sylvain.thenault@logilab.fr
parents: 1748
diff changeset
    34
        register_rtag(self)
1769
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    35
1528
864ae7c15ef5 other fixlets
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1451
diff changeset
    36
    def __repr__(self):
1849
1901fa97f521 give a name to rtags instance to ease debugging
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1769
diff changeset
    37
        return '%s: %s' % (self._name, repr(self._tagdefs))
1528
864ae7c15ef5 other fixlets
Aurelien Campeas <aurelien.campeas@logilab.fr>
parents: 1451
diff changeset
    38
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    39
    # dict compat
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    40
    def __getitem__(self, key):
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    41
        return self.get(*key)
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    42
    __contains__ = __getitem__
1451
982e8616d9a2 delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1356
diff changeset
    43
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    44
    def _get_keys(self, stype, rtype, otype, tagged):
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    45
        keys = [(rtype, tagged, '*', '*'),
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    46
                (rtype, tagged, '*', otype),
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    47
                (rtype, tagged, stype, '*'),
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    48
                (rtype, tagged, stype, otype)]
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    49
        if stype == '*' or otype == '*':
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    50
            keys.remove((rtype, tagged, '*', '*'))
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    51
            if stype == '*':
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    52
                keys.remove((rtype, tagged, '*', otype))
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    53
            if otype == '*':
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    54
                keys.remove((rtype, tagged, stype, '*'))
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    55
        return keys
1451
982e8616d9a2 delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1356
diff changeset
    56
1769
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    57
    def init(self, schema, check=True):
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    58
        # XXX check existing keys against schema
1769
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    59
        if check:
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    60
            for (rtype, tagged, stype, otype), value in self._tagdefs.items():
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    61
                for ertype in (stype, rtype, otype):
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    62
                    if ertype != '*' and not ertype in schema:
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    63
                        self.warning('removing rtag %s: %s, %s undefined in schema',
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    64
                                     (stype, rtype, otype, tagged), value, ertype)
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    65
                        self.del_rtag(stype, rtype, otype, tagged)
fb91d2b8a441 fix some rtags pb on i18n catalog generation
sylvain.thenault@logilab.fr
parents: 1752
diff changeset
    66
                        break
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    67
        if self._initfunc is not None:
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    68
            for eschema in schema.entities():
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    69
                for rschema, tschemas, role in eschema.relation_definitions(True):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    70
                    for tschema in tschemas:
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    71
                        if role == 'subject':
1744
056ed8fca8d3 fix naming to avoid errors...
sylvain.thenault@logilab.fr
parents: 1742
diff changeset
    72
                            sschema, oschema = eschema, tschema
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    73
                        else:
1744
056ed8fca8d3 fix naming to avoid errors...
sylvain.thenault@logilab.fr
parents: 1742
diff changeset
    74
                            sschema, oschema = tschema, eschema
056ed8fca8d3 fix naming to avoid errors...
sylvain.thenault@logilab.fr
parents: 1742
diff changeset
    75
                        self._initfunc(self, sschema, rschema, oschema, role)
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    76
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    77
    # rtag declaration api ####################################################
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    78
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    79
    def tag_attribute(self, key, tag):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    80
        key = list(key)
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    81
        key.append('*')
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    82
        self.tag_subject_of(key, tag)
1548
bd225e776739 new tag_attribute convenience method
sylvain.thenault@logilab.fr
parents: 1533
diff changeset
    83
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    84
    def tag_subject_of(self, key, tag):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    85
        key = list(key)
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    86
        key.append('subject')
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    87
        self.tag_relation(key, tag)
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    88
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    89
    def tag_object_of(self, key, tag):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    90
        key = list(key)
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    91
        key.append('object')
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    92
        self.tag_relation(key, tag)
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
    93
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    94
    def tag_relation(self, key, tag):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    95
        #if isinstance(key, basestring):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    96
        #    stype, rtype, otype = key.split()
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    97
        #else:
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    98
        stype, rtype, otype, tagged = [str(k) for k in key]
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
    99
        if self._allowed_values is not None:
1859
b068abd45a1c nicer error message
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1849
diff changeset
   100
            assert tag in self._allowed_values, \
b068abd45a1c nicer error message
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1849
diff changeset
   101
                   '%r is not an allowed tag (should be in %s)' % (
b068abd45a1c nicer error message
Sylvain Thénault <sylvain.thenault@logilab.fr>
parents: 1849
diff changeset
   102
                tag, self._allowed_values)
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   103
        self._tagdefs[(rtype, tagged, stype, otype)] = tag
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   104
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   105
    # rtag runtime api ########################################################
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   106
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   107
    def del_rtag(self, stype, rtype, otype, tagged):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   108
        del self._tagdefs[(rtype, tagged, stype, otype)]
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   109
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   110
    def get(self, stype, rtype, otype, tagged):
1721
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   111
        for key in reversed(self._get_keys(stype, rtype, otype, tagged)):
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   112
            try:
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   113
                return self._tagdefs[key]
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   114
            except KeyError:
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   115
                continue
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   116
        return None
1451
982e8616d9a2 delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1356
diff changeset
   117
1721
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   118
    def etype_get(self, etype, rtype, role, ttype='*'):
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   119
        if role == 'subject':
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   120
            return self.get(etype, rtype, ttype, role)
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   121
        return self.get(ttype, rtype, etype, role)
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   122
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   123
1451
982e8616d9a2 delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1356
diff changeset
   124
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   125
class RelationTagsSet(RelationTags):
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   126
    """This class associates a set of tags to each key."""
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   127
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   128
    def tag_relation(self, key, tag):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   129
        stype, rtype, otype, tagged = [str(k) for k in key]
1533
bcd4bfff658b update rtags api
sylvain.thenault@logilab.fr
parents: 1528
diff changeset
   130
        rtags = self._tagdefs.setdefault((rtype, tagged, stype, otype), set())
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   131
        rtags.add(tag)
1451
982e8616d9a2 delete-trailing-whitespaces
sylvain.thenault@logilab.fr
parents: 1356
diff changeset
   132
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   133
    def get(self, stype, rtype, otype, tagged):
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   134
        rtags = set()
1721
694f6a50e138 final rtags api (eventually :$)
sylvain.thenault@logilab.fr
parents: 1548
diff changeset
   135
        for key in self._get_keys(stype, rtype, otype, tagged):
1148
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   136
            try:
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   137
                rtags.update(self._tagdefs[key])
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   138
            except KeyError:
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   139
                continue
55a8238f8f7c keep notion of relation tags, tough with simplier implementation and usage
sylvain.thenault@logilab.fr
parents:
diff changeset
   140
        return rtags
1739
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   141
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   142
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   143
class RelationTagsBool(RelationTags):
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   144
    _allowed_values = frozenset((True, False))
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   145
78b0819162a8 final rtag api
sylvain.thenault@logilab.fr
parents: 1726
diff changeset
   146
1740
2292ae32c98f warn and drop rtags not in schema, this may be intentional; drop possibility to not specify value for bool rtags
sylvain.thenault@logilab.fr
parents: 1739
diff changeset
   147
set_log_methods(RelationTags, logging.getLogger('cubicweb.rtags'))