123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929 |
- ##############################################################################
- # Copyright (c) 2003 Zope Foundation and Contributors.
- # All Rights Reserved.
- #
- # This software is subject to the provisions of the Zope Public License,
- # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
- # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
- # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
- # FOR A PARTICULAR PURPOSE.
- ##############################################################################
- """Implementation of interface declarations
- There are three flavors of declarations:
- - Declarations are used to simply name declared interfaces.
- - ImplementsDeclarations are used to express the interfaces that a
- class implements (that instances of the class provides).
- Implements specifications support inheriting interfaces.
- - ProvidesDeclarations are used to express interfaces directly
- provided by objects.
- """
- __docformat__ = 'restructuredtext'
- import sys
- from types import FunctionType
- from types import MethodType
- from types import ModuleType
- import weakref
- from zope.interface.advice import addClassAdvisor
- from zope.interface.interface import InterfaceClass
- from zope.interface.interface import SpecificationBase
- from zope.interface.interface import Specification
- from zope.interface._compat import CLASS_TYPES as DescriptorAwareMetaClasses
- from zope.interface._compat import PYTHON3
- # Registry of class-implementation specifications
- BuiltinImplementationSpecifications = {}
- _ADVICE_ERROR = ('Class advice impossible in Python3. '
- 'Use the @%s class decorator instead.')
- _ADVICE_WARNING = ('The %s API is deprecated, and will not work in Python3 '
- 'Use the @%s class decorator instead.')
- class named(object):
- def __init__(self, name):
- self.name = name
- def __call__(self, ob):
- ob.__component_name__ = self.name
- return ob
- class Declaration(Specification):
- """Interface declarations"""
- def __init__(self, *interfaces):
- Specification.__init__(self, _normalizeargs(interfaces))
- def changed(self, originally_changed):
- Specification.changed(self, originally_changed)
- try:
- del self._v_attrs
- except AttributeError:
- pass
- def __contains__(self, interface):
- """Test whether an interface is in the specification
- """
- return self.extends(interface) and interface in self.interfaces()
- def __iter__(self):
- """Return an iterator for the interfaces in the specification
- """
- return self.interfaces()
- def flattened(self):
- """Return an iterator of all included and extended interfaces
- """
- return iter(self.__iro__)
- def __sub__(self, other):
- """Remove interfaces from a specification
- """
- return Declaration(
- *[i for i in self.interfaces()
- if not [j for j in other.interfaces()
- if i.extends(j, 0)]
- ]
- )
- def __add__(self, other):
- """Add two specifications or a specification and an interface
- """
- seen = {}
- result = []
- for i in self.interfaces():
- seen[i] = 1
- result.append(i)
- for i in other.interfaces():
- if i not in seen:
- seen[i] = 1
- result.append(i)
- return Declaration(*result)
- __radd__ = __add__
- ##############################################################################
- #
- # Implementation specifications
- #
- # These specify interfaces implemented by instances of classes
- class Implements(Declaration):
- # class whose specification should be used as additional base
- inherit = None
- # interfaces actually declared for a class
- declared = ()
- __name__ = '?'
- @classmethod
- def named(cls, name, *interfaces):
- # Implementation method: Produce an Implements interface with
- # a fully fleshed out __name__ before calling the constructor, which
- # sets bases to the given interfaces and which may pass this object to
- # other objects (e.g., to adjust dependents). If they're sorting or comparing
- # by name, this needs to be set.
- inst = cls.__new__(cls)
- inst.__name__ = name
- inst.__init__(*interfaces)
- return inst
- def __repr__(self):
- return '<implementedBy %s>' % (self.__name__)
- def __reduce__(self):
- return implementedBy, (self.inherit, )
- def __cmp(self, other):
- # Yes, I did mean to name this __cmp, rather than __cmp__.
- # It is a private method used by __lt__ and __gt__.
- # This is based on, and compatible with, InterfaceClass.
- # (The two must be mutually comparable to be able to work in e.g., BTrees.)
- # Instances of this class generally don't have a __module__ other than
- # `zope.interface.declarations`, whereas they *do* have a __name__ that is the
- # fully qualified name of the object they are representing.
- # Note, though, that equality and hashing are still identity based. This
- # accounts for things like nested objects that have the same name (typically
- # only in tests) and is consistent with pickling. As far as comparisons to InterfaceClass
- # goes, we'll never have equal name and module to those, so we're still consistent there.
- # Instances of this class are essentially intended to be unique and are
- # heavily cached (note how our __reduce__ handles this) so having identity
- # based hash and eq should also work.
- if other is None:
- return -1
- n1 = (self.__name__, self.__module__)
- n2 = (getattr(other, '__name__', ''), getattr(other, '__module__', ''))
- # This spelling works under Python3, which doesn't have cmp().
- return (n1 > n2) - (n1 < n2)
- def __hash__(self):
- return Declaration.__hash__(self)
- # We want equality to be based on identity. However, we can't actually
- # implement __eq__/__ne__ to do this because sometimes we get wrapped in a proxy.
- # We need to let the proxy types implement these methods so they can handle unwrapping
- # and then rely on: (1) the interpreter automatically changing `implements == proxy` into
- # `proxy == implements` (which will call proxy.__eq__ to do the unwrapping) and then
- # (2) the default equality semantics being identity based.
- def __lt__(self, other):
- c = self.__cmp(other)
- return c < 0
- def __le__(self, other):
- c = self.__cmp(other)
- return c <= 0
- def __gt__(self, other):
- c = self.__cmp(other)
- return c > 0
- def __ge__(self, other):
- c = self.__cmp(other)
- return c >= 0
- def _implements_name(ob):
- # Return the __name__ attribute to be used by its __implemented__
- # property.
- # This must be stable for the "same" object across processes
- # because it is used for sorting. It needn't be unique, though, in cases
- # like nested classes named Foo created by different functions, because
- # equality and hashing is still based on identity.
- # It might be nice to use __qualname__ on Python 3, but that would produce
- # different values between Py2 and Py3.
- return (getattr(ob, '__module__', '?') or '?') + \
- '.' + (getattr(ob, '__name__', '?') or '?')
- def implementedByFallback(cls):
- """Return the interfaces implemented for a class' instances
- The value returned is an IDeclaration.
- """
- try:
- spec = cls.__dict__.get('__implemented__')
- except AttributeError:
- # we can't get the class dict. This is probably due to a
- # security proxy. If this is the case, then probably no
- # descriptor was installed for the class.
- # We don't want to depend directly on zope.security in
- # zope.interface, but we'll try to make reasonable
- # accommodations in an indirect way.
- # We'll check to see if there's an implements:
- spec = getattr(cls, '__implemented__', None)
- if spec is None:
- # There's no spec stred in the class. Maybe its a builtin:
- spec = BuiltinImplementationSpecifications.get(cls)
- if spec is not None:
- return spec
- return _empty
- if spec.__class__ == Implements:
- # we defaulted to _empty or there was a spec. Good enough.
- # Return it.
- return spec
- # TODO: need old style __implements__ compatibility?
- # Hm, there's an __implemented__, but it's not a spec. Must be
- # an old-style declaration. Just compute a spec for it
- return Declaration(*_normalizeargs((spec, )))
- if isinstance(spec, Implements):
- return spec
- if spec is None:
- spec = BuiltinImplementationSpecifications.get(cls)
- if spec is not None:
- return spec
- # TODO: need old style __implements__ compatibility?
- spec_name = _implements_name(cls)
- if spec is not None:
- # old-style __implemented__ = foo declaration
- spec = (spec, ) # tuplefy, as it might be just an int
- spec = Implements.named(spec_name, *_normalizeargs(spec))
- spec.inherit = None # old-style implies no inherit
- del cls.__implemented__ # get rid of the old-style declaration
- else:
- try:
- bases = cls.__bases__
- except AttributeError:
- if not callable(cls):
- raise TypeError("ImplementedBy called for non-factory", cls)
- bases = ()
- spec = Implements.named(spec_name, *[implementedBy(c) for c in bases])
- spec.inherit = cls
- try:
- cls.__implemented__ = spec
- if not hasattr(cls, '__providedBy__'):
- cls.__providedBy__ = objectSpecificationDescriptor
- if (isinstance(cls, DescriptorAwareMetaClasses)
- and
- '__provides__' not in cls.__dict__):
- # Make sure we get a __provides__ descriptor
- cls.__provides__ = ClassProvides(
- cls,
- getattr(cls, '__class__', type(cls)),
- )
- except TypeError:
- if not isinstance(cls, type):
- raise TypeError("ImplementedBy called for non-type", cls)
- BuiltinImplementationSpecifications[cls] = spec
- return spec
- implementedBy = implementedByFallback
- def classImplementsOnly(cls, *interfaces):
- """Declare the only interfaces implemented by instances of a class
- The arguments after the class are one or more interfaces or interface
- specifications (``IDeclaration`` objects).
- The interfaces given (including the interfaces in the specifications)
- replace any previous declarations.
- """
- spec = implementedBy(cls)
- spec.declared = ()
- spec.inherit = None
- classImplements(cls, *interfaces)
- def classImplements(cls, *interfaces):
- """Declare additional interfaces implemented for instances of a class
- The arguments after the class are one or more interfaces or
- interface specifications (``IDeclaration`` objects).
- The interfaces given (including the interfaces in the specifications)
- are added to any interfaces previously declared.
- """
- spec = implementedBy(cls)
- spec.declared += tuple(_normalizeargs(interfaces))
- # compute the bases
- bases = []
- seen = {}
- for b in spec.declared:
- if b not in seen:
- seen[b] = 1
- bases.append(b)
- if spec.inherit is not None:
- for c in spec.inherit.__bases__:
- b = implementedBy(c)
- if b not in seen:
- seen[b] = 1
- bases.append(b)
- spec.__bases__ = tuple(bases)
- def _implements_advice(cls):
- interfaces, classImplements = cls.__dict__['__implements_advice_data__']
- del cls.__implements_advice_data__
- classImplements(cls, *interfaces)
- return cls
- class implementer:
- """Declare the interfaces implemented by instances of a class.
- This function is called as a class decorator.
- The arguments are one or more interfaces or interface
- specifications (IDeclaration objects).
- The interfaces given (including the interfaces in the
- specifications) are added to any interfaces previously
- declared.
- Previous declarations include declarations for base classes
- unless implementsOnly was used.
- This function is provided for convenience. It provides a more
- convenient way to call classImplements. For example::
- @implementer(I1)
- class C(object):
- pass
- is equivalent to calling::
- classImplements(C, I1)
- after the class has been created.
- """
- def __init__(self, *interfaces):
- self.interfaces = interfaces
- def __call__(self, ob):
- if isinstance(ob, DescriptorAwareMetaClasses):
- classImplements(ob, *self.interfaces)
- return ob
- spec_name = _implements_name(ob)
- spec = Implements.named(spec_name, *self.interfaces)
- try:
- ob.__implemented__ = spec
- except AttributeError:
- raise TypeError("Can't declare implements", ob)
- return ob
- class implementer_only:
- """Declare the only interfaces implemented by instances of a class
- This function is called as a class decorator.
- The arguments are one or more interfaces or interface
- specifications (IDeclaration objects).
- Previous declarations including declarations for base classes
- are overridden.
- This function is provided for convenience. It provides a more
- convenient way to call classImplementsOnly. For example::
- @implementer_only(I1)
- class C(object): pass
- is equivalent to calling::
- classImplementsOnly(I1)
- after the class has been created.
- """
- def __init__(self, *interfaces):
- self.interfaces = interfaces
- def __call__(self, ob):
- if isinstance(ob, (FunctionType, MethodType)):
- # XXX Does this decorator make sense for anything but classes?
- # I don't think so. There can be no inheritance of interfaces
- # on a method pr function....
- raise ValueError('The implementer_only decorator is not '
- 'supported for methods or functions.')
- else:
- # Assume it's a class:
- classImplementsOnly(ob, *self.interfaces)
- return ob
- def _implements(name, interfaces, classImplements):
- # This entire approach is invalid under Py3K. Don't even try to fix
- # the coverage for this block there. :(
- frame = sys._getframe(2)
- locals = frame.f_locals
- # Try to make sure we were called from a class def. In 2.2.0 we can't
- # check for __module__ since it doesn't seem to be added to the locals
- # until later on.
- if locals is frame.f_globals or '__module__' not in locals:
- raise TypeError(name+" can be used only from a class definition.")
- if '__implements_advice_data__' in locals:
- raise TypeError(name+" can be used only once in a class definition.")
- locals['__implements_advice_data__'] = interfaces, classImplements
- addClassAdvisor(_implements_advice, depth=3)
- def implements(*interfaces):
- """Declare interfaces implemented by instances of a class
- This function is called in a class definition.
- The arguments are one or more interfaces or interface
- specifications (IDeclaration objects).
- The interfaces given (including the interfaces in the
- specifications) are added to any interfaces previously
- declared.
- Previous declarations include declarations for base classes
- unless implementsOnly was used.
- This function is provided for convenience. It provides a more
- convenient way to call classImplements. For example::
- implements(I1)
- is equivalent to calling::
- classImplements(C, I1)
- after the class has been created.
- """
- # This entire approach is invalid under Py3K. Don't even try to fix
- # the coverage for this block there. :(
- if PYTHON3:
- raise TypeError(_ADVICE_ERROR % 'implementer')
- _implements("implements", interfaces, classImplements)
- def implementsOnly(*interfaces):
- """Declare the only interfaces implemented by instances of a class
- This function is called in a class definition.
- The arguments are one or more interfaces or interface
- specifications (IDeclaration objects).
- Previous declarations including declarations for base classes
- are overridden.
- This function is provided for convenience. It provides a more
- convenient way to call classImplementsOnly. For example::
- implementsOnly(I1)
- is equivalent to calling::
- classImplementsOnly(I1)
- after the class has been created.
- """
- # This entire approach is invalid under Py3K. Don't even try to fix
- # the coverage for this block there. :(
- if PYTHON3:
- raise TypeError(_ADVICE_ERROR % 'implementer_only')
- _implements("implementsOnly", interfaces, classImplementsOnly)
- ##############################################################################
- #
- # Instance declarations
- class Provides(Declaration): # Really named ProvidesClass
- """Implement __provides__, the instance-specific specification
- When an object is pickled, we pickle the interfaces that it implements.
- """
- def __init__(self, cls, *interfaces):
- self.__args = (cls, ) + interfaces
- self._cls = cls
- Declaration.__init__(self, *(interfaces + (implementedBy(cls), )))
- def __reduce__(self):
- return Provides, self.__args
- __module__ = 'zope.interface'
- def __get__(self, inst, cls):
- """Make sure that a class __provides__ doesn't leak to an instance
- """
- if inst is None and cls is self._cls:
- # We were accessed through a class, so we are the class'
- # provides spec. Just return this object, but only if we are
- # being called on the same class that we were defined for:
- return self
- raise AttributeError('__provides__')
- ProvidesClass = Provides
- # Registry of instance declarations
- # This is a memory optimization to allow objects to share specifications.
- InstanceDeclarations = weakref.WeakValueDictionary()
- def Provides(*interfaces):
- """Cache instance declarations
- Instance declarations are shared among instances that have the same
- declaration. The declarations are cached in a weak value dictionary.
- """
- spec = InstanceDeclarations.get(interfaces)
- if spec is None:
- spec = ProvidesClass(*interfaces)
- InstanceDeclarations[interfaces] = spec
- return spec
- Provides.__safe_for_unpickling__ = True
- def directlyProvides(object, *interfaces):
- """Declare interfaces declared directly for an object
- The arguments after the object are one or more interfaces or interface
- specifications (``IDeclaration`` objects).
- The interfaces given (including the interfaces in the specifications)
- replace interfaces previously declared for the object.
- """
- cls = getattr(object, '__class__', None)
- if cls is not None and getattr(cls, '__class__', None) is cls:
- # It's a meta class (well, at least it it could be an extension class)
- # Note that we can't get here from Py3k tests: there is no normal
- # class which isn't descriptor aware.
- if not isinstance(object,
- DescriptorAwareMetaClasses):
- raise TypeError("Attempt to make an interface declaration on a "
- "non-descriptor-aware class")
- interfaces = _normalizeargs(interfaces)
- if cls is None:
- cls = type(object)
- issub = False
- for damc in DescriptorAwareMetaClasses:
- if issubclass(cls, damc):
- issub = True
- break
- if issub:
- # we have a class or type. We'll use a special descriptor
- # that provides some extra caching
- object.__provides__ = ClassProvides(object, cls, *interfaces)
- else:
- object.__provides__ = Provides(cls, *interfaces)
- def alsoProvides(object, *interfaces):
- """Declare interfaces declared directly for an object
- The arguments after the object are one or more interfaces or interface
- specifications (``IDeclaration`` objects).
- The interfaces given (including the interfaces in the specifications) are
- added to the interfaces previously declared for the object.
- """
- directlyProvides(object, directlyProvidedBy(object), *interfaces)
- def noLongerProvides(object, interface):
- """ Removes a directly provided interface from an object.
- """
- directlyProvides(object, directlyProvidedBy(object) - interface)
- if interface.providedBy(object):
- raise ValueError("Can only remove directly provided interfaces.")
- class ClassProvidesBaseFallback(object):
- def __get__(self, inst, cls):
- if cls is self._cls:
- # We only work if called on the class we were defined for
- if inst is None:
- # We were accessed through a class, so we are the class'
- # provides spec. Just return this object as is:
- return self
- return self._implements
- raise AttributeError('__provides__')
- ClassProvidesBasePy = ClassProvidesBaseFallback # BBB
- ClassProvidesBase = ClassProvidesBaseFallback
- # Try to get C base:
- try:
- import zope.interface._zope_interface_coptimizations
- except ImportError:
- pass
- else:
- from zope.interface._zope_interface_coptimizations import ClassProvidesBase
- class ClassProvides(Declaration, ClassProvidesBase):
- """Special descriptor for class __provides__
- The descriptor caches the implementedBy info, so that
- we can get declarations for objects without instance-specific
- interfaces a bit quicker.
- """
- def __init__(self, cls, metacls, *interfaces):
- self._cls = cls
- self._implements = implementedBy(cls)
- self.__args = (cls, metacls, ) + interfaces
- Declaration.__init__(self, *(interfaces + (implementedBy(metacls), )))
- def __reduce__(self):
- return self.__class__, self.__args
- # Copy base-class method for speed
- __get__ = ClassProvidesBase.__get__
- def directlyProvidedBy(object):
- """Return the interfaces directly provided by the given object
- The value returned is an ``IDeclaration``.
- """
- provides = getattr(object, "__provides__", None)
- if (provides is None # no spec
- or
- # We might have gotten the implements spec, as an
- # optimization. If so, it's like having only one base, that we
- # lop off to exclude class-supplied declarations:
- isinstance(provides, Implements)
- ):
- return _empty
- # Strip off the class part of the spec:
- return Declaration(provides.__bases__[:-1])
- def classProvides(*interfaces):
- """Declare interfaces provided directly by a class
- This function is called in a class definition.
- The arguments are one or more interfaces or interface specifications
- (``IDeclaration`` objects).
- The given interfaces (including the interfaces in the specifications)
- are used to create the class's direct-object interface specification.
- An error will be raised if the module class has an direct interface
- specification. In other words, it is an error to call this function more
- than once in a class definition.
- Note that the given interfaces have nothing to do with the interfaces
- implemented by instances of the class.
- This function is provided for convenience. It provides a more convenient
- way to call directlyProvides for a class. For example::
- classProvides(I1)
- is equivalent to calling::
- directlyProvides(theclass, I1)
- after the class has been created.
- """
- # This entire approach is invalid under Py3K. Don't even try to fix
- # the coverage for this block there. :(
- if PYTHON3:
- raise TypeError(_ADVICE_ERROR % 'provider')
- frame = sys._getframe(1)
- locals = frame.f_locals
- # Try to make sure we were called from a class def
- if (locals is frame.f_globals) or ('__module__' not in locals):
- raise TypeError("classProvides can be used only from a "
- "class definition.")
- if '__provides__' in locals:
- raise TypeError(
- "classProvides can only be used once in a class definition.")
- locals["__provides__"] = _normalizeargs(interfaces)
- addClassAdvisor(_classProvides_advice, depth=2)
- def _classProvides_advice(cls):
- # This entire approach is invalid under Py3K. Don't even try to fix
- # the coverage for this block there. :(
- interfaces = cls.__dict__['__provides__']
- del cls.__provides__
- directlyProvides(cls, *interfaces)
- return cls
- class provider:
- """Class decorator version of classProvides"""
- def __init__(self, *interfaces):
- self.interfaces = interfaces
- def __call__(self, ob):
- directlyProvides(ob, *self.interfaces)
- return ob
- def moduleProvides(*interfaces):
- """Declare interfaces provided by a module
- This function is used in a module definition.
- The arguments are one or more interfaces or interface specifications
- (``IDeclaration`` objects).
- The given interfaces (including the interfaces in the specifications) are
- used to create the module's direct-object interface specification. An
- error will be raised if the module already has an interface specification.
- In other words, it is an error to call this function more than once in a
- module definition.
- This function is provided for convenience. It provides a more convenient
- way to call directlyProvides. For example::
- moduleImplements(I1)
- is equivalent to::
- directlyProvides(sys.modules[__name__], I1)
- """
- frame = sys._getframe(1)
- locals = frame.f_locals
- # Try to make sure we were called from a class def
- if (locals is not frame.f_globals) or ('__name__' not in locals):
- raise TypeError(
- "moduleProvides can only be used from a module definition.")
- if '__provides__' in locals:
- raise TypeError(
- "moduleProvides can only be used once in a module definition.")
- locals["__provides__"] = Provides(ModuleType,
- *_normalizeargs(interfaces))
- ##############################################################################
- #
- # Declaration querying support
- # XXX: is this a fossil? Nobody calls it, no unit tests exercise it, no
- # doctests import it, and the package __init__ doesn't import it.
- def ObjectSpecification(direct, cls):
- """Provide object specifications
- These combine information for the object and for it's classes.
- """
- return Provides(cls, direct) # pragma: no cover fossil
- def getObjectSpecificationFallback(ob):
- provides = getattr(ob, '__provides__', None)
- if provides is not None:
- if isinstance(provides, SpecificationBase):
- return provides
- try:
- cls = ob.__class__
- except AttributeError:
- # We can't get the class, so just consider provides
- return _empty
- return implementedBy(cls)
- getObjectSpecification = getObjectSpecificationFallback
- def providedByFallback(ob):
- # Here we have either a special object, an old-style declaration
- # or a descriptor
- # Try to get __providedBy__
- try:
- r = ob.__providedBy__
- except AttributeError:
- # Not set yet. Fall back to lower-level thing that computes it
- return getObjectSpecification(ob)
- try:
- # We might have gotten a descriptor from an instance of a
- # class (like an ExtensionClass) that doesn't support
- # descriptors. We'll make sure we got one by trying to get
- # the only attribute, which all specs have.
- r.extends
- except AttributeError:
- # The object's class doesn't understand descriptors.
- # Sigh. We need to get an object descriptor, but we have to be
- # careful. We want to use the instance's __provides__, if
- # there is one, but only if it didn't come from the class.
- try:
- r = ob.__provides__
- except AttributeError:
- # No __provides__, so just fall back to implementedBy
- return implementedBy(ob.__class__)
- # We need to make sure we got the __provides__ from the
- # instance. We'll do this by making sure we don't get the same
- # thing from the class:
- try:
- cp = ob.__class__.__provides__
- except AttributeError:
- # The ob doesn't have a class or the class has no
- # provides, assume we're done:
- return r
- if r is cp:
- # Oops, we got the provides from the class. This means
- # the object doesn't have it's own. We should use implementedBy
- return implementedBy(ob.__class__)
- return r
- providedBy = providedByFallback
- class ObjectSpecificationDescriptorFallback(object):
- """Implement the `__providedBy__` attribute
- The `__providedBy__` attribute computes the interfaces peovided by
- an object.
- """
- def __get__(self, inst, cls):
- """Get an object specification for an object
- """
- if inst is None:
- return getObjectSpecification(cls)
- provides = getattr(inst, '__provides__', None)
- if provides is not None:
- return provides
- return implementedBy(cls)
- ObjectSpecificationDescriptor = ObjectSpecificationDescriptorFallback
- ##############################################################################
- def _normalizeargs(sequence, output = None):
- """Normalize declaration arguments
- Normalization arguments might contain Declarions, tuples, or single
- interfaces.
- Anything but individial interfaces or implements specs will be expanded.
- """
- if output is None:
- output = []
- cls = sequence.__class__
- if InterfaceClass in cls.__mro__ or Implements in cls.__mro__:
- output.append(sequence)
- else:
- for v in sequence:
- _normalizeargs(v, output)
- return output
- _empty = Declaration()
- try:
- import zope.interface._zope_interface_coptimizations
- except ImportError:
- pass
- else:
- from zope.interface._zope_interface_coptimizations import implementedBy
- from zope.interface._zope_interface_coptimizations import providedBy
- from zope.interface._zope_interface_coptimizations import (
- getObjectSpecification)
- from zope.interface._zope_interface_coptimizations import (
- ObjectSpecificationDescriptor)
- objectSpecificationDescriptor = ObjectSpecificationDescriptor()
|