cubicweb/rtags.py
changeset 11888 0849a5eb57b8
parent 11886 c5c041ba35b8
child 11932 7b2247098f58
equal deleted inserted replaced
11887:42461734c3e8 11888:0849a5eb57b8
    47 
    47 
    48 def _ensure_str_key(key):
    48 def _ensure_str_key(key):
    49     return tuple(str(k) for k in key)
    49     return tuple(str(k) for k in key)
    50 
    50 
    51 
    51 
       
    52 def rtags_chain(rtag):
       
    53     """Return the rtags chain, starting from the given one, and going back through each parent rtag
       
    54     up to the root (i.e. which as no parent).
       
    55     """
       
    56     while rtag is not None:
       
    57         yield rtag
       
    58         rtag = rtag._parent
       
    59 
       
    60 
    52 class RegistrableRtags(RegistrableInstance):
    61 class RegistrableRtags(RegistrableInstance):
    53     __registry__ = 'uicfg'
    62     __registry__ = 'uicfg'
    54     __select__ = yes()
    63     __select__ = yes()
    55 
    64 
    56 
    65 
    66     _allowed_values = None
    75     _allowed_values = None
    67     # _init expected to be a method (introduced in 3.17), while _initfunc a
    76     # _init expected to be a method (introduced in 3.17), while _initfunc a
    68     # function given as __init__ argument and kept for bw compat
    77     # function given as __init__ argument and kept for bw compat
    69     _init = _initfunc = None
    78     _init = _initfunc = None
    70 
    79 
    71     def __init__(self):
    80     def __init__(self, parent=None):
    72         self._tagdefs = {}
    81         self._tagdefs = {}
       
    82         self._parent = parent
       
    83         if parent is not None:
       
    84             assert parent.__class__ is self.__class__, \
       
    85                 'inconsistent class for parent rtag {0}'.format(parent)
    73 
    86 
    74     def __repr__(self):
    87     def __repr__(self):
    75         # find a way to have more infos but keep it readable
    88         # find a way to have more infos but keep it readable
    76         # (in error messages in case of an ambiguity for instance)
    89         # (in error messages in case of an ambiguity for instance)
    77         return '%s (%s): %s' % (id(self), self.__regid__, self.__class__)
    90         return '%s (%s): %s' % (id(self), self.__regid__, self.__class__)
   103                     if ertype != '*' and ertype not in schema:
   116                     if ertype != '*' and ertype not in schema:
   104                         self.warning('removing rtag %s: %s, %s undefined in schema',
   117                         self.warning('removing rtag %s: %s, %s undefined in schema',
   105                                      (stype, rtype, otype, tagged), value, ertype)
   118                                      (stype, rtype, otype, tagged), value, ertype)
   106                         self.del_rtag(stype, rtype, otype, tagged)
   119                         self.del_rtag(stype, rtype, otype, tagged)
   107                         break
   120                         break
   108         if self._init is not None:
   121         if self._parent is None and self._init is not None:
   109             self.apply(schema, self._init)
   122             self.apply(schema, self._init)
   110 
   123 
   111     def apply(self, schema, func):
   124     def apply(self, schema, func):
   112         for eschema in schema.entities():
   125         for eschema in schema.entities():
   113             if eschema.final:
   126             if eschema.final:
   120                         sschema, oschema = tschema, eschema
   133                         sschema, oschema = tschema, eschema
   121                     func(sschema, rschema, oschema, role)
   134                     func(sschema, rschema, oschema, role)
   122 
   135 
   123     # rtag declaration api ####################################################
   136     # rtag declaration api ####################################################
   124 
   137 
       
   138     def derive(self, module, select):
       
   139         """Return a derivated of this relation tag, associated to given module and selector.
       
   140 
       
   141         This derivated will hold a set of specific rules but delegate to its "parent" relation tags
       
   142         for unfound keys.
       
   143 
       
   144         >>> class_afs = uicfg.autoform_section.derive(__name__, is_instance('Class'))
       
   145         """
       
   146         copied = self.__class__(self)
       
   147         copied.__module__ = module
       
   148         copied.__select__ = select
       
   149         return copied
       
   150 
   125     def tag_attribute(self, key, *args, **kwargs):
   151     def tag_attribute(self, key, *args, **kwargs):
   126         key = list(key)
   152         key = list(key)
   127         key.append('*')
   153         key.append('*')
   128         key.append('subject')
   154         key.append('subject')
   129         self.tag_relation(key, *args, **kwargs)
   155         self.tag_relation(key, *args, **kwargs)
   161 
   187 
   162     def del_rtag(self, *key):
   188     def del_rtag(self, *key):
   163         del self._tagdefs[key]
   189         del self._tagdefs[key]
   164 
   190 
   165     def get(self, *key):
   191     def get(self, *key):
       
   192         """Return value for the given key, by looking from the most specific key to the more
       
   193         generic (using '*' wildcards). For each key, look into this rtag and its parent rtags.
       
   194         """
   166         for key in reversed(self._get_keys(*key)):
   195         for key in reversed(self._get_keys(*key)):
   167             try:
   196             for rtag in rtags_chain(self):
   168                 return self._tagdefs[key]
   197                 try:
   169             except KeyError:
   198                     return rtag._tagdefs[key]
   170                 continue
   199                 except KeyError:
       
   200                     continue
   171         return None
   201         return None
   172 
   202 
   173     def etype_get(self, etype, rtype, role, ttype='*'):
   203     def etype_get(self, etype, rtype, role, ttype='*'):
   174         if role == 'subject':
   204         if role == 'subject':
   175             return self.get(etype, rtype, ttype, role)
   205             return self.get(etype, rtype, ttype, role)
   190                                          self.tag_container_cls())
   220                                          self.tag_container_cls())
   191         rtags.add(tag)
   221         rtags.add(tag)
   192         return rtags
   222         return rtags
   193 
   223 
   194     def get(self, stype, rtype, otype, tagged):
   224     def get(self, stype, rtype, otype, tagged):
       
   225         """Return value for the given key, which is an union of the values found from the most
       
   226         specific key to the more generic (using '*' wildcards). For each key, look into this rtag
       
   227         and its parent rtags.
       
   228         """
   195         rtags = self.tag_container_cls()
   229         rtags = self.tag_container_cls()
   196         for key in self._get_keys(stype, rtype, otype, tagged):
   230         for key in self._get_keys(stype, rtype, otype, tagged):
   197             try:
   231             for rtag in rtags_chain(self):
   198                 rtags.update(self._tagdefs[key])
   232                 try:
   199             except KeyError:
   233                     rtags.update(rtag._tagdefs[key])
   200                 continue
   234                     break
       
   235                 except KeyError:
       
   236                     continue
   201         return rtags
   237         return rtags
   202 
   238 
   203 
   239 
   204 class RelationTagsDict(RelationTagsSet):
   240 class RelationTagsDict(RelationTagsSet):
   205     """This class associates a dictionary to each key."""
   241     """This class associates a dictionary to each key."""