##############################################################################
#
# Copyright (c) 2001, 2002 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.
#
##############################################################################
"""Interface object implementation
"""
# pylint:disable=protected-access
import sys
from types import MethodType
from types import FunctionType
import weakref
from zope.interface._compat import _use_c_impl
from zope.interface._compat import PYTHON2 as PY2
from zope.interface.exceptions import Invalid
from zope.interface.ro import ro as calculate_ro
from zope.interface import ro
__all__ = [
# Most of the public API from this module is directly exported
# from zope.interface. The only remaining public API intended to
# be imported from here should be those few things documented as
# such.
'InterfaceClass',
'Specification',
'adapter_hooks',
]
CO_VARARGS = 4
CO_VARKEYWORDS = 8
# Put in the attrs dict of an interface by ``taggedValue`` and ``invariants``
TAGGED_DATA = '__interface_tagged_values__'
# Put in the attrs dict of an interface by ``interfacemethod``
INTERFACE_METHODS = '__interface_methods__'
_decorator_non_return = object()
_marker = object()
def invariant(call):
f_locals = sys._getframe(1).f_locals
tags = f_locals.setdefault(TAGGED_DATA, {})
invariants = tags.setdefault('invariants', [])
invariants.append(call)
return _decorator_non_return
def taggedValue(key, value):
"""Attaches a tagged value to an interface at definition time."""
f_locals = sys._getframe(1).f_locals
tagged_values = f_locals.setdefault(TAGGED_DATA, {})
tagged_values[key] = value
return _decorator_non_return
class Element(object):
"""
Default implementation of `zope.interface.interfaces.IElement`.
"""
# We can't say this yet because we don't have enough
# infrastructure in place.
#
#implements(IElement)
def __init__(self, __name__, __doc__=''): # pylint:disable=redefined-builtin
if not __doc__ and __name__.find(' ') >= 0:
__doc__ = __name__
__name__ = None
self.__name__ = __name__
self.__doc__ = __doc__
# Tagged values are rare, especially on methods or attributes.
# Deferring the allocation can save substantial memory.
self.__tagged_values = None
def getName(self):
""" Returns the name of the object. """
return self.__name__
def getDoc(self):
""" Returns the documentation for the object. """
return self.__doc__
###
# Tagged values.
#
# Direct tagged values are set only in this instance. Others
# may be inherited (for those subclasses that have that concept).
###
def getTaggedValue(self, tag):
""" Returns the value associated with 'tag'. """
if not self.__tagged_values:
raise KeyError(tag)
return self.__tagged_values[tag]
def queryTaggedValue(self, tag, default=None):
""" Returns the value associated with 'tag'. """
return self.__tagged_values.get(tag, default) if self.__tagged_values else default
def getTaggedValueTags(self):
""" Returns a collection of all tags. """
return self.__tagged_values.keys() if self.__tagged_values else ()
def setTaggedValue(self, tag, value):
""" Associates 'value' with 'key'. """
if self.__tagged_values is None:
self.__tagged_values = {}
self.__tagged_values[tag] = value
queryDirectTaggedValue = queryTaggedValue
getDirectTaggedValue = getTaggedValue
getDirectTaggedValueTags = getTaggedValueTags
SpecificationBasePy = object # filled by _use_c_impl.
@_use_c_impl
class SpecificationBase(object):
# This object is the base of the inheritance hierarchy for ClassProvides:
#
# ClassProvides < ClassProvidesBase, Declaration
# Declaration < Specification < SpecificationBase
# ClassProvidesBase < SpecificationBase
#
# In order to have compatible instance layouts, we need to declare
# the storage used by Specification and Declaration here (and
# those classes must have ``__slots__ = ()``); fortunately this is
# not a waste of space because those are the only two inheritance
# trees. These all translate into tp_members in C.
__slots__ = (
# Things used here.
'_implied',
# Things used in Specification.
'_dependents',
'_bases',
'_v_attrs',
'__iro__',
'__sro__',
'__weakref__',
)
def providedBy(self, ob):
"""Is the interface implemented by an object
"""
spec = providedBy(ob)
return self in spec._implied
def implementedBy(self, cls):
"""Test whether the specification is implemented by a class or factory.
Raise TypeError if argument is neither a class nor a callable.
"""
spec = implementedBy(cls)
return self in spec._implied
def isOrExtends(self, interface):
"""Is the interface the same as or extend the given interface
"""
return interface in self._implied # pylint:disable=no-member
__call__ = isOrExtends
class NameAndModuleComparisonMixin(object):
# Internal use. Implement the basic sorting operators (but not (in)equality
# or hashing). Subclasses must provide ``__name__`` and ``__module__``
# attributes. Subclasses will be mutually comparable; but because equality
# and hashing semantics are missing from this class, take care in how
# you define those two attributes: If you stick with the default equality
# and hashing (identity based) you should make sure that all possible ``__name__``
# and ``__module__`` pairs are unique ACROSS ALL SUBCLASSES. (Actually, pretty
# much the same thing goes if you define equality and hashing to be based on
# those two attributes: they must still be consistent ACROSS ALL SUBCLASSES.)
# pylint:disable=assigning-non-slot
__slots__ = ()
def _compare(self, other):
"""
Compare *self* to *other* based on ``__name__`` and ``__module__``.
Return 0 if they are equal, return 1 if *self* is
greater than *other*, and return -1 if *self* is less than
*other*.
If *other* does not have ``__name__`` or ``__module__``, then
return ``NotImplemented``.
.. caution::
This allows comparison to things well outside the type hierarchy,
perhaps not symmetrically.
For example, ``class Foo(object)`` and ``class Foo(Interface)``
in the same file would compare equal, depending on the order of
operands. Writing code like this by hand would be unusual, but it could
happen with dynamic creation of types and interfaces.
None is treated as a pseudo interface that implies the loosest
contact possible, no contract. For that reason, all interfaces
sort before None.
"""
if other is self:
return 0
if other is None:
return -1
n1 = (self.__name__, self.__module__)
try:
n2 = (other.__name__, other.__module__)
except AttributeError:
return NotImplemented
# This spelling works under Python3, which doesn't have cmp().
return (n1 > n2) - (n1 < n2)
def __lt__(self, other):
c = self._compare(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self._compare(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self._compare(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self._compare(other)
if c is NotImplemented:
return c
return c >= 0
@_use_c_impl
class InterfaceBase(NameAndModuleComparisonMixin, SpecificationBasePy):
"""Base class that wants to be replaced with a C base :)
"""
__slots__ = (
'__name__',
'__ibmodule__',
'_v_cached_hash',
)
def __init__(self, name=None, module=None):
self.__name__ = name
self.__ibmodule__ = module
def _call_conform(self, conform):
raise NotImplementedError
@property
def __module_property__(self):
# This is for _InterfaceMetaClass
return self.__ibmodule__
def __call__(self, obj, alternate=_marker):
"""Adapt an object to the interface
"""
try:
conform = obj.__conform__
except AttributeError:
conform = None
if conform is not None:
adapter = self._call_conform(conform)
if adapter is not None:
return adapter
adapter = self.__adapt__(obj)
if adapter is not None:
return adapter
if alternate is not _marker:
return alternate
raise TypeError("Could not adapt", obj, self)
def __adapt__(self, obj):
"""Adapt an object to the receiver
"""
if self.providedBy(obj):
return obj
for hook in adapter_hooks:
adapter = hook(self, obj)
if adapter is not None:
return adapter
return None
def __hash__(self):
# pylint:disable=assigning-non-slot,attribute-defined-outside-init
try:
return self._v_cached_hash
except AttributeError:
self._v_cached_hash = hash((self.__name__, self.__module__))
return self._v_cached_hash
def __eq__(self, other):
c = self._compare(other)
if c is NotImplemented:
return c
return c == 0
def __ne__(self, other):
if other is self:
return False
c = self._compare(other)
if c is NotImplemented:
return c
return c != 0
adapter_hooks = _use_c_impl([], 'adapter_hooks')
class Specification(SpecificationBase):
"""Specifications
An interface specification is used to track interface declarations
and component registrations.
This class is a base class for both interfaces themselves and for
interface specifications (declarations).
Loading ...