Mercurial > public > mercurial-scm > hg
comparison mercurial/thirdparty/zope/interface/declarations.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 # Copyright (c) 2003 Zope Foundation and Contributors. | |
3 # All Rights Reserved. | |
4 # | |
5 # This software is subject to the provisions of the Zope Public License, | |
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. | |
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED | |
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS | |
10 # FOR A PARTICULAR PURPOSE. | |
11 ############################################################################## | |
12 """Implementation of interface declarations | |
13 | |
14 There are three flavors of declarations: | |
15 | |
16 - Declarations are used to simply name declared interfaces. | |
17 | |
18 - ImplementsDeclarations are used to express the interfaces that a | |
19 class implements (that instances of the class provides). | |
20 | |
21 Implements specifications support inheriting interfaces. | |
22 | |
23 - ProvidesDeclarations are used to express interfaces directly | |
24 provided by objects. | |
25 | |
26 """ | |
27 __docformat__ = 'restructuredtext' | |
28 | |
29 import sys | |
30 from types import FunctionType | |
31 from types import MethodType | |
32 from types import ModuleType | |
33 import weakref | |
34 | |
35 from zope.interface.advice import addClassAdvisor | |
36 from zope.interface.interface import InterfaceClass | |
37 from zope.interface.interface import SpecificationBase | |
38 from zope.interface.interface import Specification | |
39 from zope.interface._compat import CLASS_TYPES as DescriptorAwareMetaClasses | |
40 from zope.interface._compat import PYTHON3 | |
41 | |
42 # Registry of class-implementation specifications | |
43 BuiltinImplementationSpecifications = {} | |
44 | |
45 _ADVICE_ERROR = ('Class advice impossible in Python3. ' | |
46 'Use the @%s class decorator instead.') | |
47 | |
48 _ADVICE_WARNING = ('The %s API is deprecated, and will not work in Python3 ' | |
49 'Use the @%s class decorator instead.') | |
50 | |
51 class named(object): | |
52 | |
53 def __init__(self, name): | |
54 self.name = name | |
55 | |
56 def __call__(self, ob): | |
57 ob.__component_name__ = self.name | |
58 return ob | |
59 | |
60 class Declaration(Specification): | |
61 """Interface declarations""" | |
62 | |
63 def __init__(self, *interfaces): | |
64 Specification.__init__(self, _normalizeargs(interfaces)) | |
65 | |
66 def changed(self, originally_changed): | |
67 Specification.changed(self, originally_changed) | |
68 try: | |
69 del self._v_attrs | |
70 except AttributeError: | |
71 pass | |
72 | |
73 def __contains__(self, interface): | |
74 """Test whether an interface is in the specification | |
75 """ | |
76 | |
77 return self.extends(interface) and interface in self.interfaces() | |
78 | |
79 def __iter__(self): | |
80 """Return an iterator for the interfaces in the specification | |
81 """ | |
82 return self.interfaces() | |
83 | |
84 def flattened(self): | |
85 """Return an iterator of all included and extended interfaces | |
86 """ | |
87 return iter(self.__iro__) | |
88 | |
89 def __sub__(self, other): | |
90 """Remove interfaces from a specification | |
91 """ | |
92 return Declaration( | |
93 *[i for i in self.interfaces() | |
94 if not [j for j in other.interfaces() | |
95 if i.extends(j, 0)] | |
96 ] | |
97 ) | |
98 | |
99 def __add__(self, other): | |
100 """Add two specifications or a specification and an interface | |
101 """ | |
102 seen = {} | |
103 result = [] | |
104 for i in self.interfaces(): | |
105 seen[i] = 1 | |
106 result.append(i) | |
107 for i in other.interfaces(): | |
108 if i not in seen: | |
109 seen[i] = 1 | |
110 result.append(i) | |
111 | |
112 return Declaration(*result) | |
113 | |
114 __radd__ = __add__ | |
115 | |
116 | |
117 ############################################################################## | |
118 # | |
119 # Implementation specifications | |
120 # | |
121 # These specify interfaces implemented by instances of classes | |
122 | |
123 class Implements(Declaration): | |
124 | |
125 # class whose specification should be used as additional base | |
126 inherit = None | |
127 | |
128 # interfaces actually declared for a class | |
129 declared = () | |
130 | |
131 __name__ = '?' | |
132 | |
133 @classmethod | |
134 def named(cls, name, *interfaces): | |
135 # Implementation method: Produce an Implements interface with | |
136 # a fully fleshed out __name__ before calling the constructor, which | |
137 # sets bases to the given interfaces and which may pass this object to | |
138 # other objects (e.g., to adjust dependents). If they're sorting or comparing | |
139 # by name, this needs to be set. | |
140 inst = cls.__new__(cls) | |
141 inst.__name__ = name | |
142 inst.__init__(*interfaces) | |
143 return inst | |
144 | |
145 def __repr__(self): | |
146 return '<implementedBy %s>' % (self.__name__) | |
147 | |
148 def __reduce__(self): | |
149 return implementedBy, (self.inherit, ) | |
150 | |
151 def __cmp(self, other): | |
152 # Yes, I did mean to name this __cmp, rather than __cmp__. | |
153 # It is a private method used by __lt__ and __gt__. | |
154 # This is based on, and compatible with, InterfaceClass. | |
155 # (The two must be mutually comparable to be able to work in e.g., BTrees.) | |
156 # Instances of this class generally don't have a __module__ other than | |
157 # `zope.interface.declarations`, whereas they *do* have a __name__ that is the | |
158 # fully qualified name of the object they are representing. | |
159 | |
160 # Note, though, that equality and hashing are still identity based. This | |
161 # accounts for things like nested objects that have the same name (typically | |
162 # only in tests) and is consistent with pickling. As far as comparisons to InterfaceClass | |
163 # goes, we'll never have equal name and module to those, so we're still consistent there. | |
164 # Instances of this class are essentially intended to be unique and are | |
165 # heavily cached (note how our __reduce__ handles this) so having identity | |
166 # based hash and eq should also work. | |
167 if other is None: | |
168 return -1 | |
169 | |
170 n1 = (self.__name__, self.__module__) | |
171 n2 = (getattr(other, '__name__', ''), getattr(other, '__module__', '')) | |
172 | |
173 # This spelling works under Python3, which doesn't have cmp(). | |
174 return (n1 > n2) - (n1 < n2) | |
175 | |
176 def __hash__(self): | |
177 return Declaration.__hash__(self) | |
178 | |
179 # We want equality to be based on identity. However, we can't actually | |
180 # implement __eq__/__ne__ to do this because sometimes we get wrapped in a proxy. | |
181 # We need to let the proxy types implement these methods so they can handle unwrapping | |
182 # and then rely on: (1) the interpreter automatically changing `implements == proxy` into | |
183 # `proxy == implements` (which will call proxy.__eq__ to do the unwrapping) and then | |
184 # (2) the default equality semantics being identity based. | |
185 | |
186 def __lt__(self, other): | |
187 c = self.__cmp(other) | |
188 return c < 0 | |
189 | |
190 def __le__(self, other): | |
191 c = self.__cmp(other) | |
192 return c <= 0 | |
193 | |
194 def __gt__(self, other): | |
195 c = self.__cmp(other) | |
196 return c > 0 | |
197 | |
198 def __ge__(self, other): | |
199 c = self.__cmp(other) | |
200 return c >= 0 | |
201 | |
202 def _implements_name(ob): | |
203 # Return the __name__ attribute to be used by its __implemented__ | |
204 # property. | |
205 # This must be stable for the "same" object across processes | |
206 # because it is used for sorting. It needn't be unique, though, in cases | |
207 # like nested classes named Foo created by different functions, because | |
208 # equality and hashing is still based on identity. | |
209 # It might be nice to use __qualname__ on Python 3, but that would produce | |
210 # different values between Py2 and Py3. | |
211 return (getattr(ob, '__module__', '?') or '?') + \ | |
212 '.' + (getattr(ob, '__name__', '?') or '?') | |
213 | |
214 def implementedByFallback(cls): | |
215 """Return the interfaces implemented for a class' instances | |
216 | |
217 The value returned is an IDeclaration. | |
218 """ | |
219 try: | |
220 spec = cls.__dict__.get('__implemented__') | |
221 except AttributeError: | |
222 | |
223 # we can't get the class dict. This is probably due to a | |
224 # security proxy. If this is the case, then probably no | |
225 # descriptor was installed for the class. | |
226 | |
227 # We don't want to depend directly on zope.security in | |
228 # zope.interface, but we'll try to make reasonable | |
229 # accommodations in an indirect way. | |
230 | |
231 # We'll check to see if there's an implements: | |
232 | |
233 spec = getattr(cls, '__implemented__', None) | |
234 if spec is None: | |
235 # There's no spec stred in the class. Maybe its a builtin: | |
236 spec = BuiltinImplementationSpecifications.get(cls) | |
237 if spec is not None: | |
238 return spec | |
239 return _empty | |
240 | |
241 if spec.__class__ == Implements: | |
242 # we defaulted to _empty or there was a spec. Good enough. | |
243 # Return it. | |
244 return spec | |
245 | |
246 # TODO: need old style __implements__ compatibility? | |
247 # Hm, there's an __implemented__, but it's not a spec. Must be | |
248 # an old-style declaration. Just compute a spec for it | |
249 return Declaration(*_normalizeargs((spec, ))) | |
250 | |
251 if isinstance(spec, Implements): | |
252 return spec | |
253 | |
254 if spec is None: | |
255 spec = BuiltinImplementationSpecifications.get(cls) | |
256 if spec is not None: | |
257 return spec | |
258 | |
259 # TODO: need old style __implements__ compatibility? | |
260 spec_name = _implements_name(cls) | |
261 if spec is not None: | |
262 # old-style __implemented__ = foo declaration | |
263 spec = (spec, ) # tuplefy, as it might be just an int | |
264 spec = Implements.named(spec_name, *_normalizeargs(spec)) | |
265 spec.inherit = None # old-style implies no inherit | |
266 del cls.__implemented__ # get rid of the old-style declaration | |
267 else: | |
268 try: | |
269 bases = cls.__bases__ | |
270 except AttributeError: | |
271 if not callable(cls): | |
272 raise TypeError("ImplementedBy called for non-factory", cls) | |
273 bases = () | |
274 | |
275 spec = Implements.named(spec_name, *[implementedBy(c) for c in bases]) | |
276 spec.inherit = cls | |
277 | |
278 try: | |
279 cls.__implemented__ = spec | |
280 if not hasattr(cls, '__providedBy__'): | |
281 cls.__providedBy__ = objectSpecificationDescriptor | |
282 | |
283 if (isinstance(cls, DescriptorAwareMetaClasses) | |
284 and | |
285 '__provides__' not in cls.__dict__): | |
286 # Make sure we get a __provides__ descriptor | |
287 cls.__provides__ = ClassProvides( | |
288 cls, | |
289 getattr(cls, '__class__', type(cls)), | |
290 ) | |
291 | |
292 except TypeError: | |
293 if not isinstance(cls, type): | |
294 raise TypeError("ImplementedBy called for non-type", cls) | |
295 BuiltinImplementationSpecifications[cls] = spec | |
296 | |
297 return spec | |
298 | |
299 implementedBy = implementedByFallback | |
300 | |
301 def classImplementsOnly(cls, *interfaces): | |
302 """Declare the only interfaces implemented by instances of a class | |
303 | |
304 The arguments after the class are one or more interfaces or interface | |
305 specifications (``IDeclaration`` objects). | |
306 | |
307 The interfaces given (including the interfaces in the specifications) | |
308 replace any previous declarations. | |
309 """ | |
310 spec = implementedBy(cls) | |
311 spec.declared = () | |
312 spec.inherit = None | |
313 classImplements(cls, *interfaces) | |
314 | |
315 def classImplements(cls, *interfaces): | |
316 """Declare additional interfaces implemented for instances of a class | |
317 | |
318 The arguments after the class are one or more interfaces or | |
319 interface specifications (``IDeclaration`` objects). | |
320 | |
321 The interfaces given (including the interfaces in the specifications) | |
322 are added to any interfaces previously declared. | |
323 """ | |
324 spec = implementedBy(cls) | |
325 spec.declared += tuple(_normalizeargs(interfaces)) | |
326 | |
327 # compute the bases | |
328 bases = [] | |
329 seen = {} | |
330 for b in spec.declared: | |
331 if b not in seen: | |
332 seen[b] = 1 | |
333 bases.append(b) | |
334 | |
335 if spec.inherit is not None: | |
336 | |
337 for c in spec.inherit.__bases__: | |
338 b = implementedBy(c) | |
339 if b not in seen: | |
340 seen[b] = 1 | |
341 bases.append(b) | |
342 | |
343 spec.__bases__ = tuple(bases) | |
344 | |
345 def _implements_advice(cls): | |
346 interfaces, classImplements = cls.__dict__['__implements_advice_data__'] | |
347 del cls.__implements_advice_data__ | |
348 classImplements(cls, *interfaces) | |
349 return cls | |
350 | |
351 | |
352 class implementer: | |
353 """Declare the interfaces implemented by instances of a class. | |
354 | |
355 This function is called as a class decorator. | |
356 | |
357 The arguments are one or more interfaces or interface | |
358 specifications (IDeclaration objects). | |
359 | |
360 The interfaces given (including the interfaces in the | |
361 specifications) are added to any interfaces previously | |
362 declared. | |
363 | |
364 Previous declarations include declarations for base classes | |
365 unless implementsOnly was used. | |
366 | |
367 This function is provided for convenience. It provides a more | |
368 convenient way to call classImplements. For example:: | |
369 | |
370 @implementer(I1) | |
371 class C(object): | |
372 pass | |
373 | |
374 is equivalent to calling:: | |
375 | |
376 classImplements(C, I1) | |
377 | |
378 after the class has been created. | |
379 """ | |
380 | |
381 def __init__(self, *interfaces): | |
382 self.interfaces = interfaces | |
383 | |
384 def __call__(self, ob): | |
385 if isinstance(ob, DescriptorAwareMetaClasses): | |
386 classImplements(ob, *self.interfaces) | |
387 return ob | |
388 | |
389 spec_name = _implements_name(ob) | |
390 spec = Implements.named(spec_name, *self.interfaces) | |
391 try: | |
392 ob.__implemented__ = spec | |
393 except AttributeError: | |
394 raise TypeError("Can't declare implements", ob) | |
395 return ob | |
396 | |
397 class implementer_only: | |
398 """Declare the only interfaces implemented by instances of a class | |
399 | |
400 This function is called as a class decorator. | |
401 | |
402 The arguments are one or more interfaces or interface | |
403 specifications (IDeclaration objects). | |
404 | |
405 Previous declarations including declarations for base classes | |
406 are overridden. | |
407 | |
408 This function is provided for convenience. It provides a more | |
409 convenient way to call classImplementsOnly. For example:: | |
410 | |
411 @implementer_only(I1) | |
412 class C(object): pass | |
413 | |
414 is equivalent to calling:: | |
415 | |
416 classImplementsOnly(I1) | |
417 | |
418 after the class has been created. | |
419 """ | |
420 | |
421 def __init__(self, *interfaces): | |
422 self.interfaces = interfaces | |
423 | |
424 def __call__(self, ob): | |
425 if isinstance(ob, (FunctionType, MethodType)): | |
426 # XXX Does this decorator make sense for anything but classes? | |
427 # I don't think so. There can be no inheritance of interfaces | |
428 # on a method pr function.... | |
429 raise ValueError('The implementer_only decorator is not ' | |
430 'supported for methods or functions.') | |
431 else: | |
432 # Assume it's a class: | |
433 classImplementsOnly(ob, *self.interfaces) | |
434 return ob | |
435 | |
436 def _implements(name, interfaces, classImplements): | |
437 # This entire approach is invalid under Py3K. Don't even try to fix | |
438 # the coverage for this block there. :( | |
439 frame = sys._getframe(2) | |
440 locals = frame.f_locals | |
441 | |
442 # Try to make sure we were called from a class def. In 2.2.0 we can't | |
443 # check for __module__ since it doesn't seem to be added to the locals | |
444 # until later on. | |
445 if locals is frame.f_globals or '__module__' not in locals: | |
446 raise TypeError(name+" can be used only from a class definition.") | |
447 | |
448 if '__implements_advice_data__' in locals: | |
449 raise TypeError(name+" can be used only once in a class definition.") | |
450 | |
451 locals['__implements_advice_data__'] = interfaces, classImplements | |
452 addClassAdvisor(_implements_advice, depth=3) | |
453 | |
454 def implements(*interfaces): | |
455 """Declare interfaces implemented by instances of a class | |
456 | |
457 This function is called in a class definition. | |
458 | |
459 The arguments are one or more interfaces or interface | |
460 specifications (IDeclaration objects). | |
461 | |
462 The interfaces given (including the interfaces in the | |
463 specifications) are added to any interfaces previously | |
464 declared. | |
465 | |
466 Previous declarations include declarations for base classes | |
467 unless implementsOnly was used. | |
468 | |
469 This function is provided for convenience. It provides a more | |
470 convenient way to call classImplements. For example:: | |
471 | |
472 implements(I1) | |
473 | |
474 is equivalent to calling:: | |
475 | |
476 classImplements(C, I1) | |
477 | |
478 after the class has been created. | |
479 """ | |
480 # This entire approach is invalid under Py3K. Don't even try to fix | |
481 # the coverage for this block there. :( | |
482 if PYTHON3: | |
483 raise TypeError(_ADVICE_ERROR % 'implementer') | |
484 _implements("implements", interfaces, classImplements) | |
485 | |
486 def implementsOnly(*interfaces): | |
487 """Declare the only interfaces implemented by instances of a class | |
488 | |
489 This function is called in a class definition. | |
490 | |
491 The arguments are one or more interfaces or interface | |
492 specifications (IDeclaration objects). | |
493 | |
494 Previous declarations including declarations for base classes | |
495 are overridden. | |
496 | |
497 This function is provided for convenience. It provides a more | |
498 convenient way to call classImplementsOnly. For example:: | |
499 | |
500 implementsOnly(I1) | |
501 | |
502 is equivalent to calling:: | |
503 | |
504 classImplementsOnly(I1) | |
505 | |
506 after the class has been created. | |
507 """ | |
508 # This entire approach is invalid under Py3K. Don't even try to fix | |
509 # the coverage for this block there. :( | |
510 if PYTHON3: | |
511 raise TypeError(_ADVICE_ERROR % 'implementer_only') | |
512 _implements("implementsOnly", interfaces, classImplementsOnly) | |
513 | |
514 ############################################################################## | |
515 # | |
516 # Instance declarations | |
517 | |
518 class Provides(Declaration): # Really named ProvidesClass | |
519 """Implement __provides__, the instance-specific specification | |
520 | |
521 When an object is pickled, we pickle the interfaces that it implements. | |
522 """ | |
523 | |
524 def __init__(self, cls, *interfaces): | |
525 self.__args = (cls, ) + interfaces | |
526 self._cls = cls | |
527 Declaration.__init__(self, *(interfaces + (implementedBy(cls), ))) | |
528 | |
529 def __reduce__(self): | |
530 return Provides, self.__args | |
531 | |
532 __module__ = 'zope.interface' | |
533 | |
534 def __get__(self, inst, cls): | |
535 """Make sure that a class __provides__ doesn't leak to an instance | |
536 """ | |
537 if inst is None and cls is self._cls: | |
538 # We were accessed through a class, so we are the class' | |
539 # provides spec. Just return this object, but only if we are | |
540 # being called on the same class that we were defined for: | |
541 return self | |
542 | |
543 raise AttributeError('__provides__') | |
544 | |
545 ProvidesClass = Provides | |
546 | |
547 # Registry of instance declarations | |
548 # This is a memory optimization to allow objects to share specifications. | |
549 InstanceDeclarations = weakref.WeakValueDictionary() | |
550 | |
551 def Provides(*interfaces): | |
552 """Cache instance declarations | |
553 | |
554 Instance declarations are shared among instances that have the same | |
555 declaration. The declarations are cached in a weak value dictionary. | |
556 """ | |
557 spec = InstanceDeclarations.get(interfaces) | |
558 if spec is None: | |
559 spec = ProvidesClass(*interfaces) | |
560 InstanceDeclarations[interfaces] = spec | |
561 | |
562 return spec | |
563 | |
564 Provides.__safe_for_unpickling__ = True | |
565 | |
566 | |
567 def directlyProvides(object, *interfaces): | |
568 """Declare interfaces declared directly for an object | |
569 | |
570 The arguments after the object are one or more interfaces or interface | |
571 specifications (``IDeclaration`` objects). | |
572 | |
573 The interfaces given (including the interfaces in the specifications) | |
574 replace interfaces previously declared for the object. | |
575 """ | |
576 cls = getattr(object, '__class__', None) | |
577 if cls is not None and getattr(cls, '__class__', None) is cls: | |
578 # It's a meta class (well, at least it it could be an extension class) | |
579 # Note that we can't get here from Py3k tests: there is no normal | |
580 # class which isn't descriptor aware. | |
581 if not isinstance(object, | |
582 DescriptorAwareMetaClasses): | |
583 raise TypeError("Attempt to make an interface declaration on a " | |
584 "non-descriptor-aware class") | |
585 | |
586 interfaces = _normalizeargs(interfaces) | |
587 if cls is None: | |
588 cls = type(object) | |
589 | |
590 issub = False | |
591 for damc in DescriptorAwareMetaClasses: | |
592 if issubclass(cls, damc): | |
593 issub = True | |
594 break | |
595 if issub: | |
596 # we have a class or type. We'll use a special descriptor | |
597 # that provides some extra caching | |
598 object.__provides__ = ClassProvides(object, cls, *interfaces) | |
599 else: | |
600 object.__provides__ = Provides(cls, *interfaces) | |
601 | |
602 | |
603 def alsoProvides(object, *interfaces): | |
604 """Declare interfaces declared directly for an object | |
605 | |
606 The arguments after the object are one or more interfaces or interface | |
607 specifications (``IDeclaration`` objects). | |
608 | |
609 The interfaces given (including the interfaces in the specifications) are | |
610 added to the interfaces previously declared for the object. | |
611 """ | |
612 directlyProvides(object, directlyProvidedBy(object), *interfaces) | |
613 | |
614 def noLongerProvides(object, interface): | |
615 """ Removes a directly provided interface from an object. | |
616 """ | |
617 directlyProvides(object, directlyProvidedBy(object) - interface) | |
618 if interface.providedBy(object): | |
619 raise ValueError("Can only remove directly provided interfaces.") | |
620 | |
621 class ClassProvidesBaseFallback(object): | |
622 | |
623 def __get__(self, inst, cls): | |
624 if cls is self._cls: | |
625 # We only work if called on the class we were defined for | |
626 | |
627 if inst is None: | |
628 # We were accessed through a class, so we are the class' | |
629 # provides spec. Just return this object as is: | |
630 return self | |
631 | |
632 return self._implements | |
633 | |
634 raise AttributeError('__provides__') | |
635 | |
636 ClassProvidesBasePy = ClassProvidesBaseFallback # BBB | |
637 ClassProvidesBase = ClassProvidesBaseFallback | |
638 | |
639 # Try to get C base: | |
640 try: | |
641 import zope.interface._zope_interface_coptimizations | |
642 except ImportError: | |
643 pass | |
644 else: | |
645 from zope.interface._zope_interface_coptimizations import ClassProvidesBase | |
646 | |
647 | |
648 class ClassProvides(Declaration, ClassProvidesBase): | |
649 """Special descriptor for class __provides__ | |
650 | |
651 The descriptor caches the implementedBy info, so that | |
652 we can get declarations for objects without instance-specific | |
653 interfaces a bit quicker. | |
654 """ | |
655 def __init__(self, cls, metacls, *interfaces): | |
656 self._cls = cls | |
657 self._implements = implementedBy(cls) | |
658 self.__args = (cls, metacls, ) + interfaces | |
659 Declaration.__init__(self, *(interfaces + (implementedBy(metacls), ))) | |
660 | |
661 def __reduce__(self): | |
662 return self.__class__, self.__args | |
663 | |
664 # Copy base-class method for speed | |
665 __get__ = ClassProvidesBase.__get__ | |
666 | |
667 def directlyProvidedBy(object): | |
668 """Return the interfaces directly provided by the given object | |
669 | |
670 The value returned is an ``IDeclaration``. | |
671 """ | |
672 provides = getattr(object, "__provides__", None) | |
673 if (provides is None # no spec | |
674 or | |
675 # We might have gotten the implements spec, as an | |
676 # optimization. If so, it's like having only one base, that we | |
677 # lop off to exclude class-supplied declarations: | |
678 isinstance(provides, Implements) | |
679 ): | |
680 return _empty | |
681 | |
682 # Strip off the class part of the spec: | |
683 return Declaration(provides.__bases__[:-1]) | |
684 | |
685 def classProvides(*interfaces): | |
686 """Declare interfaces provided directly by a class | |
687 | |
688 This function is called in a class definition. | |
689 | |
690 The arguments are one or more interfaces or interface specifications | |
691 (``IDeclaration`` objects). | |
692 | |
693 The given interfaces (including the interfaces in the specifications) | |
694 are used to create the class's direct-object interface specification. | |
695 An error will be raised if the module class has an direct interface | |
696 specification. In other words, it is an error to call this function more | |
697 than once in a class definition. | |
698 | |
699 Note that the given interfaces have nothing to do with the interfaces | |
700 implemented by instances of the class. | |
701 | |
702 This function is provided for convenience. It provides a more convenient | |
703 way to call directlyProvides for a class. For example:: | |
704 | |
705 classProvides(I1) | |
706 | |
707 is equivalent to calling:: | |
708 | |
709 directlyProvides(theclass, I1) | |
710 | |
711 after the class has been created. | |
712 """ | |
713 # This entire approach is invalid under Py3K. Don't even try to fix | |
714 # the coverage for this block there. :( | |
715 | |
716 if PYTHON3: | |
717 raise TypeError(_ADVICE_ERROR % 'provider') | |
718 | |
719 frame = sys._getframe(1) | |
720 locals = frame.f_locals | |
721 | |
722 # Try to make sure we were called from a class def | |
723 if (locals is frame.f_globals) or ('__module__' not in locals): | |
724 raise TypeError("classProvides can be used only from a " | |
725 "class definition.") | |
726 | |
727 if '__provides__' in locals: | |
728 raise TypeError( | |
729 "classProvides can only be used once in a class definition.") | |
730 | |
731 locals["__provides__"] = _normalizeargs(interfaces) | |
732 | |
733 addClassAdvisor(_classProvides_advice, depth=2) | |
734 | |
735 def _classProvides_advice(cls): | |
736 # This entire approach is invalid under Py3K. Don't even try to fix | |
737 # the coverage for this block there. :( | |
738 interfaces = cls.__dict__['__provides__'] | |
739 del cls.__provides__ | |
740 directlyProvides(cls, *interfaces) | |
741 return cls | |
742 | |
743 class provider: | |
744 """Class decorator version of classProvides""" | |
745 | |
746 def __init__(self, *interfaces): | |
747 self.interfaces = interfaces | |
748 | |
749 def __call__(self, ob): | |
750 directlyProvides(ob, *self.interfaces) | |
751 return ob | |
752 | |
753 def moduleProvides(*interfaces): | |
754 """Declare interfaces provided by a module | |
755 | |
756 This function is used in a module definition. | |
757 | |
758 The arguments are one or more interfaces or interface specifications | |
759 (``IDeclaration`` objects). | |
760 | |
761 The given interfaces (including the interfaces in the specifications) are | |
762 used to create the module's direct-object interface specification. An | |
763 error will be raised if the module already has an interface specification. | |
764 In other words, it is an error to call this function more than once in a | |
765 module definition. | |
766 | |
767 This function is provided for convenience. It provides a more convenient | |
768 way to call directlyProvides. For example:: | |
769 | |
770 moduleImplements(I1) | |
771 | |
772 is equivalent to:: | |
773 | |
774 directlyProvides(sys.modules[__name__], I1) | |
775 """ | |
776 frame = sys._getframe(1) | |
777 locals = frame.f_locals | |
778 | |
779 # Try to make sure we were called from a class def | |
780 if (locals is not frame.f_globals) or ('__name__' not in locals): | |
781 raise TypeError( | |
782 "moduleProvides can only be used from a module definition.") | |
783 | |
784 if '__provides__' in locals: | |
785 raise TypeError( | |
786 "moduleProvides can only be used once in a module definition.") | |
787 | |
788 locals["__provides__"] = Provides(ModuleType, | |
789 *_normalizeargs(interfaces)) | |
790 | |
791 ############################################################################## | |
792 # | |
793 # Declaration querying support | |
794 | |
795 # XXX: is this a fossil? Nobody calls it, no unit tests exercise it, no | |
796 # doctests import it, and the package __init__ doesn't import it. | |
797 def ObjectSpecification(direct, cls): | |
798 """Provide object specifications | |
799 | |
800 These combine information for the object and for it's classes. | |
801 """ | |
802 return Provides(cls, direct) # pragma: no cover fossil | |
803 | |
804 def getObjectSpecificationFallback(ob): | |
805 | |
806 provides = getattr(ob, '__provides__', None) | |
807 if provides is not None: | |
808 if isinstance(provides, SpecificationBase): | |
809 return provides | |
810 | |
811 try: | |
812 cls = ob.__class__ | |
813 except AttributeError: | |
814 # We can't get the class, so just consider provides | |
815 return _empty | |
816 | |
817 return implementedBy(cls) | |
818 | |
819 getObjectSpecification = getObjectSpecificationFallback | |
820 | |
821 def providedByFallback(ob): | |
822 | |
823 # Here we have either a special object, an old-style declaration | |
824 # or a descriptor | |
825 | |
826 # Try to get __providedBy__ | |
827 try: | |
828 r = ob.__providedBy__ | |
829 except AttributeError: | |
830 # Not set yet. Fall back to lower-level thing that computes it | |
831 return getObjectSpecification(ob) | |
832 | |
833 try: | |
834 # We might have gotten a descriptor from an instance of a | |
835 # class (like an ExtensionClass) that doesn't support | |
836 # descriptors. We'll make sure we got one by trying to get | |
837 # the only attribute, which all specs have. | |
838 r.extends | |
839 | |
840 except AttributeError: | |
841 | |
842 # The object's class doesn't understand descriptors. | |
843 # Sigh. We need to get an object descriptor, but we have to be | |
844 # careful. We want to use the instance's __provides__, if | |
845 # there is one, but only if it didn't come from the class. | |
846 | |
847 try: | |
848 r = ob.__provides__ | |
849 except AttributeError: | |
850 # No __provides__, so just fall back to implementedBy | |
851 return implementedBy(ob.__class__) | |
852 | |
853 # We need to make sure we got the __provides__ from the | |
854 # instance. We'll do this by making sure we don't get the same | |
855 # thing from the class: | |
856 | |
857 try: | |
858 cp = ob.__class__.__provides__ | |
859 except AttributeError: | |
860 # The ob doesn't have a class or the class has no | |
861 # provides, assume we're done: | |
862 return r | |
863 | |
864 if r is cp: | |
865 # Oops, we got the provides from the class. This means | |
866 # the object doesn't have it's own. We should use implementedBy | |
867 return implementedBy(ob.__class__) | |
868 | |
869 return r | |
870 providedBy = providedByFallback | |
871 | |
872 class ObjectSpecificationDescriptorFallback(object): | |
873 """Implement the `__providedBy__` attribute | |
874 | |
875 The `__providedBy__` attribute computes the interfaces peovided by | |
876 an object. | |
877 """ | |
878 | |
879 def __get__(self, inst, cls): | |
880 """Get an object specification for an object | |
881 """ | |
882 if inst is None: | |
883 return getObjectSpecification(cls) | |
884 | |
885 provides = getattr(inst, '__provides__', None) | |
886 if provides is not None: | |
887 return provides | |
888 | |
889 return implementedBy(cls) | |
890 | |
891 ObjectSpecificationDescriptor = ObjectSpecificationDescriptorFallback | |
892 | |
893 ############################################################################## | |
894 | |
895 def _normalizeargs(sequence, output = None): | |
896 """Normalize declaration arguments | |
897 | |
898 Normalization arguments might contain Declarions, tuples, or single | |
899 interfaces. | |
900 | |
901 Anything but individial interfaces or implements specs will be expanded. | |
902 """ | |
903 if output is None: | |
904 output = [] | |
905 | |
906 cls = sequence.__class__ | |
907 if InterfaceClass in cls.__mro__ or Implements in cls.__mro__: | |
908 output.append(sequence) | |
909 else: | |
910 for v in sequence: | |
911 _normalizeargs(v, output) | |
912 | |
913 return output | |
914 | |
915 _empty = Declaration() | |
916 | |
917 try: | |
918 import zope.interface._zope_interface_coptimizations | |
919 except ImportError: | |
920 pass | |
921 else: | |
922 from zope.interface._zope_interface_coptimizations import implementedBy | |
923 from zope.interface._zope_interface_coptimizations import providedBy | |
924 from zope.interface._zope_interface_coptimizations import ( | |
925 getObjectSpecification) | |
926 from zope.interface._zope_interface_coptimizations import ( | |
927 ObjectSpecificationDescriptor) | |
928 | |
929 objectSpecificationDescriptor = ObjectSpecificationDescriptor() |