Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

edgify / zope.interface   python

Repository URL to install this package:

Version: 5.1.0 

/ interface / interface.py

##############################################################################
#
# 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 ...