Mercurial > public > mercurial-scm > hg
comparison mercurial/thirdparty/zope/interface/adapter.py @ 37176:943d77fc07a3
thirdparty: vendor zope.interface 4.4.3
I've been trying to formalize interfaces for various components
of Mercurial. So far, we've been using the "abc" package. This
package is "good enough" for a lot of tasks. But it quickly
falls over. For example, if you declare an @abc.abstractproperty,
you must implement that attribute with a @property or the class
compile time checking performed by abc will complain. This often
forces you to implement dumb @property wrappers to return a
_ prefixed attribute of the sane name. That's ugly.
I've also wanted to implement automated checking that classes
conform to various interfaces and don't expose other "public"
attributes.
After doing a bit of research and asking around, the general
consensus seems to be that zope.interface is the best package for
doing interface-based programming in Python. It has built-in
support for verifying classes and objects conform to interfaces.
It allows an interface's properties to be defined during __init__.
There's even an "adapter registry" that allow you to register
interfaces and look up which classes implement them. That could
potentially be useful for places where our custom registry.py
modules currently facilitates central registrations, but at a
type level. Imagine extensions providing alternate implementations
of things like the local repository interface to allow opening
repositories with custom requirements.
Anyway, this commit vendors zope.interface 4.4.3. The contents of
the source tarball have been copied into mercurial/thirdparty/zope/
without modifications.
Test modules have been removed because they are not interesting
to us.
The LICENSE.txt file has been copied so it lives next to the
source.
The Python modules don't use relative imports. zope/__init__.py
defines a namespace package. So we'll need to modify the source
code before this package is usable inside Mercurial. This will
be done in subsequent commits.
# no-check-commit for various style failures
Differential Revision: https://phab.mercurial-scm.org/D2928
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Wed, 21 Mar 2018 19:48:50 -0700 |
parents | |
children | 68ee61822182 |
comparison
equal
deleted
inserted
replaced
37175:fbe34945220d | 37176:943d77fc07a3 |
---|---|
1 ############################################################################## | |
2 # | |
3 # Copyright (c) 2004 Zope Foundation and Contributors. | |
4 # All Rights Reserved. | |
5 # | |
6 # This software is subject to the provisions of the Zope Public License, | |
7 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | |
8 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | |
9 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
10 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | |
11 # FOR A PARTICULAR PURPOSE. | |
12 # | |
13 ############################################################################## | |
14 """Adapter management | |
15 """ | |
16 import weakref | |
17 | |
18 from zope.interface import implementer | |
19 from zope.interface import providedBy | |
20 from zope.interface import Interface | |
21 from zope.interface import ro | |
22 from zope.interface.interfaces import IAdapterRegistry | |
23 | |
24 from zope.interface._compat import _normalize_name | |
25 from zope.interface._compat import STRING_TYPES | |
26 | |
27 _BLANK = u'' | |
28 | |
29 class BaseAdapterRegistry(object): | |
30 | |
31 # List of methods copied from lookup sub-objects: | |
32 _delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter', | |
33 'adapter_hook', 'lookupAll', 'names', | |
34 'subscriptions', 'subscribers') | |
35 | |
36 # All registries maintain a generation that can be used by verifying | |
37 # registries | |
38 _generation = 0 | |
39 | |
40 def __init__(self, bases=()): | |
41 | |
42 # The comments here could be improved. Possibly this bit needs | |
43 # explaining in a separate document, as the comments here can | |
44 # be quite confusing. /regebro | |
45 | |
46 # {order -> {required -> {provided -> {name -> value}}}} | |
47 # Here "order" is actually an index in a list, "required" and | |
48 # "provided" are interfaces, and "required" is really a nested | |
49 # key. So, for example: | |
50 # for order == 0 (that is, self._adapters[0]), we have: | |
51 # {provided -> {name -> value}} | |
52 # but for order == 2 (that is, self._adapters[2]), we have: | |
53 # {r1 -> {r2 -> {provided -> {name -> value}}}} | |
54 # | |
55 self._adapters = [] | |
56 | |
57 # {order -> {required -> {provided -> {name -> [value]}}}} | |
58 # where the remarks about adapters above apply | |
59 self._subscribers = [] | |
60 | |
61 # Set, with a reference count, keeping track of the interfaces | |
62 # for which we have provided components: | |
63 self._provided = {} | |
64 | |
65 # Create ``_v_lookup`` object to perform lookup. We make this a | |
66 # separate object to to make it easier to implement just the | |
67 # lookup functionality in C. This object keeps track of cache | |
68 # invalidation data in two kinds of registries. | |
69 | |
70 # Invalidating registries have caches that are invalidated | |
71 # when they or their base registies change. An invalidating | |
72 # registry can only have invalidating registries as bases. | |
73 # See LookupBaseFallback below for the pertinent logic. | |
74 | |
75 # Verifying registies can't rely on getting invalidation messages, | |
76 # so have to check the generations of base registries to determine | |
77 # if their cache data are current. See VerifyingBasePy below | |
78 # for the pertinent object. | |
79 self._createLookup() | |
80 | |
81 # Setting the bases causes the registries described above | |
82 # to be initialized (self._setBases -> self.changed -> | |
83 # self._v_lookup.changed). | |
84 | |
85 self.__bases__ = bases | |
86 | |
87 def _setBases(self, bases): | |
88 self.__dict__['__bases__'] = bases | |
89 self.ro = ro.ro(self) | |
90 self.changed(self) | |
91 | |
92 __bases__ = property(lambda self: self.__dict__['__bases__'], | |
93 lambda self, bases: self._setBases(bases), | |
94 ) | |
95 | |
96 def _createLookup(self): | |
97 self._v_lookup = self.LookupClass(self) | |
98 for name in self._delegated: | |
99 self.__dict__[name] = getattr(self._v_lookup, name) | |
100 | |
101 def changed(self, originally_changed): | |
102 self._generation += 1 | |
103 self._v_lookup.changed(originally_changed) | |
104 | |
105 def register(self, required, provided, name, value): | |
106 if not isinstance(name, STRING_TYPES): | |
107 raise ValueError('name is not a string') | |
108 if value is None: | |
109 self.unregister(required, provided, name, value) | |
110 return | |
111 | |
112 required = tuple(map(_convert_None_to_Interface, required)) | |
113 name = _normalize_name(name) | |
114 order = len(required) | |
115 byorder = self._adapters | |
116 while len(byorder) <= order: | |
117 byorder.append({}) | |
118 components = byorder[order] | |
119 key = required + (provided,) | |
120 | |
121 for k in key: | |
122 d = components.get(k) | |
123 if d is None: | |
124 d = {} | |
125 components[k] = d | |
126 components = d | |
127 | |
128 if components.get(name) is value: | |
129 return | |
130 | |
131 components[name] = value | |
132 | |
133 n = self._provided.get(provided, 0) + 1 | |
134 self._provided[provided] = n | |
135 if n == 1: | |
136 self._v_lookup.add_extendor(provided) | |
137 | |
138 self.changed(self) | |
139 | |
140 def registered(self, required, provided, name=_BLANK): | |
141 required = tuple(map(_convert_None_to_Interface, required)) | |
142 name = _normalize_name(name) | |
143 order = len(required) | |
144 byorder = self._adapters | |
145 if len(byorder) <= order: | |
146 return None | |
147 | |
148 components = byorder[order] | |
149 key = required + (provided,) | |
150 | |
151 for k in key: | |
152 d = components.get(k) | |
153 if d is None: | |
154 return None | |
155 components = d | |
156 | |
157 return components.get(name) | |
158 | |
159 def unregister(self, required, provided, name, value=None): | |
160 required = tuple(map(_convert_None_to_Interface, required)) | |
161 order = len(required) | |
162 byorder = self._adapters | |
163 if order >= len(byorder): | |
164 return False | |
165 components = byorder[order] | |
166 key = required + (provided,) | |
167 | |
168 # Keep track of how we got to `components`: | |
169 lookups = [] | |
170 for k in key: | |
171 d = components.get(k) | |
172 if d is None: | |
173 return | |
174 lookups.append((components, k)) | |
175 components = d | |
176 | |
177 old = components.get(name) | |
178 if old is None: | |
179 return | |
180 if (value is not None) and (old is not value): | |
181 return | |
182 | |
183 del components[name] | |
184 if not components: | |
185 # Clean out empty containers, since we don't want our keys | |
186 # to reference global objects (interfaces) unnecessarily. | |
187 # This is often a problem when an interface is slated for | |
188 # removal; a hold-over entry in the registry can make it | |
189 # difficult to remove such interfaces. | |
190 for comp, k in reversed(lookups): | |
191 d = comp[k] | |
192 if d: | |
193 break | |
194 else: | |
195 del comp[k] | |
196 while byorder and not byorder[-1]: | |
197 del byorder[-1] | |
198 n = self._provided[provided] - 1 | |
199 if n == 0: | |
200 del self._provided[provided] | |
201 self._v_lookup.remove_extendor(provided) | |
202 else: | |
203 self._provided[provided] = n | |
204 | |
205 self.changed(self) | |
206 | |
207 def subscribe(self, required, provided, value): | |
208 required = tuple(map(_convert_None_to_Interface, required)) | |
209 name = _BLANK | |
210 order = len(required) | |
211 byorder = self._subscribers | |
212 while len(byorder) <= order: | |
213 byorder.append({}) | |
214 components = byorder[order] | |
215 key = required + (provided,) | |
216 | |
217 for k in key: | |
218 d = components.get(k) | |
219 if d is None: | |
220 d = {} | |
221 components[k] = d | |
222 components = d | |
223 | |
224 components[name] = components.get(name, ()) + (value, ) | |
225 | |
226 if provided is not None: | |
227 n = self._provided.get(provided, 0) + 1 | |
228 self._provided[provided] = n | |
229 if n == 1: | |
230 self._v_lookup.add_extendor(provided) | |
231 | |
232 self.changed(self) | |
233 | |
234 def unsubscribe(self, required, provided, value=None): | |
235 required = tuple(map(_convert_None_to_Interface, required)) | |
236 order = len(required) | |
237 byorder = self._subscribers | |
238 if order >= len(byorder): | |
239 return | |
240 components = byorder[order] | |
241 key = required + (provided,) | |
242 | |
243 # Keep track of how we got to `components`: | |
244 lookups = [] | |
245 for k in key: | |
246 d = components.get(k) | |
247 if d is None: | |
248 return | |
249 lookups.append((components, k)) | |
250 components = d | |
251 | |
252 old = components.get(_BLANK) | |
253 if not old: | |
254 # this is belt-and-suspenders against the failure of cleanup below | |
255 return # pragma: no cover | |
256 | |
257 if value is None: | |
258 new = () | |
259 else: | |
260 new = tuple([v for v in old if v is not value]) | |
261 | |
262 if new == old: | |
263 return | |
264 | |
265 if new: | |
266 components[_BLANK] = new | |
267 else: | |
268 # Instead of setting components[_BLANK] = new, we clean out | |
269 # empty containers, since we don't want our keys to | |
270 # reference global objects (interfaces) unnecessarily. This | |
271 # is often a problem when an interface is slated for | |
272 # removal; a hold-over entry in the registry can make it | |
273 # difficult to remove such interfaces. | |
274 del components[_BLANK] | |
275 for comp, k in reversed(lookups): | |
276 d = comp[k] | |
277 if d: | |
278 break | |
279 else: | |
280 del comp[k] | |
281 while byorder and not byorder[-1]: | |
282 del byorder[-1] | |
283 | |
284 if provided is not None: | |
285 n = self._provided[provided] + len(new) - len(old) | |
286 if n == 0: | |
287 del self._provided[provided] | |
288 self._v_lookup.remove_extendor(provided) | |
289 | |
290 self.changed(self) | |
291 | |
292 # XXX hack to fake out twisted's use of a private api. We need to get them | |
293 # to use the new registed method. | |
294 def get(self, _): # pragma: no cover | |
295 class XXXTwistedFakeOut: | |
296 selfImplied = {} | |
297 return XXXTwistedFakeOut | |
298 | |
299 | |
300 _not_in_mapping = object() | |
301 class LookupBaseFallback(object): | |
302 | |
303 def __init__(self): | |
304 self._cache = {} | |
305 self._mcache = {} | |
306 self._scache = {} | |
307 | |
308 def changed(self, ignored=None): | |
309 self._cache.clear() | |
310 self._mcache.clear() | |
311 self._scache.clear() | |
312 | |
313 def _getcache(self, provided, name): | |
314 cache = self._cache.get(provided) | |
315 if cache is None: | |
316 cache = {} | |
317 self._cache[provided] = cache | |
318 if name: | |
319 c = cache.get(name) | |
320 if c is None: | |
321 c = {} | |
322 cache[name] = c | |
323 cache = c | |
324 return cache | |
325 | |
326 def lookup(self, required, provided, name=_BLANK, default=None): | |
327 if not isinstance(name, STRING_TYPES): | |
328 raise ValueError('name is not a string') | |
329 cache = self._getcache(provided, name) | |
330 required = tuple(required) | |
331 if len(required) == 1: | |
332 result = cache.get(required[0], _not_in_mapping) | |
333 else: | |
334 result = cache.get(tuple(required), _not_in_mapping) | |
335 | |
336 if result is _not_in_mapping: | |
337 result = self._uncached_lookup(required, provided, name) | |
338 if len(required) == 1: | |
339 cache[required[0]] = result | |
340 else: | |
341 cache[tuple(required)] = result | |
342 | |
343 if result is None: | |
344 return default | |
345 | |
346 return result | |
347 | |
348 def lookup1(self, required, provided, name=_BLANK, default=None): | |
349 if not isinstance(name, STRING_TYPES): | |
350 raise ValueError('name is not a string') | |
351 cache = self._getcache(provided, name) | |
352 result = cache.get(required, _not_in_mapping) | |
353 if result is _not_in_mapping: | |
354 return self.lookup((required, ), provided, name, default) | |
355 | |
356 if result is None: | |
357 return default | |
358 | |
359 return result | |
360 | |
361 def queryAdapter(self, object, provided, name=_BLANK, default=None): | |
362 return self.adapter_hook(provided, object, name, default) | |
363 | |
364 def adapter_hook(self, provided, object, name=_BLANK, default=None): | |
365 if not isinstance(name, STRING_TYPES): | |
366 raise ValueError('name is not a string') | |
367 required = providedBy(object) | |
368 cache = self._getcache(provided, name) | |
369 factory = cache.get(required, _not_in_mapping) | |
370 if factory is _not_in_mapping: | |
371 factory = self.lookup((required, ), provided, name) | |
372 | |
373 if factory is not None: | |
374 result = factory(object) | |
375 if result is not None: | |
376 return result | |
377 | |
378 return default | |
379 | |
380 def lookupAll(self, required, provided): | |
381 cache = self._mcache.get(provided) | |
382 if cache is None: | |
383 cache = {} | |
384 self._mcache[provided] = cache | |
385 | |
386 required = tuple(required) | |
387 result = cache.get(required, _not_in_mapping) | |
388 if result is _not_in_mapping: | |
389 result = self._uncached_lookupAll(required, provided) | |
390 cache[required] = result | |
391 | |
392 return result | |
393 | |
394 | |
395 def subscriptions(self, required, provided): | |
396 cache = self._scache.get(provided) | |
397 if cache is None: | |
398 cache = {} | |
399 self._scache[provided] = cache | |
400 | |
401 required = tuple(required) | |
402 result = cache.get(required, _not_in_mapping) | |
403 if result is _not_in_mapping: | |
404 result = self._uncached_subscriptions(required, provided) | |
405 cache[required] = result | |
406 | |
407 return result | |
408 | |
409 LookupBasePy = LookupBaseFallback # BBB | |
410 | |
411 try: | |
412 from zope.interface._zope_interface_coptimizations import LookupBase | |
413 except ImportError: | |
414 LookupBase = LookupBaseFallback | |
415 | |
416 | |
417 class VerifyingBaseFallback(LookupBaseFallback): | |
418 # Mixin for lookups against registries which "chain" upwards, and | |
419 # whose lookups invalidate their own caches whenever a parent registry | |
420 # bumps its own '_generation' counter. E.g., used by | |
421 # zope.component.persistentregistry | |
422 | |
423 def changed(self, originally_changed): | |
424 LookupBaseFallback.changed(self, originally_changed) | |
425 self._verify_ro = self._registry.ro[1:] | |
426 self._verify_generations = [r._generation for r in self._verify_ro] | |
427 | |
428 def _verify(self): | |
429 if ([r._generation for r in self._verify_ro] | |
430 != self._verify_generations): | |
431 self.changed(None) | |
432 | |
433 def _getcache(self, provided, name): | |
434 self._verify() | |
435 return LookupBaseFallback._getcache(self, provided, name) | |
436 | |
437 def lookupAll(self, required, provided): | |
438 self._verify() | |
439 return LookupBaseFallback.lookupAll(self, required, provided) | |
440 | |
441 def subscriptions(self, required, provided): | |
442 self._verify() | |
443 return LookupBaseFallback.subscriptions(self, required, provided) | |
444 | |
445 VerifyingBasePy = VerifyingBaseFallback #BBB | |
446 | |
447 try: | |
448 from zope.interface._zope_interface_coptimizations import VerifyingBase | |
449 except ImportError: | |
450 VerifyingBase = VerifyingBaseFallback | |
451 | |
452 | |
453 class AdapterLookupBase(object): | |
454 | |
455 def __init__(self, registry): | |
456 self._registry = registry | |
457 self._required = {} | |
458 self.init_extendors() | |
459 super(AdapterLookupBase, self).__init__() | |
460 | |
461 def changed(self, ignored=None): | |
462 super(AdapterLookupBase, self).changed(None) | |
463 for r in self._required.keys(): | |
464 r = r() | |
465 if r is not None: | |
466 r.unsubscribe(self) | |
467 self._required.clear() | |
468 | |
469 | |
470 # Extendors | |
471 # --------- | |
472 | |
473 # When given an target interface for an adapter lookup, we need to consider | |
474 # adapters for interfaces that extend the target interface. This is | |
475 # what the extendors dictionary is about. It tells us all of the | |
476 # interfaces that extend an interface for which there are adapters | |
477 # registered. | |
478 | |
479 # We could separate this by order and name, thus reducing the | |
480 # number of provided interfaces to search at run time. The tradeoff, | |
481 # however, is that we have to store more information. For example, | |
482 # if the same interface is provided for multiple names and if the | |
483 # interface extends many interfaces, we'll have to keep track of | |
484 # a fair bit of information for each name. It's better to | |
485 # be space efficient here and be time efficient in the cache | |
486 # implementation. | |
487 | |
488 # TODO: add invalidation when a provided interface changes, in case | |
489 # the interface's __iro__ has changed. This is unlikely enough that | |
490 # we'll take our chances for now. | |
491 | |
492 def init_extendors(self): | |
493 self._extendors = {} | |
494 for p in self._registry._provided: | |
495 self.add_extendor(p) | |
496 | |
497 def add_extendor(self, provided): | |
498 _extendors = self._extendors | |
499 for i in provided.__iro__: | |
500 extendors = _extendors.get(i, ()) | |
501 _extendors[i] = ( | |
502 [e for e in extendors if provided.isOrExtends(e)] | |
503 + | |
504 [provided] | |
505 + | |
506 [e for e in extendors if not provided.isOrExtends(e)] | |
507 ) | |
508 | |
509 def remove_extendor(self, provided): | |
510 _extendors = self._extendors | |
511 for i in provided.__iro__: | |
512 _extendors[i] = [e for e in _extendors.get(i, ()) | |
513 if e != provided] | |
514 | |
515 | |
516 def _subscribe(self, *required): | |
517 _refs = self._required | |
518 for r in required: | |
519 ref = r.weakref() | |
520 if ref not in _refs: | |
521 r.subscribe(self) | |
522 _refs[ref] = 1 | |
523 | |
524 def _uncached_lookup(self, required, provided, name=_BLANK): | |
525 required = tuple(required) | |
526 result = None | |
527 order = len(required) | |
528 for registry in self._registry.ro: | |
529 byorder = registry._adapters | |
530 if order >= len(byorder): | |
531 continue | |
532 | |
533 extendors = registry._v_lookup._extendors.get(provided) | |
534 if not extendors: | |
535 continue | |
536 | |
537 components = byorder[order] | |
538 result = _lookup(components, required, extendors, name, 0, | |
539 order) | |
540 if result is not None: | |
541 break | |
542 | |
543 self._subscribe(*required) | |
544 | |
545 return result | |
546 | |
547 def queryMultiAdapter(self, objects, provided, name=_BLANK, default=None): | |
548 factory = self.lookup(map(providedBy, objects), provided, name) | |
549 if factory is None: | |
550 return default | |
551 | |
552 result = factory(*objects) | |
553 if result is None: | |
554 return default | |
555 | |
556 return result | |
557 | |
558 def _uncached_lookupAll(self, required, provided): | |
559 required = tuple(required) | |
560 order = len(required) | |
561 result = {} | |
562 for registry in reversed(self._registry.ro): | |
563 byorder = registry._adapters | |
564 if order >= len(byorder): | |
565 continue | |
566 extendors = registry._v_lookup._extendors.get(provided) | |
567 if not extendors: | |
568 continue | |
569 components = byorder[order] | |
570 _lookupAll(components, required, extendors, result, 0, order) | |
571 | |
572 self._subscribe(*required) | |
573 | |
574 return tuple(result.items()) | |
575 | |
576 def names(self, required, provided): | |
577 return [c[0] for c in self.lookupAll(required, provided)] | |
578 | |
579 def _uncached_subscriptions(self, required, provided): | |
580 required = tuple(required) | |
581 order = len(required) | |
582 result = [] | |
583 for registry in reversed(self._registry.ro): | |
584 byorder = registry._subscribers | |
585 if order >= len(byorder): | |
586 continue | |
587 | |
588 if provided is None: | |
589 extendors = (provided, ) | |
590 else: | |
591 extendors = registry._v_lookup._extendors.get(provided) | |
592 if extendors is None: | |
593 continue | |
594 | |
595 _subscriptions(byorder[order], required, extendors, _BLANK, | |
596 result, 0, order) | |
597 | |
598 self._subscribe(*required) | |
599 | |
600 return result | |
601 | |
602 def subscribers(self, objects, provided): | |
603 subscriptions = self.subscriptions(map(providedBy, objects), provided) | |
604 if provided is None: | |
605 result = () | |
606 for subscription in subscriptions: | |
607 subscription(*objects) | |
608 else: | |
609 result = [] | |
610 for subscription in subscriptions: | |
611 subscriber = subscription(*objects) | |
612 if subscriber is not None: | |
613 result.append(subscriber) | |
614 return result | |
615 | |
616 class AdapterLookup(AdapterLookupBase, LookupBase): | |
617 pass | |
618 | |
619 @implementer(IAdapterRegistry) | |
620 class AdapterRegistry(BaseAdapterRegistry): | |
621 | |
622 LookupClass = AdapterLookup | |
623 | |
624 def __init__(self, bases=()): | |
625 # AdapterRegisties are invalidating registries, so | |
626 # we need to keep track of out invalidating subregistries. | |
627 self._v_subregistries = weakref.WeakKeyDictionary() | |
628 | |
629 super(AdapterRegistry, self).__init__(bases) | |
630 | |
631 def _addSubregistry(self, r): | |
632 self._v_subregistries[r] = 1 | |
633 | |
634 def _removeSubregistry(self, r): | |
635 if r in self._v_subregistries: | |
636 del self._v_subregistries[r] | |
637 | |
638 def _setBases(self, bases): | |
639 old = self.__dict__.get('__bases__', ()) | |
640 for r in old: | |
641 if r not in bases: | |
642 r._removeSubregistry(self) | |
643 for r in bases: | |
644 if r not in old: | |
645 r._addSubregistry(self) | |
646 | |
647 super(AdapterRegistry, self)._setBases(bases) | |
648 | |
649 def changed(self, originally_changed): | |
650 super(AdapterRegistry, self).changed(originally_changed) | |
651 | |
652 for sub in self._v_subregistries.keys(): | |
653 sub.changed(originally_changed) | |
654 | |
655 | |
656 class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase): | |
657 pass | |
658 | |
659 @implementer(IAdapterRegistry) | |
660 class VerifyingAdapterRegistry(BaseAdapterRegistry): | |
661 | |
662 LookupClass = VerifyingAdapterLookup | |
663 | |
664 def _convert_None_to_Interface(x): | |
665 if x is None: | |
666 return Interface | |
667 else: | |
668 return x | |
669 | |
670 def _lookup(components, specs, provided, name, i, l): | |
671 if i < l: | |
672 for spec in specs[i].__sro__: | |
673 comps = components.get(spec) | |
674 if comps: | |
675 r = _lookup(comps, specs, provided, name, i+1, l) | |
676 if r is not None: | |
677 return r | |
678 else: | |
679 for iface in provided: | |
680 comps = components.get(iface) | |
681 if comps: | |
682 r = comps.get(name) | |
683 if r is not None: | |
684 return r | |
685 | |
686 return None | |
687 | |
688 def _lookupAll(components, specs, provided, result, i, l): | |
689 if i < l: | |
690 for spec in reversed(specs[i].__sro__): | |
691 comps = components.get(spec) | |
692 if comps: | |
693 _lookupAll(comps, specs, provided, result, i+1, l) | |
694 else: | |
695 for iface in reversed(provided): | |
696 comps = components.get(iface) | |
697 if comps: | |
698 result.update(comps) | |
699 | |
700 def _subscriptions(components, specs, provided, name, result, i, l): | |
701 if i < l: | |
702 for spec in reversed(specs[i].__sro__): | |
703 comps = components.get(spec) | |
704 if comps: | |
705 _subscriptions(comps, specs, provided, name, result, i+1, l) | |
706 else: | |
707 for iface in reversed(provided): | |
708 comps = components.get(iface) | |
709 if comps: | |
710 comps = comps.get(name) | |
711 if comps: | |
712 result.extend(comps) |