1 """This file contains some basic registerers required by application objects |
|
2 registry to handle registration at startup time. |
|
3 |
|
4 A registerer is responsible to tell if an object should be registered according |
|
5 to the application's schema or to already registered object |
|
6 |
|
7 :organization: Logilab |
|
8 :copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
9 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
10 """ |
|
11 __docformat__ = "restructuredtext en" |
|
12 |
|
13 from cubicweb.vregistry import registerer |
|
14 |
|
15 |
|
16 def _accepts_interfaces(obj): |
|
17 return sorted(getattr(obj, 'accepts_interfaces', ())) |
|
18 |
|
19 |
|
20 class yes_registerer(registerer): |
|
21 """register without any other action""" |
|
22 def do_it_yourself(self, registered): |
|
23 return self.vobject |
|
24 |
|
25 class priority_registerer(registerer): |
|
26 """systematically kick previous registered class and register the |
|
27 wrapped class (based on the fact that directory containing vobjects |
|
28 are loaded from the most generic to the most specific). |
|
29 |
|
30 This is usually for templates or startup views where we want to |
|
31 keep only the latest in the load path |
|
32 """ |
|
33 def do_it_yourself(self, registered): |
|
34 if registered: |
|
35 if len(registered) > 1: |
|
36 self.warning('priority_registerer found more than one registered objects ' |
|
37 '(registerer monkey patch ?)') |
|
38 for regobj in registered[:]: |
|
39 self.kick(registered, regobj) |
|
40 return self.vobject |
|
41 |
|
42 def remove_equivalents(self, registered): |
|
43 for _obj in registered[:]: |
|
44 if self.equivalent(_obj): |
|
45 self.kick(registered, _obj) |
|
46 break |
|
47 |
|
48 def remove_all_equivalents(self, registered): |
|
49 for _obj in registered[:]: |
|
50 if _obj is self.vobject: |
|
51 continue |
|
52 if self.equivalent(_obj): |
|
53 self.kick(registered, _obj) |
|
54 |
|
55 def equivalent(self, other): |
|
56 raise NotImplementedError(self, self.vobject) |
|
57 |
|
58 |
|
59 class kick_registerer(registerer): |
|
60 """systematically kick previous registered class and don't register the |
|
61 wrapped class. This is temporarily used to discard library object registrable |
|
62 but that we don't want to use |
|
63 """ |
|
64 def do_it_yourself(self, registered): |
|
65 if registered: |
|
66 self.kick(registered, registered[-1]) |
|
67 return |
|
68 |
|
69 |
|
70 class accepts_registerer(priority_registerer): |
|
71 """register according to the .accepts attribute of the wrapped |
|
72 class, which should be a tuple refering some entity's types |
|
73 |
|
74 * if no type is defined the application'schema, skip the wrapped |
|
75 class |
|
76 * if the class defines a requires attribute, each entity type defined |
|
77 in the requires list must be in the schema |
|
78 * if an object previously registered has equivalent .accepts |
|
79 attribute, kick it out |
|
80 * register |
|
81 """ |
|
82 def do_it_yourself(self, registered): |
|
83 # if object is accepting interface, we have register it now and |
|
84 # remove it latter if no object is implementing accepted interfaces |
|
85 if _accepts_interfaces(self.vobject): |
|
86 return self.vobject |
|
87 if not 'Any' in self.vobject.accepts: |
|
88 for ertype in self.vobject.accepts: |
|
89 if ertype in self.schema: |
|
90 break |
|
91 else: |
|
92 self.skip() |
|
93 return None |
|
94 for required in getattr(self.vobject, 'requires', ()): |
|
95 if required not in self.schema: |
|
96 self.skip() |
|
97 return |
|
98 self.remove_equivalents(registered) |
|
99 return self.vobject |
|
100 |
|
101 def equivalent(self, other): |
|
102 if _accepts_interfaces(self.vobject) != _accepts_interfaces(other): |
|
103 return False |
|
104 if getattr(self.vobject, 'require_groups', ()) != getattr(other, 'require_groups', ()): |
|
105 return False |
|
106 try: |
|
107 newaccepts = list(other.accepts) |
|
108 for etype in self.vobject.accepts: |
|
109 try: |
|
110 newaccepts.remove(etype) |
|
111 except ValueError: |
|
112 continue |
|
113 if newaccepts: |
|
114 other.accepts = tuple(newaccepts) |
|
115 return False |
|
116 return True |
|
117 except AttributeError: |
|
118 return False |
|
119 |
|
120 |
|
121 class id_registerer(priority_registerer): |
|
122 """register according to the "id" attribute of the wrapped class, |
|
123 refering to an entity type. |
|
124 |
|
125 * if the type is not Any and is not defined the application'schema, |
|
126 skip the wrapped class |
|
127 * if an object previously registered has the same .id attribute, |
|
128 kick it out |
|
129 * register |
|
130 """ |
|
131 def do_it_yourself(self, registered): |
|
132 etype = self.vobject.id |
|
133 if etype != 'Any' and not self.schema.has_entity(etype): |
|
134 self.skip() |
|
135 return |
|
136 self.remove_equivalents(registered) |
|
137 return self.vobject |
|
138 |
|
139 def equivalent(self, other): |
|
140 return other.id == self.vobject.id |
|
141 |
|
142 |
|
143 class etype_rtype_registerer(registerer): |
|
144 """registerer handling optional .etype and .rtype attributes.: |
|
145 |
|
146 * if .etype is set and is not an entity type defined in the |
|
147 application schema, skip the wrapped class |
|
148 * if .rtype or .relname is set and is not a relation type defined in |
|
149 the application schema, skip the wrapped class |
|
150 * register |
|
151 """ |
|
152 def do_it_yourself(self, registered): |
|
153 cls = self.vobject |
|
154 if hasattr(cls, 'etype'): |
|
155 if not self.schema.has_entity(cls.etype): |
|
156 return |
|
157 rtype = getattr(cls, 'rtype', None) |
|
158 if rtype and not self.schema.has_relation(rtype): |
|
159 return |
|
160 return cls |
|
161 |
|
162 class etype_rtype_priority_registerer(etype_rtype_registerer): |
|
163 """add priority behaviour to the etype_rtype_registerer |
|
164 """ |
|
165 def do_it_yourself(self, registered): |
|
166 cls = super(etype_rtype_priority_registerer, self).do_it_yourself(registered) |
|
167 if cls: |
|
168 registerer = priority_registerer(self.registry, cls) |
|
169 cls = registerer.do_it_yourself(registered) |
|
170 return cls |
|
171 |
|
172 class action_registerer(etype_rtype_registerer): |
|
173 """'all in one' actions registerer, handling optional .accepts, |
|
174 .etype and .rtype attributes: |
|
175 |
|
176 * if .etype is set and is not an entity type defined in the |
|
177 application schema, skip the wrapped class |
|
178 * if .rtype or .relname is set and is not a relation type defined in |
|
179 the application schema, skip the wrapped class |
|
180 * if .accepts is set, delegate to the accepts_registerer |
|
181 * register |
|
182 """ |
|
183 def do_it_yourself(self, registered): |
|
184 cls = super(action_registerer, self).do_it_yourself(registered) |
|
185 if hasattr(cls, 'accepts'): |
|
186 registerer = accepts_registerer(self.registry, cls) |
|
187 cls = registerer.do_it_yourself(registered) |
|
188 return cls |
|
189 |
|
190 |
|
191 class extresources_registerer(priority_registerer): |
|
192 """'registerer according to a .need_resources attributes which |
|
193 should list necessary resource identifiers for the wrapped object. |
|
194 If one of its resources is missing, don't register |
|
195 """ |
|
196 def do_it_yourself(self, registered): |
|
197 if not hasattr(self.config, 'has_resource'): |
|
198 return |
|
199 for resourceid in self.vobject.need_resources: |
|
200 if not self.config.has_resource(resourceid): |
|
201 return |
|
202 return super(extresources_registerer, self).do_it_yourself(registered) |
|
203 |
|
204 |
|
205 __all__ = [cls.__name__ for cls in globals().values() |
|
206 if isinstance(cls, type) and issubclass(cls, registerer) |
|
207 and not cls is registerer] |
|