added forced package imports
This commit is contained in:
parent
0e2ffdbbb1
commit
ef9022c6eb
943 changed files with 125530 additions and 16 deletions
90
lib/zope/interface/__init__.py
Normal file
90
lib/zope/interface/__init__.py
Normal file
|
@ -0,0 +1,90 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Interfaces
|
||||
|
||||
This package implements the Python "scarecrow" proposal.
|
||||
|
||||
The package exports two objects, `Interface` and `Attribute` directly. It also
|
||||
exports several helper methods. Interface is used to create an interface with
|
||||
a class statement, as in:
|
||||
|
||||
class IMyInterface(Interface):
|
||||
'''Interface documentation
|
||||
'''
|
||||
|
||||
def meth(arg1, arg2):
|
||||
'''Documentation for meth
|
||||
'''
|
||||
|
||||
# Note that there is no self argument
|
||||
|
||||
To find out what you can do with interfaces, see the interface
|
||||
interface, `IInterface` in the `interfaces` module.
|
||||
|
||||
The package has several public modules:
|
||||
|
||||
o `declarations` provides utilities to declare interfaces on objects. It
|
||||
also provides a wide range of helpful utilities that aid in managing
|
||||
declared interfaces. Most of its public names are however imported here.
|
||||
|
||||
o `document` has a utility for documenting an interface as structured text.
|
||||
|
||||
o `exceptions` has the interface-defined exceptions
|
||||
|
||||
o `interfaces` contains a list of all public interfaces for this package.
|
||||
|
||||
o `verify` has utilities for verifying implementations of interfaces.
|
||||
|
||||
See the module doc strings for more information.
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
from zope.interface.interface import Interface
|
||||
from zope.interface.interface import _wire
|
||||
|
||||
# Need to actually get the interface elements to implement the right interfaces
|
||||
_wire()
|
||||
del _wire
|
||||
|
||||
from zope.interface.declarations import Declaration
|
||||
from zope.interface.declarations import alsoProvides
|
||||
from zope.interface.declarations import classImplements
|
||||
from zope.interface.declarations import classImplementsOnly
|
||||
from zope.interface.declarations import classProvides
|
||||
from zope.interface.declarations import directlyProvidedBy
|
||||
from zope.interface.declarations import directlyProvides
|
||||
from zope.interface.declarations import implementedBy
|
||||
from zope.interface.declarations import implementer
|
||||
from zope.interface.declarations import implementer_only
|
||||
from zope.interface.declarations import implements
|
||||
from zope.interface.declarations import implementsOnly
|
||||
from zope.interface.declarations import moduleProvides
|
||||
from zope.interface.declarations import named
|
||||
from zope.interface.declarations import noLongerProvides
|
||||
from zope.interface.declarations import providedBy
|
||||
from zope.interface.declarations import provider
|
||||
from zope.interface.exceptions import Invalid
|
||||
from zope.interface.interface import Attribute
|
||||
from zope.interface.interface import invariant
|
||||
from zope.interface.interface import taggedValue
|
||||
|
||||
# The following are to make spec pickles cleaner
|
||||
from zope.interface.declarations import Provides
|
||||
|
||||
|
||||
from zope.interface.interfaces import IInterfaceDeclaration
|
||||
|
||||
moduleProvides(IInterfaceDeclaration)
|
||||
|
||||
__all__ = ('Interface', 'Attribute') + tuple(IInterfaceDeclaration)
|
58
lib/zope/interface/_compat.py
Normal file
58
lib/zope/interface/_compat.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Basic components support
|
||||
"""
|
||||
import sys
|
||||
import types
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
|
||||
def _normalize_name(name):
|
||||
if isinstance(name, basestring):
|
||||
return unicode(name)
|
||||
raise TypeError("name must be a regular or unicode string")
|
||||
|
||||
CLASS_TYPES = (type, types.ClassType)
|
||||
STRING_TYPES = (basestring,)
|
||||
|
||||
_BUILTINS = '__builtin__'
|
||||
|
||||
PYTHON3 = False
|
||||
PYTHON2 = True
|
||||
|
||||
else:
|
||||
|
||||
def _normalize_name(name):
|
||||
if isinstance(name, bytes):
|
||||
name = str(name, 'ascii')
|
||||
if isinstance(name, str):
|
||||
return name
|
||||
raise TypeError("name must be a string or ASCII-only bytes")
|
||||
|
||||
CLASS_TYPES = (type,)
|
||||
STRING_TYPES = (str,)
|
||||
|
||||
_BUILTINS = 'builtins'
|
||||
|
||||
PYTHON3 = True
|
||||
PYTHON2 = False
|
||||
|
||||
def _skip_under_py3k(test_method):
|
||||
import unittest
|
||||
return unittest.skipIf(sys.version_info[0] >= 3, "Only on Python 2")(test_method)
|
||||
|
||||
|
||||
def _skip_under_py2(test_method):
|
||||
import unittest
|
||||
return unittest.skipIf(sys.version_info[0] < 3, "Only on Python 3")(test_method)
|
35
lib/zope/interface/_flatten.py
Normal file
35
lib/zope/interface/_flatten.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Adapter-style interface registry
|
||||
|
||||
See Adapter class.
|
||||
"""
|
||||
from zope.interface import Declaration
|
||||
|
||||
def _flatten(implements, include_None=0):
|
||||
|
||||
try:
|
||||
r = implements.flattened()
|
||||
except AttributeError:
|
||||
if implements is None:
|
||||
r=()
|
||||
else:
|
||||
r = Declaration(implements).flattened()
|
||||
|
||||
if not include_None:
|
||||
return r
|
||||
|
||||
r = list(r)
|
||||
r.append(None)
|
||||
return r
|
1726
lib/zope/interface/_zope_interface_coptimizations.c
Normal file
1726
lib/zope/interface/_zope_interface_coptimizations.c
Normal file
File diff suppressed because it is too large
Load diff
BIN
lib/zope/interface/_zope_interface_coptimizations.cp37-win32.pyd
Normal file
BIN
lib/zope/interface/_zope_interface_coptimizations.cp37-win32.pyd
Normal file
Binary file not shown.
712
lib/zope/interface/adapter.py
Normal file
712
lib/zope/interface/adapter.py
Normal file
|
@ -0,0 +1,712 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Adapter management
|
||||
"""
|
||||
import weakref
|
||||
|
||||
from zope.interface import implementer
|
||||
from zope.interface import providedBy
|
||||
from zope.interface import Interface
|
||||
from zope.interface import ro
|
||||
from zope.interface.interfaces import IAdapterRegistry
|
||||
|
||||
from zope.interface._compat import _normalize_name
|
||||
from zope.interface._compat import STRING_TYPES
|
||||
|
||||
_BLANK = u''
|
||||
|
||||
class BaseAdapterRegistry(object):
|
||||
|
||||
# List of methods copied from lookup sub-objects:
|
||||
_delegated = ('lookup', 'queryMultiAdapter', 'lookup1', 'queryAdapter',
|
||||
'adapter_hook', 'lookupAll', 'names',
|
||||
'subscriptions', 'subscribers')
|
||||
|
||||
# All registries maintain a generation that can be used by verifying
|
||||
# registries
|
||||
_generation = 0
|
||||
|
||||
def __init__(self, bases=()):
|
||||
|
||||
# The comments here could be improved. Possibly this bit needs
|
||||
# explaining in a separate document, as the comments here can
|
||||
# be quite confusing. /regebro
|
||||
|
||||
# {order -> {required -> {provided -> {name -> value}}}}
|
||||
# Here "order" is actually an index in a list, "required" and
|
||||
# "provided" are interfaces, and "required" is really a nested
|
||||
# key. So, for example:
|
||||
# for order == 0 (that is, self._adapters[0]), we have:
|
||||
# {provided -> {name -> value}}
|
||||
# but for order == 2 (that is, self._adapters[2]), we have:
|
||||
# {r1 -> {r2 -> {provided -> {name -> value}}}}
|
||||
#
|
||||
self._adapters = []
|
||||
|
||||
# {order -> {required -> {provided -> {name -> [value]}}}}
|
||||
# where the remarks about adapters above apply
|
||||
self._subscribers = []
|
||||
|
||||
# Set, with a reference count, keeping track of the interfaces
|
||||
# for which we have provided components:
|
||||
self._provided = {}
|
||||
|
||||
# Create ``_v_lookup`` object to perform lookup. We make this a
|
||||
# separate object to to make it easier to implement just the
|
||||
# lookup functionality in C. This object keeps track of cache
|
||||
# invalidation data in two kinds of registries.
|
||||
|
||||
# Invalidating registries have caches that are invalidated
|
||||
# when they or their base registies change. An invalidating
|
||||
# registry can only have invalidating registries as bases.
|
||||
# See LookupBaseFallback below for the pertinent logic.
|
||||
|
||||
# Verifying registies can't rely on getting invalidation messages,
|
||||
# so have to check the generations of base registries to determine
|
||||
# if their cache data are current. See VerifyingBasePy below
|
||||
# for the pertinent object.
|
||||
self._createLookup()
|
||||
|
||||
# Setting the bases causes the registries described above
|
||||
# to be initialized (self._setBases -> self.changed ->
|
||||
# self._v_lookup.changed).
|
||||
|
||||
self.__bases__ = bases
|
||||
|
||||
def _setBases(self, bases):
|
||||
self.__dict__['__bases__'] = bases
|
||||
self.ro = ro.ro(self)
|
||||
self.changed(self)
|
||||
|
||||
__bases__ = property(lambda self: self.__dict__['__bases__'],
|
||||
lambda self, bases: self._setBases(bases),
|
||||
)
|
||||
|
||||
def _createLookup(self):
|
||||
self._v_lookup = self.LookupClass(self)
|
||||
for name in self._delegated:
|
||||
self.__dict__[name] = getattr(self._v_lookup, name)
|
||||
|
||||
def changed(self, originally_changed):
|
||||
self._generation += 1
|
||||
self._v_lookup.changed(originally_changed)
|
||||
|
||||
def register(self, required, provided, name, value):
|
||||
if not isinstance(name, STRING_TYPES):
|
||||
raise ValueError('name is not a string')
|
||||
if value is None:
|
||||
self.unregister(required, provided, name, value)
|
||||
return
|
||||
|
||||
required = tuple(map(_convert_None_to_Interface, required))
|
||||
name = _normalize_name(name)
|
||||
order = len(required)
|
||||
byorder = self._adapters
|
||||
while len(byorder) <= order:
|
||||
byorder.append({})
|
||||
components = byorder[order]
|
||||
key = required + (provided,)
|
||||
|
||||
for k in key:
|
||||
d = components.get(k)
|
||||
if d is None:
|
||||
d = {}
|
||||
components[k] = d
|
||||
components = d
|
||||
|
||||
if components.get(name) is value:
|
||||
return
|
||||
|
||||
components[name] = value
|
||||
|
||||
n = self._provided.get(provided, 0) + 1
|
||||
self._provided[provided] = n
|
||||
if n == 1:
|
||||
self._v_lookup.add_extendor(provided)
|
||||
|
||||
self.changed(self)
|
||||
|
||||
def registered(self, required, provided, name=_BLANK):
|
||||
required = tuple(map(_convert_None_to_Interface, required))
|
||||
name = _normalize_name(name)
|
||||
order = len(required)
|
||||
byorder = self._adapters
|
||||
if len(byorder) <= order:
|
||||
return None
|
||||
|
||||
components = byorder[order]
|
||||
key = required + (provided,)
|
||||
|
||||
for k in key:
|
||||
d = components.get(k)
|
||||
if d is None:
|
||||
return None
|
||||
components = d
|
||||
|
||||
return components.get(name)
|
||||
|
||||
def unregister(self, required, provided, name, value=None):
|
||||
required = tuple(map(_convert_None_to_Interface, required))
|
||||
order = len(required)
|
||||
byorder = self._adapters
|
||||
if order >= len(byorder):
|
||||
return False
|
||||
components = byorder[order]
|
||||
key = required + (provided,)
|
||||
|
||||
# Keep track of how we got to `components`:
|
||||
lookups = []
|
||||
for k in key:
|
||||
d = components.get(k)
|
||||
if d is None:
|
||||
return
|
||||
lookups.append((components, k))
|
||||
components = d
|
||||
|
||||
old = components.get(name)
|
||||
if old is None:
|
||||
return
|
||||
if (value is not None) and (old is not value):
|
||||
return
|
||||
|
||||
del components[name]
|
||||
if not components:
|
||||
# Clean out empty containers, since we don't want our keys
|
||||
# to reference global objects (interfaces) unnecessarily.
|
||||
# This is often a problem when an interface is slated for
|
||||
# removal; a hold-over entry in the registry can make it
|
||||
# difficult to remove such interfaces.
|
||||
for comp, k in reversed(lookups):
|
||||
d = comp[k]
|
||||
if d:
|
||||
break
|
||||
else:
|
||||
del comp[k]
|
||||
while byorder and not byorder[-1]:
|
||||
del byorder[-1]
|
||||
n = self._provided[provided] - 1
|
||||
if n == 0:
|
||||
del self._provided[provided]
|
||||
self._v_lookup.remove_extendor(provided)
|
||||
else:
|
||||
self._provided[provided] = n
|
||||
|
||||
self.changed(self)
|
||||
|
||||
def subscribe(self, required, provided, value):
|
||||
required = tuple(map(_convert_None_to_Interface, required))
|
||||
name = _BLANK
|
||||
order = len(required)
|
||||
byorder = self._subscribers
|
||||
while len(byorder) <= order:
|
||||
byorder.append({})
|
||||
components = byorder[order]
|
||||
key = required + (provided,)
|
||||
|
||||
for k in key:
|
||||
d = components.get(k)
|
||||
if d is None:
|
||||
d = {}
|
||||
components[k] = d
|
||||
components = d
|
||||
|
||||
components[name] = components.get(name, ()) + (value, )
|
||||
|
||||
if provided is not None:
|
||||
n = self._provided.get(provided, 0) + 1
|
||||
self._provided[provided] = n
|
||||
if n == 1:
|
||||
self._v_lookup.add_extendor(provided)
|
||||
|
||||
self.changed(self)
|
||||
|
||||
def unsubscribe(self, required, provided, value=None):
|
||||
required = tuple(map(_convert_None_to_Interface, required))
|
||||
order = len(required)
|
||||
byorder = self._subscribers
|
||||
if order >= len(byorder):
|
||||
return
|
||||
components = byorder[order]
|
||||
key = required + (provided,)
|
||||
|
||||
# Keep track of how we got to `components`:
|
||||
lookups = []
|
||||
for k in key:
|
||||
d = components.get(k)
|
||||
if d is None:
|
||||
return
|
||||
lookups.append((components, k))
|
||||
components = d
|
||||
|
||||
old = components.get(_BLANK)
|
||||
if not old:
|
||||
# this is belt-and-suspenders against the failure of cleanup below
|
||||
return # pragma: no cover
|
||||
|
||||
if value is None:
|
||||
new = ()
|
||||
else:
|
||||
new = tuple([v for v in old if v != value])
|
||||
|
||||
if new == old:
|
||||
return
|
||||
|
||||
if new:
|
||||
components[_BLANK] = new
|
||||
else:
|
||||
# Instead of setting components[_BLANK] = new, we clean out
|
||||
# empty containers, since we don't want our keys to
|
||||
# reference global objects (interfaces) unnecessarily. This
|
||||
# is often a problem when an interface is slated for
|
||||
# removal; a hold-over entry in the registry can make it
|
||||
# difficult to remove such interfaces.
|
||||
del components[_BLANK]
|
||||
for comp, k in reversed(lookups):
|
||||
d = comp[k]
|
||||
if d:
|
||||
break
|
||||
else:
|
||||
del comp[k]
|
||||
while byorder and not byorder[-1]:
|
||||
del byorder[-1]
|
||||
|
||||
if provided is not None:
|
||||
n = self._provided[provided] + len(new) - len(old)
|
||||
if n == 0:
|
||||
del self._provided[provided]
|
||||
self._v_lookup.remove_extendor(provided)
|
||||
|
||||
self.changed(self)
|
||||
|
||||
# XXX hack to fake out twisted's use of a private api. We need to get them
|
||||
# to use the new registed method.
|
||||
def get(self, _): # pragma: no cover
|
||||
class XXXTwistedFakeOut:
|
||||
selfImplied = {}
|
||||
return XXXTwistedFakeOut
|
||||
|
||||
|
||||
_not_in_mapping = object()
|
||||
class LookupBaseFallback(object):
|
||||
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
self._mcache = {}
|
||||
self._scache = {}
|
||||
|
||||
def changed(self, ignored=None):
|
||||
self._cache.clear()
|
||||
self._mcache.clear()
|
||||
self._scache.clear()
|
||||
|
||||
def _getcache(self, provided, name):
|
||||
cache = self._cache.get(provided)
|
||||
if cache is None:
|
||||
cache = {}
|
||||
self._cache[provided] = cache
|
||||
if name:
|
||||
c = cache.get(name)
|
||||
if c is None:
|
||||
c = {}
|
||||
cache[name] = c
|
||||
cache = c
|
||||
return cache
|
||||
|
||||
def lookup(self, required, provided, name=_BLANK, default=None):
|
||||
if not isinstance(name, STRING_TYPES):
|
||||
raise ValueError('name is not a string')
|
||||
cache = self._getcache(provided, name)
|
||||
required = tuple(required)
|
||||
if len(required) == 1:
|
||||
result = cache.get(required[0], _not_in_mapping)
|
||||
else:
|
||||
result = cache.get(tuple(required), _not_in_mapping)
|
||||
|
||||
if result is _not_in_mapping:
|
||||
result = self._uncached_lookup(required, provided, name)
|
||||
if len(required) == 1:
|
||||
cache[required[0]] = result
|
||||
else:
|
||||
cache[tuple(required)] = result
|
||||
|
||||
if result is None:
|
||||
return default
|
||||
|
||||
return result
|
||||
|
||||
def lookup1(self, required, provided, name=_BLANK, default=None):
|
||||
if not isinstance(name, STRING_TYPES):
|
||||
raise ValueError('name is not a string')
|
||||
cache = self._getcache(provided, name)
|
||||
result = cache.get(required, _not_in_mapping)
|
||||
if result is _not_in_mapping:
|
||||
return self.lookup((required, ), provided, name, default)
|
||||
|
||||
if result is None:
|
||||
return default
|
||||
|
||||
return result
|
||||
|
||||
def queryAdapter(self, object, provided, name=_BLANK, default=None):
|
||||
return self.adapter_hook(provided, object, name, default)
|
||||
|
||||
def adapter_hook(self, provided, object, name=_BLANK, default=None):
|
||||
if not isinstance(name, STRING_TYPES):
|
||||
raise ValueError('name is not a string')
|
||||
required = providedBy(object)
|
||||
cache = self._getcache(provided, name)
|
||||
factory = cache.get(required, _not_in_mapping)
|
||||
if factory is _not_in_mapping:
|
||||
factory = self.lookup((required, ), provided, name)
|
||||
|
||||
if factory is not None:
|
||||
result = factory(object)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return default
|
||||
|
||||
def lookupAll(self, required, provided):
|
||||
cache = self._mcache.get(provided)
|
||||
if cache is None:
|
||||
cache = {}
|
||||
self._mcache[provided] = cache
|
||||
|
||||
required = tuple(required)
|
||||
result = cache.get(required, _not_in_mapping)
|
||||
if result is _not_in_mapping:
|
||||
result = self._uncached_lookupAll(required, provided)
|
||||
cache[required] = result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def subscriptions(self, required, provided):
|
||||
cache = self._scache.get(provided)
|
||||
if cache is None:
|
||||
cache = {}
|
||||
self._scache[provided] = cache
|
||||
|
||||
required = tuple(required)
|
||||
result = cache.get(required, _not_in_mapping)
|
||||
if result is _not_in_mapping:
|
||||
result = self._uncached_subscriptions(required, provided)
|
||||
cache[required] = result
|
||||
|
||||
return result
|
||||
|
||||
LookupBasePy = LookupBaseFallback # BBB
|
||||
|
||||
try:
|
||||
from zope.interface._zope_interface_coptimizations import LookupBase
|
||||
except ImportError:
|
||||
LookupBase = LookupBaseFallback
|
||||
|
||||
|
||||
class VerifyingBaseFallback(LookupBaseFallback):
|
||||
# Mixin for lookups against registries which "chain" upwards, and
|
||||
# whose lookups invalidate their own caches whenever a parent registry
|
||||
# bumps its own '_generation' counter. E.g., used by
|
||||
# zope.component.persistentregistry
|
||||
|
||||
def changed(self, originally_changed):
|
||||
LookupBaseFallback.changed(self, originally_changed)
|
||||
self._verify_ro = self._registry.ro[1:]
|
||||
self._verify_generations = [r._generation for r in self._verify_ro]
|
||||
|
||||
def _verify(self):
|
||||
if ([r._generation for r in self._verify_ro]
|
||||
!= self._verify_generations):
|
||||
self.changed(None)
|
||||
|
||||
def _getcache(self, provided, name):
|
||||
self._verify()
|
||||
return LookupBaseFallback._getcache(self, provided, name)
|
||||
|
||||
def lookupAll(self, required, provided):
|
||||
self._verify()
|
||||
return LookupBaseFallback.lookupAll(self, required, provided)
|
||||
|
||||
def subscriptions(self, required, provided):
|
||||
self._verify()
|
||||
return LookupBaseFallback.subscriptions(self, required, provided)
|
||||
|
||||
VerifyingBasePy = VerifyingBaseFallback #BBB
|
||||
|
||||
try:
|
||||
from zope.interface._zope_interface_coptimizations import VerifyingBase
|
||||
except ImportError:
|
||||
VerifyingBase = VerifyingBaseFallback
|
||||
|
||||
|
||||
class AdapterLookupBase(object):
|
||||
|
||||
def __init__(self, registry):
|
||||
self._registry = registry
|
||||
self._required = {}
|
||||
self.init_extendors()
|
||||
super(AdapterLookupBase, self).__init__()
|
||||
|
||||
def changed(self, ignored=None):
|
||||
super(AdapterLookupBase, self).changed(None)
|
||||
for r in self._required.keys():
|
||||
r = r()
|
||||
if r is not None:
|
||||
r.unsubscribe(self)
|
||||
self._required.clear()
|
||||
|
||||
|
||||
# Extendors
|
||||
# ---------
|
||||
|
||||
# When given an target interface for an adapter lookup, we need to consider
|
||||
# adapters for interfaces that extend the target interface. This is
|
||||
# what the extendors dictionary is about. It tells us all of the
|
||||
# interfaces that extend an interface for which there are adapters
|
||||
# registered.
|
||||
|
||||
# We could separate this by order and name, thus reducing the
|
||||
# number of provided interfaces to search at run time. The tradeoff,
|
||||
# however, is that we have to store more information. For example,
|
||||
# if the same interface is provided for multiple names and if the
|
||||
# interface extends many interfaces, we'll have to keep track of
|
||||
# a fair bit of information for each name. It's better to
|
||||
# be space efficient here and be time efficient in the cache
|
||||
# implementation.
|
||||
|
||||
# TODO: add invalidation when a provided interface changes, in case
|
||||
# the interface's __iro__ has changed. This is unlikely enough that
|
||||
# we'll take our chances for now.
|
||||
|
||||
def init_extendors(self):
|
||||
self._extendors = {}
|
||||
for p in self._registry._provided:
|
||||
self.add_extendor(p)
|
||||
|
||||
def add_extendor(self, provided):
|
||||
_extendors = self._extendors
|
||||
for i in provided.__iro__:
|
||||
extendors = _extendors.get(i, ())
|
||||
_extendors[i] = (
|
||||
[e for e in extendors if provided.isOrExtends(e)]
|
||||
+
|
||||
[provided]
|
||||
+
|
||||
[e for e in extendors if not provided.isOrExtends(e)]
|
||||
)
|
||||
|
||||
def remove_extendor(self, provided):
|
||||
_extendors = self._extendors
|
||||
for i in provided.__iro__:
|
||||
_extendors[i] = [e for e in _extendors.get(i, ())
|
||||
if e != provided]
|
||||
|
||||
|
||||
def _subscribe(self, *required):
|
||||
_refs = self._required
|
||||
for r in required:
|
||||
ref = r.weakref()
|
||||
if ref not in _refs:
|
||||
r.subscribe(self)
|
||||
_refs[ref] = 1
|
||||
|
||||
def _uncached_lookup(self, required, provided, name=_BLANK):
|
||||
required = tuple(required)
|
||||
result = None
|
||||
order = len(required)
|
||||
for registry in self._registry.ro:
|
||||
byorder = registry._adapters
|
||||
if order >= len(byorder):
|
||||
continue
|
||||
|
||||
extendors = registry._v_lookup._extendors.get(provided)
|
||||
if not extendors:
|
||||
continue
|
||||
|
||||
components = byorder[order]
|
||||
result = _lookup(components, required, extendors, name, 0,
|
||||
order)
|
||||
if result is not None:
|
||||
break
|
||||
|
||||
self._subscribe(*required)
|
||||
|
||||
return result
|
||||
|
||||
def queryMultiAdapter(self, objects, provided, name=_BLANK, default=None):
|
||||
factory = self.lookup(map(providedBy, objects), provided, name)
|
||||
if factory is None:
|
||||
return default
|
||||
|
||||
result = factory(*objects)
|
||||
if result is None:
|
||||
return default
|
||||
|
||||
return result
|
||||
|
||||
def _uncached_lookupAll(self, required, provided):
|
||||
required = tuple(required)
|
||||
order = len(required)
|
||||
result = {}
|
||||
for registry in reversed(self._registry.ro):
|
||||
byorder = registry._adapters
|
||||
if order >= len(byorder):
|
||||
continue
|
||||
extendors = registry._v_lookup._extendors.get(provided)
|
||||
if not extendors:
|
||||
continue
|
||||
components = byorder[order]
|
||||
_lookupAll(components, required, extendors, result, 0, order)
|
||||
|
||||
self._subscribe(*required)
|
||||
|
||||
return tuple(result.items())
|
||||
|
||||
def names(self, required, provided):
|
||||
return [c[0] for c in self.lookupAll(required, provided)]
|
||||
|
||||
def _uncached_subscriptions(self, required, provided):
|
||||
required = tuple(required)
|
||||
order = len(required)
|
||||
result = []
|
||||
for registry in reversed(self._registry.ro):
|
||||
byorder = registry._subscribers
|
||||
if order >= len(byorder):
|
||||
continue
|
||||
|
||||
if provided is None:
|
||||
extendors = (provided, )
|
||||
else:
|
||||
extendors = registry._v_lookup._extendors.get(provided)
|
||||
if extendors is None:
|
||||
continue
|
||||
|
||||
_subscriptions(byorder[order], required, extendors, _BLANK,
|
||||
result, 0, order)
|
||||
|
||||
self._subscribe(*required)
|
||||
|
||||
return result
|
||||
|
||||
def subscribers(self, objects, provided):
|
||||
subscriptions = self.subscriptions(map(providedBy, objects), provided)
|
||||
if provided is None:
|
||||
result = ()
|
||||
for subscription in subscriptions:
|
||||
subscription(*objects)
|
||||
else:
|
||||
result = []
|
||||
for subscription in subscriptions:
|
||||
subscriber = subscription(*objects)
|
||||
if subscriber is not None:
|
||||
result.append(subscriber)
|
||||
return result
|
||||
|
||||
class AdapterLookup(AdapterLookupBase, LookupBase):
|
||||
pass
|
||||
|
||||
@implementer(IAdapterRegistry)
|
||||
class AdapterRegistry(BaseAdapterRegistry):
|
||||
|
||||
LookupClass = AdapterLookup
|
||||
|
||||
def __init__(self, bases=()):
|
||||
# AdapterRegisties are invalidating registries, so
|
||||
# we need to keep track of out invalidating subregistries.
|
||||
self._v_subregistries = weakref.WeakKeyDictionary()
|
||||
|
||||
super(AdapterRegistry, self).__init__(bases)
|
||||
|
||||
def _addSubregistry(self, r):
|
||||
self._v_subregistries[r] = 1
|
||||
|
||||
def _removeSubregistry(self, r):
|
||||
if r in self._v_subregistries:
|
||||
del self._v_subregistries[r]
|
||||
|
||||
def _setBases(self, bases):
|
||||
old = self.__dict__.get('__bases__', ())
|
||||
for r in old:
|
||||
if r not in bases:
|
||||
r._removeSubregistry(self)
|
||||
for r in bases:
|
||||
if r not in old:
|
||||
r._addSubregistry(self)
|
||||
|
||||
super(AdapterRegistry, self)._setBases(bases)
|
||||
|
||||
def changed(self, originally_changed):
|
||||
super(AdapterRegistry, self).changed(originally_changed)
|
||||
|
||||
for sub in self._v_subregistries.keys():
|
||||
sub.changed(originally_changed)
|
||||
|
||||
|
||||
class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase):
|
||||
pass
|
||||
|
||||
@implementer(IAdapterRegistry)
|
||||
class VerifyingAdapterRegistry(BaseAdapterRegistry):
|
||||
|
||||
LookupClass = VerifyingAdapterLookup
|
||||
|
||||
def _convert_None_to_Interface(x):
|
||||
if x is None:
|
||||
return Interface
|
||||
else:
|
||||
return x
|
||||
|
||||
def _lookup(components, specs, provided, name, i, l):
|
||||
if i < l:
|
||||
for spec in specs[i].__sro__:
|
||||
comps = components.get(spec)
|
||||
if comps:
|
||||
r = _lookup(comps, specs, provided, name, i+1, l)
|
||||
if r is not None:
|
||||
return r
|
||||
else:
|
||||
for iface in provided:
|
||||
comps = components.get(iface)
|
||||
if comps:
|
||||
r = comps.get(name)
|
||||
if r is not None:
|
||||
return r
|
||||
|
||||
return None
|
||||
|
||||
def _lookupAll(components, specs, provided, result, i, l):
|
||||
if i < l:
|
||||
for spec in reversed(specs[i].__sro__):
|
||||
comps = components.get(spec)
|
||||
if comps:
|
||||
_lookupAll(comps, specs, provided, result, i+1, l)
|
||||
else:
|
||||
for iface in reversed(provided):
|
||||
comps = components.get(iface)
|
||||
if comps:
|
||||
result.update(comps)
|
||||
|
||||
def _subscriptions(components, specs, provided, name, result, i, l):
|
||||
if i < l:
|
||||
for spec in reversed(specs[i].__sro__):
|
||||
comps = components.get(spec)
|
||||
if comps:
|
||||
_subscriptions(comps, specs, provided, name, result, i+1, l)
|
||||
else:
|
||||
for iface in reversed(provided):
|
||||
comps = components.get(iface)
|
||||
if comps:
|
||||
comps = comps.get(name)
|
||||
if comps:
|
||||
result.extend(comps)
|
205
lib/zope/interface/advice.py
Normal file
205
lib/zope/interface/advice.py
Normal file
|
@ -0,0 +1,205 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Class advice.
|
||||
|
||||
This module was adapted from 'protocols.advice', part of the Python
|
||||
Enterprise Application Kit (PEAK). Please notify the PEAK authors
|
||||
(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
|
||||
Zope-specific changes are required, so that the PEAK version of this module
|
||||
can be kept in sync.
|
||||
|
||||
PEAK is a Python application framework that interoperates with (but does
|
||||
not require) Zope 3 and Twisted. It provides tools for manipulating UML
|
||||
models, object-relational persistence, aspect-oriented programming, and more.
|
||||
Visit the PEAK home page at http://peak.telecommunity.com for more information.
|
||||
"""
|
||||
|
||||
from types import FunctionType
|
||||
try:
|
||||
from types import ClassType
|
||||
except ImportError:
|
||||
__python3 = True
|
||||
else:
|
||||
__python3 = False
|
||||
|
||||
import sys
|
||||
|
||||
def getFrameInfo(frame):
|
||||
"""Return (kind,module,locals,globals) for a frame
|
||||
|
||||
'kind' is one of "exec", "module", "class", "function call", or "unknown".
|
||||
"""
|
||||
|
||||
f_locals = frame.f_locals
|
||||
f_globals = frame.f_globals
|
||||
|
||||
sameNamespace = f_locals is f_globals
|
||||
hasModule = '__module__' in f_locals
|
||||
hasName = '__name__' in f_globals
|
||||
|
||||
sameName = hasModule and hasName
|
||||
sameName = sameName and f_globals['__name__']==f_locals['__module__']
|
||||
|
||||
module = hasName and sys.modules.get(f_globals['__name__']) or None
|
||||
|
||||
namespaceIsModule = module and module.__dict__ is f_globals
|
||||
|
||||
if not namespaceIsModule:
|
||||
# some kind of funky exec
|
||||
kind = "exec"
|
||||
elif sameNamespace and not hasModule:
|
||||
kind = "module"
|
||||
elif sameName and not sameNamespace:
|
||||
kind = "class"
|
||||
elif not sameNamespace:
|
||||
kind = "function call"
|
||||
else: # pragma: no cover
|
||||
# How can you have f_locals is f_globals, and have '__module__' set?
|
||||
# This is probably module-level code, but with a '__module__' variable.
|
||||
kind = "unknown"
|
||||
return kind, module, f_locals, f_globals
|
||||
|
||||
|
||||
def addClassAdvisor(callback, depth=2):
|
||||
"""Set up 'callback' to be passed the containing class upon creation
|
||||
|
||||
This function is designed to be called by an "advising" function executed
|
||||
in a class suite. The "advising" function supplies a callback that it
|
||||
wishes to have executed when the containing class is created. The
|
||||
callback will be given one argument: the newly created containing class.
|
||||
The return value of the callback will be used in place of the class, so
|
||||
the callback should return the input if it does not wish to replace the
|
||||
class.
|
||||
|
||||
The optional 'depth' argument to this function determines the number of
|
||||
frames between this function and the targeted class suite. 'depth'
|
||||
defaults to 2, since this skips this function's frame and one calling
|
||||
function frame. If you use this function from a function called directly
|
||||
in the class suite, the default will be correct, otherwise you will need
|
||||
to determine the correct depth yourself.
|
||||
|
||||
This function works by installing a special class factory function in
|
||||
place of the '__metaclass__' of the containing class. Therefore, only
|
||||
callbacks *after* the last '__metaclass__' assignment in the containing
|
||||
class will be executed. Be sure that classes using "advising" functions
|
||||
declare any '__metaclass__' *first*, to ensure all callbacks are run."""
|
||||
# This entire approach is invalid under Py3K. Don't even try to fix
|
||||
# the coverage for this block there. :(
|
||||
if __python3: # pragma: no cover
|
||||
raise TypeError('Class advice impossible in Python3')
|
||||
|
||||
frame = sys._getframe(depth)
|
||||
kind, module, caller_locals, caller_globals = getFrameInfo(frame)
|
||||
|
||||
# This causes a problem when zope interfaces are used from doctest.
|
||||
# In these cases, kind == "exec".
|
||||
#
|
||||
#if kind != "class":
|
||||
# raise SyntaxError(
|
||||
# "Advice must be in the body of a class statement"
|
||||
# )
|
||||
|
||||
previousMetaclass = caller_locals.get('__metaclass__')
|
||||
if __python3: # pragma: no cover
|
||||
defaultMetaclass = caller_globals.get('__metaclass__', type)
|
||||
else:
|
||||
defaultMetaclass = caller_globals.get('__metaclass__', ClassType)
|
||||
|
||||
|
||||
def advise(name, bases, cdict):
|
||||
|
||||
if '__metaclass__' in cdict:
|
||||
del cdict['__metaclass__']
|
||||
|
||||
if previousMetaclass is None:
|
||||
if bases:
|
||||
# find best metaclass or use global __metaclass__ if no bases
|
||||
meta = determineMetaclass(bases)
|
||||
else:
|
||||
meta = defaultMetaclass
|
||||
|
||||
elif isClassAdvisor(previousMetaclass):
|
||||
# special case: we can't compute the "true" metaclass here,
|
||||
# so we need to invoke the previous metaclass and let it
|
||||
# figure it out for us (and apply its own advice in the process)
|
||||
meta = previousMetaclass
|
||||
|
||||
else:
|
||||
meta = determineMetaclass(bases, previousMetaclass)
|
||||
|
||||
newClass = meta(name,bases,cdict)
|
||||
|
||||
# this lets the callback replace the class completely, if it wants to
|
||||
return callback(newClass)
|
||||
|
||||
# introspection data only, not used by inner function
|
||||
advise.previousMetaclass = previousMetaclass
|
||||
advise.callback = callback
|
||||
|
||||
# install the advisor
|
||||
caller_locals['__metaclass__'] = advise
|
||||
|
||||
|
||||
def isClassAdvisor(ob):
|
||||
"""True if 'ob' is a class advisor function"""
|
||||
return isinstance(ob,FunctionType) and hasattr(ob,'previousMetaclass')
|
||||
|
||||
|
||||
def determineMetaclass(bases, explicit_mc=None):
|
||||
"""Determine metaclass from 1+ bases and optional explicit __metaclass__"""
|
||||
|
||||
meta = [getattr(b,'__class__',type(b)) for b in bases]
|
||||
|
||||
if explicit_mc is not None:
|
||||
# The explicit metaclass needs to be verified for compatibility
|
||||
# as well, and allowed to resolve the incompatible bases, if any
|
||||
meta.append(explicit_mc)
|
||||
|
||||
if len(meta)==1:
|
||||
# easy case
|
||||
return meta[0]
|
||||
|
||||
candidates = minimalBases(meta) # minimal set of metaclasses
|
||||
|
||||
if not candidates: # pragma: no cover
|
||||
# they're all "classic" classes
|
||||
assert(not __python3) # This should not happen under Python 3
|
||||
return ClassType
|
||||
|
||||
elif len(candidates)>1:
|
||||
# We could auto-combine, but for now we won't...
|
||||
raise TypeError("Incompatible metatypes",bases)
|
||||
|
||||
# Just one, return it
|
||||
return candidates[0]
|
||||
|
||||
|
||||
def minimalBases(classes):
|
||||
"""Reduce a list of base classes to its ordered minimum equivalent"""
|
||||
|
||||
if not __python3: # pragma: no cover
|
||||
classes = [c for c in classes if c is not ClassType]
|
||||
candidates = []
|
||||
|
||||
for m in classes:
|
||||
for n in classes:
|
||||
if issubclass(n,m) and m is not n:
|
||||
break
|
||||
else:
|
||||
# m has no subclasses in 'classes'
|
||||
if m in candidates:
|
||||
candidates.remove(m) # ensure that we're later in the list
|
||||
candidates.append(m)
|
||||
|
||||
return candidates
|
2
lib/zope/interface/common/__init__.py
Normal file
2
lib/zope/interface/common/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
#
|
||||
# This file is necessary to make this directory a package.
|
606
lib/zope/interface/common/idatetime.py
Normal file
606
lib/zope/interface/common/idatetime.py
Normal file
|
@ -0,0 +1,606 @@
|
|||
##############################################################################
|
||||
# Copyright (c) 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.
|
||||
##############################################################################
|
||||
"""Datetime interfaces.
|
||||
|
||||
This module is called idatetime because if it were called datetime the import
|
||||
of the real datetime would fail.
|
||||
"""
|
||||
from datetime import timedelta, date, datetime, time, tzinfo
|
||||
|
||||
from zope.interface import Interface, Attribute
|
||||
from zope.interface import classImplements
|
||||
|
||||
|
||||
class ITimeDeltaClass(Interface):
|
||||
"""This is the timedelta class interface.
|
||||
|
||||
This is symbolic; this module does **not** make
|
||||
`datetime.timedelta` provide this interface.
|
||||
"""
|
||||
|
||||
min = Attribute("The most negative timedelta object")
|
||||
|
||||
max = Attribute("The most positive timedelta object")
|
||||
|
||||
resolution = Attribute(
|
||||
"The smallest difference between non-equal timedelta objects")
|
||||
|
||||
|
||||
class ITimeDelta(ITimeDeltaClass):
|
||||
"""Represent the difference between two datetime objects.
|
||||
|
||||
Implemented by `datetime.timedelta`.
|
||||
|
||||
Supported operators:
|
||||
|
||||
- add, subtract timedelta
|
||||
- unary plus, minus, abs
|
||||
- compare to timedelta
|
||||
- multiply, divide by int/long
|
||||
|
||||
In addition, `.datetime` supports subtraction of two `.datetime` objects
|
||||
returning a `.timedelta`, and addition or subtraction of a `.datetime`
|
||||
and a `.timedelta` giving a `.datetime`.
|
||||
|
||||
Representation: (days, seconds, microseconds).
|
||||
"""
|
||||
|
||||
days = Attribute("Days between -999999999 and 999999999 inclusive")
|
||||
|
||||
seconds = Attribute("Seconds between 0 and 86399 inclusive")
|
||||
|
||||
microseconds = Attribute("Microseconds between 0 and 999999 inclusive")
|
||||
|
||||
|
||||
class IDateClass(Interface):
|
||||
"""This is the date class interface.
|
||||
|
||||
This is symbolic; this module does **not** make
|
||||
`datetime.date` provide this interface.
|
||||
"""
|
||||
|
||||
min = Attribute("The earliest representable date")
|
||||
|
||||
max = Attribute("The latest representable date")
|
||||
|
||||
resolution = Attribute(
|
||||
"The smallest difference between non-equal date objects")
|
||||
|
||||
def today():
|
||||
"""Return the current local time.
|
||||
|
||||
This is equivalent to ``date.fromtimestamp(time.time())``"""
|
||||
|
||||
def fromtimestamp(timestamp):
|
||||
"""Return the local date from a POSIX timestamp (like time.time())
|
||||
|
||||
This may raise `ValueError`, if the timestamp is out of the range of
|
||||
values supported by the platform C ``localtime()`` function. It's common
|
||||
for this to be restricted to years from 1970 through 2038. Note that
|
||||
on non-POSIX systems that include leap seconds in their notion of a
|
||||
timestamp, leap seconds are ignored by `fromtimestamp`.
|
||||
"""
|
||||
|
||||
def fromordinal(ordinal):
|
||||
"""Return the date corresponding to the proleptic Gregorian ordinal.
|
||||
|
||||
January 1 of year 1 has ordinal 1. `ValueError` is raised unless
|
||||
1 <= ordinal <= date.max.toordinal().
|
||||
|
||||
For any date *d*, ``date.fromordinal(d.toordinal()) == d``.
|
||||
"""
|
||||
|
||||
|
||||
class IDate(IDateClass):
|
||||
"""Represents a date (year, month and day) in an idealized calendar.
|
||||
|
||||
Implemented by `datetime.date`.
|
||||
|
||||
Operators:
|
||||
|
||||
__repr__, __str__
|
||||
__cmp__, __hash__
|
||||
__add__, __radd__, __sub__ (add/radd only with timedelta arg)
|
||||
"""
|
||||
|
||||
year = Attribute("Between MINYEAR and MAXYEAR inclusive.")
|
||||
|
||||
month = Attribute("Between 1 and 12 inclusive")
|
||||
|
||||
day = Attribute(
|
||||
"Between 1 and the number of days in the given month of the given year.")
|
||||
|
||||
def replace(year, month, day):
|
||||
"""Return a date with the same value.
|
||||
|
||||
Except for those members given new values by whichever keyword
|
||||
arguments are specified. For example, if ``d == date(2002, 12, 31)``, then
|
||||
``d.replace(day=26) == date(2000, 12, 26)``.
|
||||
"""
|
||||
|
||||
def timetuple():
|
||||
"""Return a 9-element tuple of the form returned by `time.localtime`.
|
||||
|
||||
The hours, minutes and seconds are 0, and the DST flag is -1.
|
||||
``d.timetuple()`` is equivalent to
|
||||
``(d.year, d.month, d.day, 0, 0, 0, d.weekday(), d.toordinal() -
|
||||
date(d.year, 1, 1).toordinal() + 1, -1)``
|
||||
"""
|
||||
|
||||
def toordinal():
|
||||
"""Return the proleptic Gregorian ordinal of the date
|
||||
|
||||
January 1 of year 1 has ordinal 1. For any date object *d*,
|
||||
``date.fromordinal(d.toordinal()) == d``.
|
||||
"""
|
||||
|
||||
def weekday():
|
||||
"""Return the day of the week as an integer.
|
||||
|
||||
Monday is 0 and Sunday is 6. For example,
|
||||
``date(2002, 12, 4).weekday() == 2``, a Wednesday.
|
||||
|
||||
.. seealso:: `isoweekday`.
|
||||
"""
|
||||
|
||||
def isoweekday():
|
||||
"""Return the day of the week as an integer.
|
||||
|
||||
Monday is 1 and Sunday is 7. For example,
|
||||
date(2002, 12, 4).isoweekday() == 3, a Wednesday.
|
||||
|
||||
.. seealso:: `weekday`, `isocalendar`.
|
||||
"""
|
||||
|
||||
def isocalendar():
|
||||
"""Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
|
||||
|
||||
The ISO calendar is a widely used variant of the Gregorian calendar.
|
||||
See http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm for a good
|
||||
explanation.
|
||||
|
||||
The ISO year consists of 52 or 53 full weeks, and where a week starts
|
||||
on a Monday and ends on a Sunday. The first week of an ISO year is the
|
||||
first (Gregorian) calendar week of a year containing a Thursday. This
|
||||
is called week number 1, and the ISO year of that Thursday is the same
|
||||
as its Gregorian year.
|
||||
|
||||
For example, 2004 begins on a Thursday, so the first week of ISO year
|
||||
2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so
|
||||
that ``date(2003, 12, 29).isocalendar() == (2004, 1, 1)`` and
|
||||
``date(2004, 1, 4).isocalendar() == (2004, 1, 7)``.
|
||||
"""
|
||||
|
||||
def isoformat():
|
||||
"""Return a string representing the date in ISO 8601 format.
|
||||
|
||||
This is 'YYYY-MM-DD'.
|
||||
For example, ``date(2002, 12, 4).isoformat() == '2002-12-04'``.
|
||||
"""
|
||||
|
||||
def __str__():
|
||||
"""For a date *d*, ``str(d)`` is equivalent to ``d.isoformat()``."""
|
||||
|
||||
def ctime():
|
||||
"""Return a string representing the date.
|
||||
|
||||
For example date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'.
|
||||
d.ctime() is equivalent to time.ctime(time.mktime(d.timetuple()))
|
||||
on platforms where the native C ctime() function
|
||||
(which `time.ctime` invokes, but which date.ctime() does not invoke)
|
||||
conforms to the C standard.
|
||||
"""
|
||||
|
||||
def strftime(format):
|
||||
"""Return a string representing the date.
|
||||
|
||||
Controlled by an explicit format string. Format codes referring to
|
||||
hours, minutes or seconds will see 0 values.
|
||||
"""
|
||||
|
||||
|
||||
class IDateTimeClass(Interface):
|
||||
"""This is the datetime class interface.
|
||||
|
||||
This is symbolic; this module does **not** make
|
||||
`datetime.datetime` provide this interface.
|
||||
"""
|
||||
|
||||
min = Attribute("The earliest representable datetime")
|
||||
|
||||
max = Attribute("The latest representable datetime")
|
||||
|
||||
resolution = Attribute(
|
||||
"The smallest possible difference between non-equal datetime objects")
|
||||
|
||||
def today():
|
||||
"""Return the current local datetime, with tzinfo None.
|
||||
|
||||
This is equivalent to ``datetime.fromtimestamp(time.time())``.
|
||||
|
||||
.. seealso:: `now`, `fromtimestamp`.
|
||||
"""
|
||||
|
||||
def now(tz=None):
|
||||
"""Return the current local date and time.
|
||||
|
||||
If optional argument *tz* is None or not specified, this is like `today`,
|
||||
but, if possible, supplies more precision than can be gotten from going
|
||||
through a `time.time` timestamp (for example, this may be possible on
|
||||
platforms supplying the C ``gettimeofday()`` function).
|
||||
|
||||
Else tz must be an instance of a class tzinfo subclass, and the current
|
||||
date and time are converted to tz's time zone. In this case the result
|
||||
is equivalent to tz.fromutc(datetime.utcnow().replace(tzinfo=tz)).
|
||||
|
||||
.. seealso:: `today`, `utcnow`.
|
||||
"""
|
||||
|
||||
def utcnow():
|
||||
"""Return the current UTC date and time, with tzinfo None.
|
||||
|
||||
This is like `now`, but returns the current UTC date and time, as a
|
||||
naive datetime object.
|
||||
|
||||
.. seealso:: `now`.
|
||||
"""
|
||||
|
||||
def fromtimestamp(timestamp, tz=None):
|
||||
"""Return the local date and time corresponding to the POSIX timestamp.
|
||||
|
||||
Same as is returned by time.time(). If optional argument tz is None or
|
||||
not specified, the timestamp is converted to the platform's local date
|
||||
and time, and the returned datetime object is naive.
|
||||
|
||||
Else tz must be an instance of a class tzinfo subclass, and the
|
||||
timestamp is converted to tz's time zone. In this case the result is
|
||||
equivalent to
|
||||
``tz.fromutc(datetime.utcfromtimestamp(timestamp).replace(tzinfo=tz))``.
|
||||
|
||||
fromtimestamp() may raise `ValueError`, if the timestamp is out of the
|
||||
range of values supported by the platform C localtime() or gmtime()
|
||||
functions. It's common for this to be restricted to years in 1970
|
||||
through 2038. Note that on non-POSIX systems that include leap seconds
|
||||
in their notion of a timestamp, leap seconds are ignored by
|
||||
fromtimestamp(), and then it's possible to have two timestamps
|
||||
differing by a second that yield identical datetime objects.
|
||||
|
||||
.. seealso:: `utcfromtimestamp`.
|
||||
"""
|
||||
|
||||
def utcfromtimestamp(timestamp):
|
||||
"""Return the UTC datetime from the POSIX timestamp with tzinfo None.
|
||||
|
||||
This may raise `ValueError`, if the timestamp is out of the range of
|
||||
values supported by the platform C ``gmtime()`` function. It's common for
|
||||
this to be restricted to years in 1970 through 2038.
|
||||
|
||||
.. seealso:: `fromtimestamp`.
|
||||
"""
|
||||
|
||||
def fromordinal(ordinal):
|
||||
"""Return the datetime from the proleptic Gregorian ordinal.
|
||||
|
||||
January 1 of year 1 has ordinal 1. `ValueError` is raised unless
|
||||
1 <= ordinal <= datetime.max.toordinal().
|
||||
The hour, minute, second and microsecond of the result are all 0, and
|
||||
tzinfo is None.
|
||||
"""
|
||||
|
||||
def combine(date, time):
|
||||
"""Return a new datetime object.
|
||||
|
||||
Its date members are equal to the given date object's, and whose time
|
||||
and tzinfo members are equal to the given time object's. For any
|
||||
datetime object *d*, ``d == datetime.combine(d.date(), d.timetz())``.
|
||||
If date is a datetime object, its time and tzinfo members are ignored.
|
||||
"""
|
||||
|
||||
|
||||
class IDateTime(IDate, IDateTimeClass):
|
||||
"""Object contains all the information from a date object and a time object.
|
||||
|
||||
Implemented by `datetime.datetime`.
|
||||
"""
|
||||
|
||||
year = Attribute("Year between MINYEAR and MAXYEAR inclusive")
|
||||
|
||||
month = Attribute("Month between 1 and 12 inclusive")
|
||||
|
||||
day = Attribute(
|
||||
"Day between 1 and the number of days in the given month of the year")
|
||||
|
||||
hour = Attribute("Hour in range(24)")
|
||||
|
||||
minute = Attribute("Minute in range(60)")
|
||||
|
||||
second = Attribute("Second in range(60)")
|
||||
|
||||
microsecond = Attribute("Microsecond in range(1000000)")
|
||||
|
||||
tzinfo = Attribute(
|
||||
"""The object passed as the tzinfo argument to the datetime constructor
|
||||
or None if none was passed""")
|
||||
|
||||
def date():
|
||||
"""Return date object with same year, month and day."""
|
||||
|
||||
def time():
|
||||
"""Return time object with same hour, minute, second, microsecond.
|
||||
|
||||
tzinfo is None.
|
||||
|
||||
.. seealso:: Method :meth:`timetz`.
|
||||
"""
|
||||
|
||||
def timetz():
|
||||
"""Return time object with same hour, minute, second, microsecond,
|
||||
and tzinfo.
|
||||
|
||||
.. seealso:: Method :meth:`time`.
|
||||
"""
|
||||
|
||||
def replace(year, month, day, hour, minute, second, microsecond, tzinfo):
|
||||
"""Return a datetime with the same members, except for those members
|
||||
given new values by whichever keyword arguments are specified.
|
||||
|
||||
Note that ``tzinfo=None`` can be specified to create a naive datetime from
|
||||
an aware datetime with no conversion of date and time members.
|
||||
"""
|
||||
|
||||
def astimezone(tz):
|
||||
"""Return a datetime object with new tzinfo member tz, adjusting the
|
||||
date and time members so the result is the same UTC time as self, but
|
||||
in tz's local time.
|
||||
|
||||
tz must be an instance of a tzinfo subclass, and its utcoffset() and
|
||||
dst() methods must not return None. self must be aware (self.tzinfo
|
||||
must not be None, and self.utcoffset() must not return None).
|
||||
|
||||
If self.tzinfo is tz, self.astimezone(tz) is equal to self: no
|
||||
adjustment of date or time members is performed. Else the result is
|
||||
local time in time zone tz, representing the same UTC time as self:
|
||||
|
||||
after astz = dt.astimezone(tz), astz - astz.utcoffset()
|
||||
|
||||
will usually have the same date and time members as dt - dt.utcoffset().
|
||||
The discussion of class `datetime.tzinfo` explains the cases at Daylight Saving
|
||||
Time transition boundaries where this cannot be achieved (an issue only
|
||||
if tz models both standard and daylight time).
|
||||
|
||||
If you merely want to attach a time zone object *tz* to a datetime *dt*
|
||||
without adjustment of date and time members, use ``dt.replace(tzinfo=tz)``.
|
||||
If you merely want to remove the time zone object from an aware
|
||||
datetime dt without conversion of date and time members, use
|
||||
``dt.replace(tzinfo=None)``.
|
||||
|
||||
Note that the default `tzinfo.fromutc` method can be overridden in a
|
||||
tzinfo subclass to effect the result returned by `astimezone`.
|
||||
"""
|
||||
|
||||
def utcoffset():
|
||||
"""Return the timezone offset in minutes east of UTC (negative west of
|
||||
UTC)."""
|
||||
|
||||
def dst():
|
||||
"""Return 0 if DST is not in effect, or the DST offset (in minutes
|
||||
eastward) if DST is in effect.
|
||||
"""
|
||||
|
||||
def tzname():
|
||||
"""Return the timezone name."""
|
||||
|
||||
def timetuple():
|
||||
"""Return a 9-element tuple of the form returned by `time.localtime`."""
|
||||
|
||||
def utctimetuple():
|
||||
"""Return UTC time tuple compatilble with `time.gmtime`."""
|
||||
|
||||
def toordinal():
|
||||
"""Return the proleptic Gregorian ordinal of the date.
|
||||
|
||||
The same as self.date().toordinal().
|
||||
"""
|
||||
|
||||
def weekday():
|
||||
"""Return the day of the week as an integer.
|
||||
|
||||
Monday is 0 and Sunday is 6. The same as self.date().weekday().
|
||||
See also isoweekday().
|
||||
"""
|
||||
|
||||
def isoweekday():
|
||||
"""Return the day of the week as an integer.
|
||||
|
||||
Monday is 1 and Sunday is 7. The same as self.date().isoweekday.
|
||||
|
||||
.. seealso:: `weekday`, `isocalendar`.
|
||||
"""
|
||||
|
||||
def isocalendar():
|
||||
"""Return a 3-tuple, (ISO year, ISO week number, ISO weekday).
|
||||
|
||||
The same as self.date().isocalendar().
|
||||
"""
|
||||
|
||||
def isoformat(sep='T'):
|
||||
"""Return a string representing the date and time in ISO 8601 format.
|
||||
|
||||
YYYY-MM-DDTHH:MM:SS.mmmmmm or YYYY-MM-DDTHH:MM:SS if microsecond is 0
|
||||
|
||||
If `utcoffset` does not return None, a 6-character string is appended,
|
||||
giving the UTC offset in (signed) hours and minutes:
|
||||
|
||||
YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or YYYY-MM-DDTHH:MM:SS+HH:MM
|
||||
if microsecond is 0.
|
||||
|
||||
The optional argument sep (default 'T') is a one-character separator,
|
||||
placed between the date and time portions of the result.
|
||||
"""
|
||||
|
||||
def __str__():
|
||||
"""For a datetime instance *d*, ``str(d)`` is equivalent to ``d.isoformat(' ')``.
|
||||
"""
|
||||
|
||||
def ctime():
|
||||
"""Return a string representing the date and time.
|
||||
|
||||
``datetime(2002, 12, 4, 20, 30, 40).ctime() == 'Wed Dec 4 20:30:40 2002'``.
|
||||
``d.ctime()`` is equivalent to ``time.ctime(time.mktime(d.timetuple()))`` on
|
||||
platforms where the native C ``ctime()`` function (which `time.ctime`
|
||||
invokes, but which `datetime.ctime` does not invoke) conforms to the
|
||||
C standard.
|
||||
"""
|
||||
|
||||
def strftime(format):
|
||||
"""Return a string representing the date and time.
|
||||
|
||||
This is controlled by an explicit format string.
|
||||
"""
|
||||
|
||||
|
||||
class ITimeClass(Interface):
|
||||
"""This is the time class interface.
|
||||
|
||||
This is symbolic; this module does **not** make
|
||||
`datetime.time` provide this interface.
|
||||
|
||||
"""
|
||||
|
||||
min = Attribute("The earliest representable time")
|
||||
|
||||
max = Attribute("The latest representable time")
|
||||
|
||||
resolution = Attribute(
|
||||
"The smallest possible difference between non-equal time objects")
|
||||
|
||||
|
||||
class ITime(ITimeClass):
|
||||
"""Represent time with time zone.
|
||||
|
||||
Implemented by `datetime.time`.
|
||||
|
||||
Operators:
|
||||
|
||||
__repr__, __str__
|
||||
__cmp__, __hash__
|
||||
"""
|
||||
|
||||
hour = Attribute("Hour in range(24)")
|
||||
|
||||
minute = Attribute("Minute in range(60)")
|
||||
|
||||
second = Attribute("Second in range(60)")
|
||||
|
||||
microsecond = Attribute("Microsecond in range(1000000)")
|
||||
|
||||
tzinfo = Attribute(
|
||||
"""The object passed as the tzinfo argument to the time constructor
|
||||
or None if none was passed.""")
|
||||
|
||||
def replace(hour, minute, second, microsecond, tzinfo):
|
||||
"""Return a time with the same value.
|
||||
|
||||
Except for those members given new values by whichever keyword
|
||||
arguments are specified. Note that tzinfo=None can be specified
|
||||
to create a naive time from an aware time, without conversion of the
|
||||
time members.
|
||||
"""
|
||||
|
||||
def isoformat():
|
||||
"""Return a string representing the time in ISO 8601 format.
|
||||
|
||||
That is HH:MM:SS.mmmmmm or, if self.microsecond is 0, HH:MM:SS
|
||||
If utcoffset() does not return None, a 6-character string is appended,
|
||||
giving the UTC offset in (signed) hours and minutes:
|
||||
HH:MM:SS.mmmmmm+HH:MM or, if self.microsecond is 0, HH:MM:SS+HH:MM
|
||||
"""
|
||||
|
||||
def __str__():
|
||||
"""For a time t, str(t) is equivalent to t.isoformat()."""
|
||||
|
||||
def strftime(format):
|
||||
"""Return a string representing the time.
|
||||
|
||||
This is controlled by an explicit format string.
|
||||
"""
|
||||
|
||||
def utcoffset():
|
||||
"""Return the timezone offset in minutes east of UTC (negative west of
|
||||
UTC).
|
||||
|
||||
If tzinfo is None, returns None, else returns
|
||||
self.tzinfo.utcoffset(None), and raises an exception if the latter
|
||||
doesn't return None or a timedelta object representing a whole number
|
||||
of minutes with magnitude less than one day.
|
||||
"""
|
||||
|
||||
def dst():
|
||||
"""Return 0 if DST is not in effect, or the DST offset (in minutes
|
||||
eastward) if DST is in effect.
|
||||
|
||||
If tzinfo is None, returns None, else returns self.tzinfo.dst(None),
|
||||
and raises an exception if the latter doesn't return None, or a
|
||||
timedelta object representing a whole number of minutes with
|
||||
magnitude less than one day.
|
||||
"""
|
||||
|
||||
def tzname():
|
||||
"""Return the timezone name.
|
||||
|
||||
If tzinfo is None, returns None, else returns self.tzinfo.tzname(None),
|
||||
or raises an exception if the latter doesn't return None or a string
|
||||
object.
|
||||
"""
|
||||
|
||||
|
||||
class ITZInfo(Interface):
|
||||
"""Time zone info class.
|
||||
"""
|
||||
|
||||
def utcoffset(dt):
|
||||
"""Return offset of local time from UTC, in minutes east of UTC.
|
||||
|
||||
If local time is west of UTC, this should be negative.
|
||||
Note that this is intended to be the total offset from UTC;
|
||||
for example, if a tzinfo object represents both time zone and DST
|
||||
adjustments, utcoffset() should return their sum. If the UTC offset
|
||||
isn't known, return None. Else the value returned must be a timedelta
|
||||
object specifying a whole number of minutes in the range -1439 to 1439
|
||||
inclusive (1440 = 24*60; the magnitude of the offset must be less
|
||||
than one day).
|
||||
"""
|
||||
|
||||
def dst(dt):
|
||||
"""Return the daylight saving time (DST) adjustment, in minutes east
|
||||
of UTC, or None if DST information isn't known.
|
||||
"""
|
||||
|
||||
def tzname(dt):
|
||||
"""Return the time zone name corresponding to the datetime object as
|
||||
a string.
|
||||
"""
|
||||
|
||||
def fromutc(dt):
|
||||
"""Return an equivalent datetime in self's local time."""
|
||||
|
||||
|
||||
classImplements(timedelta, ITimeDelta)
|
||||
classImplements(date, IDate)
|
||||
classImplements(datetime, IDateTime)
|
||||
classImplements(time, ITime)
|
||||
classImplements(tzinfo, ITZInfo)
|
||||
|
||||
## directlyProvides(timedelta, ITimeDeltaClass)
|
||||
## directlyProvides(date, IDateClass)
|
||||
## directlyProvides(datetime, IDateTimeClass)
|
||||
## directlyProvides(time, ITimeClass)
|
212
lib/zope/interface/common/interfaces.py
Normal file
212
lib/zope/interface/common/interfaces.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Interfaces for standard python exceptions
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.interface import classImplements
|
||||
|
||||
class IException(Interface):
|
||||
"Interface for `Exception`"
|
||||
classImplements(Exception, IException)
|
||||
|
||||
|
||||
class IStandardError(IException):
|
||||
"Interface for `StandardError` (Python 2 only.)"
|
||||
try:
|
||||
classImplements(StandardError, IStandardError)
|
||||
except NameError: #pragma NO COVER
|
||||
pass # StandardError does not exist in Python 3
|
||||
|
||||
|
||||
class IWarning(IException):
|
||||
"Interface for `Warning`"
|
||||
classImplements(Warning, IWarning)
|
||||
|
||||
|
||||
class ISyntaxError(IStandardError):
|
||||
"Interface for `SyntaxError`"
|
||||
classImplements(SyntaxError, ISyntaxError)
|
||||
|
||||
|
||||
class ILookupError(IStandardError):
|
||||
"Interface for `LookupError`"
|
||||
classImplements(LookupError, ILookupError)
|
||||
|
||||
|
||||
class IValueError(IStandardError):
|
||||
"Interface for `ValueError`"
|
||||
classImplements(ValueError, IValueError)
|
||||
|
||||
|
||||
class IRuntimeError(IStandardError):
|
||||
"Interface for `RuntimeError`"
|
||||
classImplements(RuntimeError, IRuntimeError)
|
||||
|
||||
|
||||
class IArithmeticError(IStandardError):
|
||||
"Interface for `ArithmeticError`"
|
||||
classImplements(ArithmeticError, IArithmeticError)
|
||||
|
||||
|
||||
class IAssertionError(IStandardError):
|
||||
"Interface for `AssertionError`"
|
||||
classImplements(AssertionError, IAssertionError)
|
||||
|
||||
|
||||
class IAttributeError(IStandardError):
|
||||
"Interface for `AttributeError`"
|
||||
classImplements(AttributeError, IAttributeError)
|
||||
|
||||
|
||||
class IDeprecationWarning(IWarning):
|
||||
"Interface for `DeprecationWarning`"
|
||||
classImplements(DeprecationWarning, IDeprecationWarning)
|
||||
|
||||
|
||||
class IEOFError(IStandardError):
|
||||
"Interface for `EOFError`"
|
||||
classImplements(EOFError, IEOFError)
|
||||
|
||||
|
||||
class IEnvironmentError(IStandardError):
|
||||
"Interface for `EnvironmentError`"
|
||||
classImplements(EnvironmentError, IEnvironmentError)
|
||||
|
||||
|
||||
class IFloatingPointError(IArithmeticError):
|
||||
"Interface for `FloatingPointError`"
|
||||
classImplements(FloatingPointError, IFloatingPointError)
|
||||
|
||||
|
||||
class IIOError(IEnvironmentError):
|
||||
"Interface for `IOError`"
|
||||
classImplements(IOError, IIOError)
|
||||
|
||||
|
||||
class IImportError(IStandardError):
|
||||
"Interface for `ImportError`"
|
||||
classImplements(ImportError, IImportError)
|
||||
|
||||
|
||||
class IIndentationError(ISyntaxError):
|
||||
"Interface for `IndentationError`"
|
||||
classImplements(IndentationError, IIndentationError)
|
||||
|
||||
|
||||
class IIndexError(ILookupError):
|
||||
"Interface for `IndexError`"
|
||||
classImplements(IndexError, IIndexError)
|
||||
|
||||
|
||||
class IKeyError(ILookupError):
|
||||
"Interface for `KeyError`"
|
||||
classImplements(KeyError, IKeyError)
|
||||
|
||||
|
||||
class IKeyboardInterrupt(IStandardError):
|
||||
"Interface for `KeyboardInterrupt`"
|
||||
classImplements(KeyboardInterrupt, IKeyboardInterrupt)
|
||||
|
||||
|
||||
class IMemoryError(IStandardError):
|
||||
"Interface for `MemoryError`"
|
||||
classImplements(MemoryError, IMemoryError)
|
||||
|
||||
|
||||
class INameError(IStandardError):
|
||||
"Interface for `NameError`"
|
||||
classImplements(NameError, INameError)
|
||||
|
||||
|
||||
class INotImplementedError(IRuntimeError):
|
||||
"Interface for `NotImplementedError`"
|
||||
classImplements(NotImplementedError, INotImplementedError)
|
||||
|
||||
|
||||
class IOSError(IEnvironmentError):
|
||||
"Interface for `OSError`"
|
||||
classImplements(OSError, IOSError)
|
||||
|
||||
|
||||
class IOverflowError(IArithmeticError):
|
||||
"Interface for `ArithmeticError`"
|
||||
classImplements(OverflowError, IOverflowError)
|
||||
|
||||
|
||||
class IOverflowWarning(IWarning):
|
||||
"""Deprecated, no standard class implements this.
|
||||
|
||||
This was the interface for ``OverflowWarning`` prior to Python 2.5,
|
||||
but that class was removed for all versions after that.
|
||||
"""
|
||||
|
||||
|
||||
class IReferenceError(IStandardError):
|
||||
"Interface for `ReferenceError`"
|
||||
classImplements(ReferenceError, IReferenceError)
|
||||
|
||||
|
||||
class IRuntimeWarning(IWarning):
|
||||
"Interface for `RuntimeWarning`"
|
||||
classImplements(RuntimeWarning, IRuntimeWarning)
|
||||
|
||||
|
||||
class IStopIteration(IException):
|
||||
"Interface for `StopIteration`"
|
||||
classImplements(StopIteration, IStopIteration)
|
||||
|
||||
|
||||
class ISyntaxWarning(IWarning):
|
||||
"Interface for `SyntaxWarning`"
|
||||
classImplements(SyntaxWarning, ISyntaxWarning)
|
||||
|
||||
|
||||
class ISystemError(IStandardError):
|
||||
"Interface for `SystemError`"
|
||||
classImplements(SystemError, ISystemError)
|
||||
|
||||
|
||||
class ISystemExit(IException):
|
||||
"Interface for `SystemExit`"
|
||||
classImplements(SystemExit, ISystemExit)
|
||||
|
||||
|
||||
class ITabError(IIndentationError):
|
||||
"Interface for `TabError`"
|
||||
classImplements(TabError, ITabError)
|
||||
|
||||
|
||||
class ITypeError(IStandardError):
|
||||
"Interface for `TypeError`"
|
||||
classImplements(TypeError, ITypeError)
|
||||
|
||||
|
||||
class IUnboundLocalError(INameError):
|
||||
"Interface for `UnboundLocalError`"
|
||||
classImplements(UnboundLocalError, IUnboundLocalError)
|
||||
|
||||
|
||||
class IUnicodeError(IValueError):
|
||||
"Interface for `UnicodeError`"
|
||||
classImplements(UnicodeError, IUnicodeError)
|
||||
|
||||
|
||||
class IUserWarning(IWarning):
|
||||
"Interface for `UserWarning`"
|
||||
classImplements(UserWarning, IUserWarning)
|
||||
|
||||
|
||||
class IZeroDivisionError(IArithmeticError):
|
||||
"Interface for `ZeroDivisionError`"
|
||||
classImplements(ZeroDivisionError, IZeroDivisionError)
|
150
lib/zope/interface/common/mapping.py
Normal file
150
lib/zope/interface/common/mapping.py
Normal file
|
@ -0,0 +1,150 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Mapping Interfaces.
|
||||
|
||||
Importing this module does *not* mark any standard classes
|
||||
as implementing any of these interfaces.
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
|
||||
class IItemMapping(Interface):
|
||||
"""Simplest readable mapping object
|
||||
"""
|
||||
|
||||
def __getitem__(key):
|
||||
"""Get a value for a key
|
||||
|
||||
A `KeyError` is raised if there is no value for the key.
|
||||
"""
|
||||
|
||||
|
||||
class IReadMapping(IItemMapping):
|
||||
"""Basic mapping interface
|
||||
"""
|
||||
|
||||
def get(key, default=None):
|
||||
"""Get a value for a key
|
||||
|
||||
The default is returned if there is no value for the key.
|
||||
"""
|
||||
|
||||
def __contains__(key):
|
||||
"""Tell if a key exists in the mapping."""
|
||||
|
||||
|
||||
class IWriteMapping(Interface):
|
||||
"""Mapping methods for changing data"""
|
||||
|
||||
def __delitem__(key):
|
||||
"""Delete a value from the mapping using the key."""
|
||||
|
||||
def __setitem__(key, value):
|
||||
"""Set a new item in the mapping."""
|
||||
|
||||
|
||||
class IEnumerableMapping(IReadMapping):
|
||||
"""Mapping objects whose items can be enumerated.
|
||||
"""
|
||||
|
||||
def keys():
|
||||
"""Return the keys of the mapping object.
|
||||
"""
|
||||
|
||||
def __iter__():
|
||||
"""Return an iterator for the keys of the mapping object.
|
||||
"""
|
||||
|
||||
def values():
|
||||
"""Return the values of the mapping object.
|
||||
"""
|
||||
|
||||
def items():
|
||||
"""Return the items of the mapping object.
|
||||
"""
|
||||
|
||||
def __len__():
|
||||
"""Return the number of items.
|
||||
"""
|
||||
|
||||
class IMapping(IWriteMapping, IEnumerableMapping):
|
||||
''' Simple mapping interface '''
|
||||
|
||||
class IIterableMapping(IEnumerableMapping):
|
||||
"""A mapping that has distinct methods for iterating
|
||||
without copying.
|
||||
|
||||
On Python 2, a `dict` has these methods, but on Python 3
|
||||
the methods defined in `IEnumerableMapping` already iterate
|
||||
without copying.
|
||||
"""
|
||||
|
||||
def iterkeys():
|
||||
"iterate over keys; equivalent to ``__iter__``"
|
||||
|
||||
def itervalues():
|
||||
"iterate over values"
|
||||
|
||||
def iteritems():
|
||||
"iterate over items"
|
||||
|
||||
class IClonableMapping(Interface):
|
||||
"""Something that can produce a copy of itself.
|
||||
|
||||
This is available in `dict`.
|
||||
"""
|
||||
|
||||
def copy():
|
||||
"return copy of dict"
|
||||
|
||||
class IExtendedReadMapping(IIterableMapping):
|
||||
"""
|
||||
Something with a particular method equivalent to ``__contains__``.
|
||||
|
||||
On Python 2, `dict` provides this method, but it was removed
|
||||
in Python 3.
|
||||
"""
|
||||
|
||||
def has_key(key):
|
||||
"""Tell if a key exists in the mapping; equivalent to ``__contains__``"""
|
||||
|
||||
class IExtendedWriteMapping(IWriteMapping):
|
||||
"""Additional mutation methods.
|
||||
|
||||
These are all provided by `dict`.
|
||||
"""
|
||||
|
||||
def clear():
|
||||
"delete all items"
|
||||
|
||||
def update(d):
|
||||
" Update D from E: for k in E.keys(): D[k] = E[k]"
|
||||
|
||||
def setdefault(key, default=None):
|
||||
"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"
|
||||
|
||||
def pop(k, *args):
|
||||
"""Remove specified key and return the corresponding value.
|
||||
|
||||
``*args`` may contain a single default value, or may not be supplied.
|
||||
If key is not found, default is returned if given, otherwise
|
||||
`KeyError` is raised"""
|
||||
|
||||
def popitem():
|
||||
"""remove and return some (key, value) pair as a
|
||||
2-tuple; but raise KeyError if mapping is empty"""
|
||||
|
||||
class IFullMapping(
|
||||
IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping):
|
||||
''' Full mapping interface ''' # IMapping included so tests for IMapping
|
||||
# succeed with IFullMapping
|
165
lib/zope/interface/common/sequence.py
Normal file
165
lib/zope/interface/common/sequence.py
Normal file
|
@ -0,0 +1,165 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Sequence Interfaces
|
||||
|
||||
Importing this module does *not* mark any standard classes
|
||||
as implementing any of these interfaces.
|
||||
"""
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
from zope.interface import Interface
|
||||
|
||||
class IMinimalSequence(Interface):
|
||||
"""Most basic sequence interface.
|
||||
|
||||
All sequences are iterable. This requires at least one of the
|
||||
following:
|
||||
|
||||
- a `__getitem__()` method that takes a single argument; integer
|
||||
values starting at 0 must be supported, and `IndexError` should
|
||||
be raised for the first index for which there is no value, or
|
||||
|
||||
- an `__iter__()` method that returns an iterator as defined in
|
||||
the Python documentation (http://docs.python.org/lib/typeiter.html).
|
||||
|
||||
"""
|
||||
|
||||
def __getitem__(index):
|
||||
"""``x.__getitem__(index) <==> x[index]``
|
||||
|
||||
Declaring this interface does not specify whether `__getitem__`
|
||||
supports slice objects."""
|
||||
|
||||
class IFiniteSequence(IMinimalSequence):
|
||||
|
||||
def __len__():
|
||||
"""``x.__len__() <==> len(x)``"""
|
||||
|
||||
class IReadSequence(IFiniteSequence):
|
||||
"""read interface shared by tuple and list"""
|
||||
|
||||
def __contains__(item):
|
||||
"""``x.__contains__(item) <==> item in x``"""
|
||||
|
||||
def __lt__(other):
|
||||
"""``x.__lt__(other) <==> x < other``"""
|
||||
|
||||
def __le__(other):
|
||||
"""``x.__le__(other) <==> x <= other``"""
|
||||
|
||||
def __eq__(other):
|
||||
"""``x.__eq__(other) <==> x == other``"""
|
||||
|
||||
def __ne__(other):
|
||||
"""``x.__ne__(other) <==> x != other``"""
|
||||
|
||||
def __gt__(other):
|
||||
"""``x.__gt__(other) <==> x > other``"""
|
||||
|
||||
def __ge__(other):
|
||||
"""``x.__ge__(other) <==> x >= other``"""
|
||||
|
||||
def __add__(other):
|
||||
"""``x.__add__(other) <==> x + other``"""
|
||||
|
||||
def __mul__(n):
|
||||
"""``x.__mul__(n) <==> x * n``"""
|
||||
|
||||
def __rmul__(n):
|
||||
"""``x.__rmul__(n) <==> n * x``"""
|
||||
|
||||
def __getslice__(i, j):
|
||||
"""``x.__getslice__(i, j) <==> x[i:j]``
|
||||
|
||||
Use of negative indices is not supported.
|
||||
|
||||
Deprecated since Python 2.0 but still a part of `UserList`.
|
||||
"""
|
||||
|
||||
class IExtendedReadSequence(IReadSequence):
|
||||
"""Full read interface for lists"""
|
||||
|
||||
def count(item):
|
||||
"""Return number of occurrences of value"""
|
||||
|
||||
def index(item, *args):
|
||||
"""index(value, [start, [stop]]) -> int
|
||||
|
||||
Return first index of *value*
|
||||
"""
|
||||
|
||||
class IUniqueMemberWriteSequence(Interface):
|
||||
"""The write contract for a sequence that may enforce unique members"""
|
||||
|
||||
def __setitem__(index, item):
|
||||
"""``x.__setitem__(index, item) <==> x[index] = item``
|
||||
|
||||
Declaring this interface does not specify whether `__setitem__`
|
||||
supports slice objects.
|
||||
"""
|
||||
|
||||
def __delitem__(index):
|
||||
"""``x.__delitem__(index) <==> del x[index]``
|
||||
|
||||
Declaring this interface does not specify whether `__delitem__`
|
||||
supports slice objects.
|
||||
"""
|
||||
|
||||
def __setslice__(i, j, other):
|
||||
"""``x.__setslice__(i, j, other) <==> x[i:j] = other``
|
||||
|
||||
Use of negative indices is not supported.
|
||||
|
||||
Deprecated since Python 2.0 but still a part of `UserList`.
|
||||
"""
|
||||
|
||||
def __delslice__(i, j):
|
||||
"""``x.__delslice__(i, j) <==> del x[i:j]``
|
||||
|
||||
Use of negative indices is not supported.
|
||||
|
||||
Deprecated since Python 2.0 but still a part of `UserList`.
|
||||
"""
|
||||
def __iadd__(y):
|
||||
"""``x.__iadd__(y) <==> x += y``"""
|
||||
|
||||
def append(item):
|
||||
"""Append item to end"""
|
||||
|
||||
def insert(index, item):
|
||||
"""Insert item before index"""
|
||||
|
||||
def pop(index=-1):
|
||||
"""Remove and return item at index (default last)"""
|
||||
|
||||
def remove(item):
|
||||
"""Remove first occurrence of value"""
|
||||
|
||||
def reverse():
|
||||
"""Reverse *IN PLACE*"""
|
||||
|
||||
def sort(cmpfunc=None):
|
||||
"""Stable sort *IN PLACE*; `cmpfunc(x, y)` -> -1, 0, 1"""
|
||||
|
||||
def extend(iterable):
|
||||
"""Extend list by appending elements from the iterable"""
|
||||
|
||||
class IWriteSequence(IUniqueMemberWriteSequence):
|
||||
"""Full write contract for sequences"""
|
||||
|
||||
def __imul__(n):
|
||||
"""``x.__imul__(n) <==> x *= n``"""
|
||||
|
||||
class ISequence(IReadSequence, IWriteSequence):
|
||||
"""Full sequence contract"""
|
2
lib/zope/interface/common/tests/__init__.py
Normal file
2
lib/zope/interface/common/tests/__init__.py
Normal file
|
@ -0,0 +1,2 @@
|
|||
#
|
||||
# This file is necessary to make this directory a package.
|
107
lib/zope/interface/common/tests/basemapping.py
Normal file
107
lib/zope/interface/common/tests/basemapping.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Base Mapping tests
|
||||
"""
|
||||
from operator import __getitem__
|
||||
|
||||
def testIReadMapping(self, inst, state, absent):
|
||||
for key in state:
|
||||
self.assertEqual(inst[key], state[key])
|
||||
self.assertEqual(inst.get(key, None), state[key])
|
||||
self.assertTrue(key in inst)
|
||||
|
||||
for key in absent:
|
||||
self.assertEqual(inst.get(key, None), None)
|
||||
self.assertEqual(inst.get(key), None)
|
||||
self.assertEqual(inst.get(key, self), self)
|
||||
self.assertRaises(KeyError, __getitem__, inst, key)
|
||||
|
||||
|
||||
def test_keys(self, inst, state):
|
||||
# Return the keys of the mapping object
|
||||
inst_keys = list(inst.keys()); inst_keys.sort()
|
||||
state_keys = list(state.keys()) ; state_keys.sort()
|
||||
self.assertEqual(inst_keys, state_keys)
|
||||
|
||||
def test_iter(self, inst, state):
|
||||
# Return the keys of the mapping object
|
||||
inst_keys = list(inst); inst_keys.sort()
|
||||
state_keys = list(state.keys()) ; state_keys.sort()
|
||||
self.assertEqual(inst_keys, state_keys)
|
||||
|
||||
def test_values(self, inst, state):
|
||||
# Return the values of the mapping object
|
||||
inst_values = list(inst.values()); inst_values.sort()
|
||||
state_values = list(state.values()) ; state_values.sort()
|
||||
self.assertEqual(inst_values, state_values)
|
||||
|
||||
def test_items(self, inst, state):
|
||||
# Return the items of the mapping object
|
||||
inst_items = list(inst.items()); inst_items.sort()
|
||||
state_items = list(state.items()) ; state_items.sort()
|
||||
self.assertEqual(inst_items, state_items)
|
||||
|
||||
def test___len__(self, inst, state):
|
||||
# Return the number of items
|
||||
self.assertEqual(len(inst), len(state))
|
||||
|
||||
def testIEnumerableMapping(self, inst, state):
|
||||
test_keys(self, inst, state)
|
||||
test_items(self, inst, state)
|
||||
test_values(self, inst, state)
|
||||
test___len__(self, inst, state)
|
||||
|
||||
|
||||
class BaseTestIReadMapping(object):
|
||||
def testIReadMapping(self):
|
||||
inst = self._IReadMapping__sample()
|
||||
state = self._IReadMapping__stateDict()
|
||||
absent = self._IReadMapping__absentKeys()
|
||||
testIReadMapping(self, inst, state, absent)
|
||||
|
||||
|
||||
class BaseTestIEnumerableMapping(BaseTestIReadMapping):
|
||||
# Mapping objects whose items can be enumerated
|
||||
def test_keys(self):
|
||||
# Return the keys of the mapping object
|
||||
inst = self._IEnumerableMapping__sample()
|
||||
state = self._IEnumerableMapping__stateDict()
|
||||
test_keys(self, inst, state)
|
||||
|
||||
def test_values(self):
|
||||
# Return the values of the mapping object
|
||||
inst = self._IEnumerableMapping__sample()
|
||||
state = self._IEnumerableMapping__stateDict()
|
||||
test_values(self, inst, state)
|
||||
|
||||
def test_items(self):
|
||||
# Return the items of the mapping object
|
||||
inst = self._IEnumerableMapping__sample()
|
||||
state = self._IEnumerableMapping__stateDict()
|
||||
test_items(self, inst, state)
|
||||
|
||||
def test___len__(self):
|
||||
# Return the number of items
|
||||
inst = self._IEnumerableMapping__sample()
|
||||
state = self._IEnumerableMapping__stateDict()
|
||||
test___len__(self, inst, state)
|
||||
|
||||
def _IReadMapping__stateDict(self):
|
||||
return self._IEnumerableMapping__stateDict()
|
||||
|
||||
def _IReadMapping__sample(self):
|
||||
return self._IEnumerableMapping__sample()
|
||||
|
||||
def _IReadMapping__absentKeys(self):
|
||||
return self._IEnumerableMapping__absentKeys()
|
37
lib/zope/interface/common/tests/test_idatetime.py
Normal file
37
lib/zope/interface/common/tests/test_idatetime.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test for datetime interfaces
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from zope.interface.verify import verifyObject, verifyClass
|
||||
from zope.interface.common.idatetime import ITimeDelta, ITimeDeltaClass
|
||||
from zope.interface.common.idatetime import IDate, IDateClass
|
||||
from zope.interface.common.idatetime import IDateTime, IDateTimeClass
|
||||
from zope.interface.common.idatetime import ITime, ITimeClass, ITZInfo
|
||||
from datetime import timedelta, date, datetime, time, tzinfo
|
||||
|
||||
class TestDateTimeInterfaces(unittest.TestCase):
|
||||
|
||||
def test_interfaces(self):
|
||||
verifyObject(ITimeDelta, timedelta(minutes=20))
|
||||
verifyObject(IDate, date(2000, 1, 2))
|
||||
verifyObject(IDateTime, datetime(2000, 1, 2, 10, 20))
|
||||
verifyObject(ITime, time(20, 30, 15, 1234))
|
||||
verifyObject(ITZInfo, tzinfo())
|
||||
verifyClass(ITimeDeltaClass, timedelta)
|
||||
verifyClass(IDateClass, date)
|
||||
verifyClass(IDateTimeClass, datetime)
|
||||
verifyClass(ITimeClass, time)
|
20
lib/zope/interface/common/tests/test_import_interfaces.py
Normal file
20
lib/zope/interface/common/tests/test_import_interfaces.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
import unittest
|
||||
|
||||
class TestInterfaceImport(unittest.TestCase):
|
||||
|
||||
def test_import(self):
|
||||
import zope.interface.common.interfaces as x
|
||||
self.assertIsNotNone(x)
|
929
lib/zope/interface/declarations.py
Normal file
929
lib/zope/interface/declarations.py
Normal file
|
@ -0,0 +1,929 @@
|
|||
##############################################################################
|
||||
# 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 `~zope.interface.interfaces.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 (`~zope.interface.interfaces.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 (`~zope.interface.interfaces.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(object):
|
||||
"""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 (`~zope.interface.interfaces.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(object):
|
||||
"""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 (`~zope.interface.interfaces.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 (`~zope.interface.interfaces.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 (`~zope.interface.interfaces.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 (`~zope.interface.interfaces.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 (`~zope.interface.interfaces.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 `~zope.interface.interfaces.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
|
||||
(`~zope.interface.interfaces.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(object):
|
||||
"""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
|
||||
(`~zope.interface.interfaces.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()
|
120
lib/zope/interface/document.py
Normal file
120
lib/zope/interface/document.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" Pretty-Print an Interface object as structured text (Yum)
|
||||
|
||||
This module provides a function, asStructuredText, for rendering an
|
||||
interface as structured text.
|
||||
"""
|
||||
import zope.interface
|
||||
|
||||
|
||||
def asStructuredText(I, munge=0, rst=False):
|
||||
""" Output structured text format. Note, this will whack any existing
|
||||
'structured' format of the text.
|
||||
|
||||
If `rst=True`, then the output will quote all code as inline literals in
|
||||
accordance with 'reStructuredText' markup principles.
|
||||
"""
|
||||
|
||||
if rst:
|
||||
inline_literal = lambda s: "``%s``" % (s,)
|
||||
else:
|
||||
inline_literal = lambda s: s
|
||||
|
||||
r = [inline_literal(I.getName())]
|
||||
outp = r.append
|
||||
level = 1
|
||||
|
||||
if I.getDoc():
|
||||
outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level))
|
||||
|
||||
bases = [base
|
||||
for base in I.__bases__
|
||||
if base is not zope.interface.Interface
|
||||
]
|
||||
if bases:
|
||||
outp(_justify_and_indent("This interface extends:", level, munge))
|
||||
level += 1
|
||||
for b in bases:
|
||||
item = "o %s" % inline_literal(b.getName())
|
||||
outp(_justify_and_indent(_trim_doc_string(item), level, munge))
|
||||
level -= 1
|
||||
|
||||
namesAndDescriptions = sorted(I.namesAndDescriptions())
|
||||
|
||||
outp(_justify_and_indent("Attributes:", level, munge))
|
||||
level += 1
|
||||
for name, desc in namesAndDescriptions:
|
||||
if not hasattr(desc, 'getSignatureString'): # ugh...
|
||||
item = "%s -- %s" % (inline_literal(desc.getName()),
|
||||
desc.getDoc() or 'no documentation')
|
||||
outp(_justify_and_indent(_trim_doc_string(item), level, munge))
|
||||
level -= 1
|
||||
|
||||
outp(_justify_and_indent("Methods:", level, munge))
|
||||
level += 1
|
||||
for name, desc in namesAndDescriptions:
|
||||
if hasattr(desc, 'getSignatureString'): # ugh...
|
||||
_call = "%s%s" % (desc.getName(), desc.getSignatureString())
|
||||
item = "%s -- %s" % (inline_literal(_call),
|
||||
desc.getDoc() or 'no documentation')
|
||||
outp(_justify_and_indent(_trim_doc_string(item), level, munge))
|
||||
|
||||
return "\n\n".join(r) + "\n\n"
|
||||
|
||||
|
||||
def asReStructuredText(I, munge=0):
|
||||
""" Output reStructuredText format. Note, this will whack any existing
|
||||
'structured' format of the text."""
|
||||
return asStructuredText(I, munge=munge, rst=True)
|
||||
|
||||
|
||||
def _trim_doc_string(text):
|
||||
""" Trims a doc string to make it format
|
||||
correctly with structured text. """
|
||||
|
||||
lines = text.replace('\r\n', '\n').split('\n')
|
||||
nlines = [lines.pop(0)]
|
||||
if lines:
|
||||
min_indent = min([len(line) - len(line.lstrip())
|
||||
for line in lines])
|
||||
for line in lines:
|
||||
nlines.append(line[min_indent:])
|
||||
|
||||
return '\n'.join(nlines)
|
||||
|
||||
|
||||
def _justify_and_indent(text, level, munge=0, width=72):
|
||||
""" indent and justify text, rejustify (munge) if specified """
|
||||
|
||||
indent = " " * level
|
||||
|
||||
if munge:
|
||||
lines = []
|
||||
line = indent
|
||||
text = text.split()
|
||||
|
||||
for word in text:
|
||||
line = ' '.join([line, word])
|
||||
if len(line) > width:
|
||||
lines.append(line)
|
||||
line = indent
|
||||
else:
|
||||
lines.append(line)
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
else:
|
||||
return indent + \
|
||||
text.strip().replace("\r\n", "\n") .replace("\n", "\n" + indent)
|
67
lib/zope/interface/exceptions.py
Normal file
67
lib/zope/interface/exceptions.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 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-specific exceptions
|
||||
"""
|
||||
|
||||
class Invalid(Exception):
|
||||
"""A specification is violated
|
||||
"""
|
||||
|
||||
class DoesNotImplement(Invalid):
|
||||
""" This object does not implement """
|
||||
def __init__(self, interface):
|
||||
self.interface = interface
|
||||
|
||||
def __str__(self):
|
||||
return """An object does not implement interface %(interface)s
|
||||
|
||||
""" % self.__dict__
|
||||
|
||||
class BrokenImplementation(Invalid):
|
||||
"""An attribute is not completely implemented.
|
||||
"""
|
||||
|
||||
def __init__(self, interface, name):
|
||||
self.interface=interface
|
||||
self.name=name
|
||||
|
||||
def __str__(self):
|
||||
return """An object has failed to implement interface %(interface)s
|
||||
|
||||
The %(name)s attribute was not provided.
|
||||
""" % self.__dict__
|
||||
|
||||
class BrokenMethodImplementation(Invalid):
|
||||
"""An method is not completely implemented.
|
||||
"""
|
||||
|
||||
def __init__(self, method, mess):
|
||||
self.method=method
|
||||
self.mess=mess
|
||||
|
||||
def __str__(self):
|
||||
return """The implementation of %(method)s violates its contract
|
||||
because %(mess)s.
|
||||
""" % self.__dict__
|
||||
|
||||
class InvalidInterface(Exception):
|
||||
"""The interface has invalid contents
|
||||
"""
|
||||
|
||||
class BadImplements(TypeError):
|
||||
"""An implementation assertion is invalid
|
||||
|
||||
because it doesn't contain an interface or a sequence of valid
|
||||
implementation assertions.
|
||||
"""
|
687
lib/zope/interface/interface.py
Normal file
687
lib/zope/interface/interface.py
Normal file
|
@ -0,0 +1,687 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
"""
|
||||
from __future__ import generators
|
||||
|
||||
import sys
|
||||
from types import MethodType
|
||||
from types import FunctionType
|
||||
import warnings
|
||||
import weakref
|
||||
|
||||
from zope.interface.exceptions import Invalid
|
||||
from zope.interface.ro import ro
|
||||
|
||||
|
||||
CO_VARARGS = 4
|
||||
CO_VARKEYWORDS = 8
|
||||
TAGGED_DATA = '__interface_tagged_values__'
|
||||
|
||||
_decorator_non_return = 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__=''):
|
||||
if not __doc__ and __name__.find(' ') >= 0:
|
||||
__doc__ = __name__
|
||||
__name__ = None
|
||||
|
||||
self.__name__=__name__
|
||||
self.__doc__=__doc__
|
||||
self.__tagged_values = {}
|
||||
|
||||
def getName(self):
|
||||
""" Returns the name of the object. """
|
||||
return self.__name__
|
||||
|
||||
def getDoc(self):
|
||||
""" Returns the documentation for the object. """
|
||||
return self.__doc__
|
||||
|
||||
def getTaggedValue(self, tag):
|
||||
""" Returns the value associated with '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)
|
||||
|
||||
def getTaggedValueTags(self):
|
||||
""" Returns a list of all tags. """
|
||||
return self.__tagged_values.keys()
|
||||
|
||||
def setTaggedValue(self, tag, value):
|
||||
""" Associates 'value' with 'key'. """
|
||||
self.__tagged_values[tag] = value
|
||||
|
||||
class SpecificationBasePy(object):
|
||||
|
||||
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
|
||||
|
||||
__call__ = isOrExtends
|
||||
|
||||
SpecificationBase = SpecificationBasePy
|
||||
try:
|
||||
from zope.interface._zope_interface_coptimizations import SpecificationBase
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
_marker = object()
|
||||
class InterfaceBasePy(object):
|
||||
"""Base class that wants to be replaced with a C base :)
|
||||
"""
|
||||
|
||||
def __call__(self, obj, alternate=_marker):
|
||||
"""Adapt an object to the interface
|
||||
"""
|
||||
conform = getattr(obj, '__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
|
||||
elif alternate is not _marker:
|
||||
return alternate
|
||||
else:
|
||||
raise TypeError("Could not adapt", obj, self)
|
||||
|
||||
def __adapt__(self, obj):
|
||||
"""Adapt an object to the reciever
|
||||
"""
|
||||
if self.providedBy(obj):
|
||||
return obj
|
||||
|
||||
for hook in adapter_hooks:
|
||||
adapter = hook(self, obj)
|
||||
if adapter is not None:
|
||||
return adapter
|
||||
|
||||
|
||||
InterfaceBase = InterfaceBasePy
|
||||
try:
|
||||
from zope.interface._zope_interface_coptimizations import InterfaceBase
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
adapter_hooks = []
|
||||
try:
|
||||
from zope.interface._zope_interface_coptimizations import adapter_hooks
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
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).
|
||||
|
||||
Specifications are mutable. If you reassign their bases, their
|
||||
relations with other specifications are adjusted accordingly.
|
||||
"""
|
||||
|
||||
# Copy some base class methods for speed
|
||||
isOrExtends = SpecificationBase.isOrExtends
|
||||
providedBy = SpecificationBase.providedBy
|
||||
|
||||
def __init__(self, bases=()):
|
||||
self._implied = {}
|
||||
self.dependents = weakref.WeakKeyDictionary()
|
||||
self.__bases__ = tuple(bases)
|
||||
|
||||
def subscribe(self, dependent):
|
||||
self.dependents[dependent] = self.dependents.get(dependent, 0) + 1
|
||||
|
||||
def unsubscribe(self, dependent):
|
||||
n = self.dependents.get(dependent, 0) - 1
|
||||
if not n:
|
||||
del self.dependents[dependent]
|
||||
elif n > 0:
|
||||
self.dependents[dependent] = n
|
||||
else:
|
||||
raise KeyError(dependent)
|
||||
|
||||
def __setBases(self, bases):
|
||||
# Register ourselves as a dependent of our old bases
|
||||
for b in self.__bases__:
|
||||
b.unsubscribe(self)
|
||||
|
||||
# Register ourselves as a dependent of our bases
|
||||
self.__dict__['__bases__'] = bases
|
||||
for b in bases:
|
||||
b.subscribe(self)
|
||||
|
||||
self.changed(self)
|
||||
|
||||
__bases__ = property(
|
||||
|
||||
lambda self: self.__dict__.get('__bases__', ()),
|
||||
__setBases,
|
||||
)
|
||||
|
||||
def changed(self, originally_changed):
|
||||
"""We, or something we depend on, have changed
|
||||
"""
|
||||
try:
|
||||
del self._v_attrs
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
implied = self._implied
|
||||
implied.clear()
|
||||
|
||||
ancestors = ro(self)
|
||||
|
||||
try:
|
||||
if Interface not in ancestors:
|
||||
ancestors.append(Interface)
|
||||
except NameError:
|
||||
pass # defining Interface itself
|
||||
|
||||
self.__sro__ = tuple(ancestors)
|
||||
self.__iro__ = tuple([ancestor for ancestor in ancestors
|
||||
if isinstance(ancestor, InterfaceClass)
|
||||
])
|
||||
|
||||
for ancestor in ancestors:
|
||||
# We directly imply our ancestors:
|
||||
implied[ancestor] = ()
|
||||
|
||||
# Now, advise our dependents of change:
|
||||
for dependent in tuple(self.dependents.keys()):
|
||||
dependent.changed(originally_changed)
|
||||
|
||||
|
||||
def interfaces(self):
|
||||
"""Return an iterator for the interfaces in the specification.
|
||||
"""
|
||||
seen = {}
|
||||
for base in self.__bases__:
|
||||
for interface in base.interfaces():
|
||||
if interface not in seen:
|
||||
seen[interface] = 1
|
||||
yield interface
|
||||
|
||||
|
||||
def extends(self, interface, strict=True):
|
||||
"""Does the specification extend the given interface?
|
||||
|
||||
Test whether an interface in the specification extends the
|
||||
given interface
|
||||
"""
|
||||
return ((interface in self._implied)
|
||||
and
|
||||
((not strict) or (self != interface))
|
||||
)
|
||||
|
||||
def weakref(self, callback=None):
|
||||
return weakref.ref(self, callback)
|
||||
|
||||
def get(self, name, default=None):
|
||||
"""Query for an attribute description
|
||||
"""
|
||||
try:
|
||||
attrs = self._v_attrs
|
||||
except AttributeError:
|
||||
attrs = self._v_attrs = {}
|
||||
attr = attrs.get(name)
|
||||
if attr is None:
|
||||
for iface in self.__iro__:
|
||||
attr = iface.direct(name)
|
||||
if attr is not None:
|
||||
attrs[name] = attr
|
||||
break
|
||||
|
||||
if attr is None:
|
||||
return default
|
||||
else:
|
||||
return attr
|
||||
|
||||
class InterfaceClass(Element, InterfaceBase, Specification):
|
||||
"""Prototype (scarecrow) Interfaces Implementation."""
|
||||
|
||||
# We can't say this yet because we don't have enough
|
||||
# infrastructure in place.
|
||||
#
|
||||
#implements(IInterface)
|
||||
|
||||
def __init__(self, name, bases=(), attrs=None, __doc__=None,
|
||||
__module__=None):
|
||||
|
||||
if attrs is None:
|
||||
attrs = {}
|
||||
|
||||
if __module__ is None:
|
||||
__module__ = attrs.get('__module__')
|
||||
if isinstance(__module__, str):
|
||||
del attrs['__module__']
|
||||
else:
|
||||
try:
|
||||
# Figure out what module defined the interface.
|
||||
# This is how cPython figures out the module of
|
||||
# a class, but of course it does it in C. :-/
|
||||
__module__ = sys._getframe(1).f_globals['__name__']
|
||||
except (AttributeError, KeyError): # pragma: no cover
|
||||
pass
|
||||
|
||||
self.__module__ = __module__
|
||||
|
||||
d = attrs.get('__doc__')
|
||||
if d is not None:
|
||||
if not isinstance(d, Attribute):
|
||||
if __doc__ is None:
|
||||
__doc__ = d
|
||||
del attrs['__doc__']
|
||||
|
||||
if __doc__ is None:
|
||||
__doc__ = ''
|
||||
|
||||
Element.__init__(self, name, __doc__)
|
||||
|
||||
tagged_data = attrs.pop(TAGGED_DATA, None)
|
||||
if tagged_data is not None:
|
||||
for key, val in tagged_data.items():
|
||||
self.setTaggedValue(key, val)
|
||||
|
||||
for base in bases:
|
||||
if not isinstance(base, InterfaceClass):
|
||||
raise TypeError('Expected base interfaces')
|
||||
|
||||
Specification.__init__(self, bases)
|
||||
|
||||
# Make sure that all recorded attributes (and methods) are of type
|
||||
# `Attribute` and `Method`
|
||||
for name, attr in list(attrs.items()):
|
||||
if name in ('__locals__', '__qualname__', '__annotations__'):
|
||||
# __locals__: Python 3 sometimes adds this.
|
||||
# __qualname__: PEP 3155 (Python 3.3+)
|
||||
# __annotations__: PEP 3107 (Python 3.0+)
|
||||
del attrs[name]
|
||||
continue
|
||||
if isinstance(attr, Attribute):
|
||||
attr.interface = self
|
||||
if not attr.__name__:
|
||||
attr.__name__ = name
|
||||
elif isinstance(attr, FunctionType):
|
||||
attrs[name] = fromFunction(attr, self, name=name)
|
||||
elif attr is _decorator_non_return:
|
||||
del attrs[name]
|
||||
else:
|
||||
raise InvalidInterface("Concrete attribute, " + name)
|
||||
|
||||
self.__attrs = attrs
|
||||
|
||||
self.__identifier__ = "%s.%s" % (self.__module__, self.__name__)
|
||||
|
||||
def interfaces(self):
|
||||
"""Return an iterator for the interfaces in the specification.
|
||||
"""
|
||||
yield self
|
||||
|
||||
def getBases(self):
|
||||
return self.__bases__
|
||||
|
||||
def isEqualOrExtendedBy(self, other):
|
||||
"""Same interface or extends?"""
|
||||
return self == other or other.extends(self)
|
||||
|
||||
def names(self, all=False):
|
||||
"""Return the attribute names defined by the interface."""
|
||||
if not all:
|
||||
return self.__attrs.keys()
|
||||
|
||||
r = self.__attrs.copy()
|
||||
|
||||
for base in self.__bases__:
|
||||
r.update(dict.fromkeys(base.names(all)))
|
||||
|
||||
return r.keys()
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.names(all=True))
|
||||
|
||||
def namesAndDescriptions(self, all=False):
|
||||
"""Return attribute names and descriptions defined by interface."""
|
||||
if not all:
|
||||
return self.__attrs.items()
|
||||
|
||||
r = {}
|
||||
for base in self.__bases__[::-1]:
|
||||
r.update(dict(base.namesAndDescriptions(all)))
|
||||
|
||||
r.update(self.__attrs)
|
||||
|
||||
return r.items()
|
||||
|
||||
def getDescriptionFor(self, name):
|
||||
"""Return the attribute description for the given name."""
|
||||
r = self.get(name)
|
||||
if r is not None:
|
||||
return r
|
||||
|
||||
raise KeyError(name)
|
||||
|
||||
__getitem__ = getDescriptionFor
|
||||
|
||||
def __contains__(self, name):
|
||||
return self.get(name) is not None
|
||||
|
||||
def direct(self, name):
|
||||
return self.__attrs.get(name)
|
||||
|
||||
def queryDescriptionFor(self, name, default=None):
|
||||
return self.get(name, default)
|
||||
|
||||
def validateInvariants(self, obj, errors=None):
|
||||
"""validate object to defined invariants."""
|
||||
for call in self.queryTaggedValue('invariants', []):
|
||||
try:
|
||||
call(obj)
|
||||
except Invalid as e:
|
||||
if errors is None:
|
||||
raise
|
||||
else:
|
||||
errors.append(e)
|
||||
for base in self.__bases__:
|
||||
try:
|
||||
base.validateInvariants(obj, errors)
|
||||
except Invalid:
|
||||
if errors is None:
|
||||
raise
|
||||
if errors:
|
||||
raise Invalid(errors)
|
||||
|
||||
def __repr__(self): # pragma: no cover
|
||||
try:
|
||||
return self._v_repr
|
||||
except AttributeError:
|
||||
name = self.__name__
|
||||
m = self.__module__
|
||||
if m:
|
||||
name = '%s.%s' % (m, name)
|
||||
r = "<%s %s>" % (self.__class__.__name__, name)
|
||||
self._v_repr = r
|
||||
return r
|
||||
|
||||
def _call_conform(self, conform):
|
||||
try:
|
||||
return conform(self)
|
||||
except TypeError: # pragma: no cover
|
||||
# We got a TypeError. It might be an error raised by
|
||||
# the __conform__ implementation, or *we* may have
|
||||
# made the TypeError by calling an unbound method
|
||||
# (object is a class). In the later case, we behave
|
||||
# as though there is no __conform__ method. We can
|
||||
# detect this case by checking whether there is more
|
||||
# than one traceback object in the traceback chain:
|
||||
if sys.exc_info()[2].tb_next is not None:
|
||||
# There is more than one entry in the chain, so
|
||||
# reraise the error:
|
||||
raise
|
||||
# This clever trick is from Phillip Eby
|
||||
|
||||
return None # pragma: no cover
|
||||
|
||||
def __reduce__(self):
|
||||
return self.__name__
|
||||
|
||||
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__.
|
||||
# I don't want to override __eq__ because I want the default
|
||||
# __eq__, which is really fast.
|
||||
"""Make interfaces sortable
|
||||
|
||||
TODO: It would ne nice if:
|
||||
|
||||
More specific interfaces should sort before less specific ones.
|
||||
Otherwise, sort on name and module.
|
||||
|
||||
But this is too complicated, and we're going to punt on it
|
||||
for now.
|
||||
|
||||
For now, sort on interface and module name.
|
||||
|
||||
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 None:
|
||||
return -1
|
||||
|
||||
n1 = (getattr(self, '__name__', ''), getattr(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):
|
||||
d = self.__dict__
|
||||
if '__module__' not in d or '__name__' not in d: # pragma: no cover
|
||||
warnings.warn('Hashing uninitialized InterfaceClass instance')
|
||||
return 1
|
||||
return hash((self.__name__, self.__module__))
|
||||
|
||||
def __eq__(self, other):
|
||||
c = self.__cmp(other)
|
||||
return c == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
c = self.__cmp(other)
|
||||
return c != 0
|
||||
|
||||
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
|
||||
|
||||
|
||||
Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
|
||||
|
||||
class Attribute(Element):
|
||||
"""Attribute descriptions
|
||||
"""
|
||||
|
||||
# We can't say this yet because we don't have enough
|
||||
# infrastructure in place.
|
||||
#
|
||||
# implements(IAttribute)
|
||||
|
||||
interface = None
|
||||
|
||||
|
||||
class Method(Attribute):
|
||||
"""Method interfaces
|
||||
|
||||
The idea here is that you have objects that describe methods.
|
||||
This provides an opportunity for rich meta-data.
|
||||
"""
|
||||
|
||||
# We can't say this yet because we don't have enough
|
||||
# infrastructure in place.
|
||||
#
|
||||
# implements(IMethod)
|
||||
|
||||
positional = required = ()
|
||||
_optional = varargs = kwargs = None
|
||||
def _get_optional(self):
|
||||
if self._optional is None:
|
||||
return {}
|
||||
return self._optional
|
||||
def _set_optional(self, opt):
|
||||
self._optional = opt
|
||||
def _del_optional(self):
|
||||
self._optional = None
|
||||
optional = property(_get_optional, _set_optional, _del_optional)
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
raise BrokenImplementation(self.interface, self.__name__)
|
||||
|
||||
def getSignatureInfo(self):
|
||||
return {'positional': self.positional,
|
||||
'required': self.required,
|
||||
'optional': self.optional,
|
||||
'varargs': self.varargs,
|
||||
'kwargs': self.kwargs,
|
||||
}
|
||||
|
||||
def getSignatureString(self):
|
||||
sig = []
|
||||
for v in self.positional:
|
||||
sig.append(v)
|
||||
if v in self.optional.keys():
|
||||
sig[-1] += "=" + repr(self.optional[v])
|
||||
if self.varargs:
|
||||
sig.append("*" + self.varargs)
|
||||
if self.kwargs:
|
||||
sig.append("**" + self.kwargs)
|
||||
|
||||
return "(%s)" % ", ".join(sig)
|
||||
|
||||
def fromFunction(func, interface=None, imlevel=0, name=None):
|
||||
name = name or func.__name__
|
||||
method = Method(name, func.__doc__)
|
||||
defaults = getattr(func, '__defaults__', None) or ()
|
||||
code = func.__code__
|
||||
# Number of positional arguments
|
||||
na = code.co_argcount-imlevel
|
||||
names = code.co_varnames[imlevel:]
|
||||
opt = {}
|
||||
# Number of required arguments
|
||||
nr = na-len(defaults)
|
||||
if nr < 0:
|
||||
defaults=defaults[-nr:]
|
||||
nr = 0
|
||||
|
||||
# Determine the optional arguments.
|
||||
opt.update(dict(zip(names[nr:], defaults)))
|
||||
|
||||
method.positional = names[:na]
|
||||
method.required = names[:nr]
|
||||
method.optional = opt
|
||||
|
||||
argno = na
|
||||
|
||||
# Determine the function's variable argument's name (i.e. *args)
|
||||
if code.co_flags & CO_VARARGS:
|
||||
method.varargs = names[argno]
|
||||
argno = argno + 1
|
||||
else:
|
||||
method.varargs = None
|
||||
|
||||
# Determine the function's keyword argument's name (i.e. **kw)
|
||||
if code.co_flags & CO_VARKEYWORDS:
|
||||
method.kwargs = names[argno]
|
||||
else:
|
||||
method.kwargs = None
|
||||
|
||||
method.interface = interface
|
||||
|
||||
for key, value in func.__dict__.items():
|
||||
method.setTaggedValue(key, value)
|
||||
|
||||
return method
|
||||
|
||||
|
||||
def fromMethod(meth, interface=None, name=None):
|
||||
if isinstance(meth, MethodType):
|
||||
func = meth.__func__
|
||||
else:
|
||||
func = meth
|
||||
return fromFunction(func, interface, imlevel=1, name=name)
|
||||
|
||||
|
||||
# Now we can create the interesting interfaces and wire them up:
|
||||
def _wire():
|
||||
from zope.interface.declarations import classImplements
|
||||
|
||||
from zope.interface.interfaces import IAttribute
|
||||
classImplements(Attribute, IAttribute)
|
||||
|
||||
from zope.interface.interfaces import IMethod
|
||||
classImplements(Method, IMethod)
|
||||
|
||||
from zope.interface.interfaces import IInterface
|
||||
classImplements(InterfaceClass, IInterface)
|
||||
|
||||
from zope.interface.interfaces import ISpecification
|
||||
classImplements(Specification, ISpecification)
|
||||
|
||||
# We import this here to deal with module dependencies.
|
||||
from zope.interface.declarations import implementedBy
|
||||
from zope.interface.declarations import providedBy
|
||||
from zope.interface.exceptions import InvalidInterface
|
||||
from zope.interface.exceptions import BrokenImplementation
|
1282
lib/zope/interface/interfaces.py
Normal file
1282
lib/zope/interface/interfaces.py
Normal file
File diff suppressed because it is too large
Load diff
654
lib/zope/interface/registry.py
Normal file
654
lib/zope/interface/registry.py
Normal file
|
@ -0,0 +1,654 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Basic components support
|
||||
"""
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
from zope.event import notify
|
||||
except ImportError: # pragma: no cover
|
||||
def notify(*arg, **kw): pass
|
||||
|
||||
from zope.interface.interfaces import ISpecification
|
||||
from zope.interface.interfaces import ComponentLookupError
|
||||
from zope.interface.interfaces import IAdapterRegistration
|
||||
from zope.interface.interfaces import IComponents
|
||||
from zope.interface.interfaces import IHandlerRegistration
|
||||
from zope.interface.interfaces import ISubscriptionAdapterRegistration
|
||||
from zope.interface.interfaces import IUtilityRegistration
|
||||
from zope.interface.interfaces import Registered
|
||||
from zope.interface.interfaces import Unregistered
|
||||
|
||||
from zope.interface.interface import Interface
|
||||
from zope.interface.declarations import implementedBy
|
||||
from zope.interface.declarations import implementer
|
||||
from zope.interface.declarations import implementer_only
|
||||
from zope.interface.declarations import providedBy
|
||||
from zope.interface.adapter import AdapterRegistry
|
||||
from zope.interface._compat import CLASS_TYPES
|
||||
from zope.interface._compat import STRING_TYPES
|
||||
|
||||
|
||||
class _UnhashableComponentCounter(object):
|
||||
# defaultdict(int)-like object for unhashable components
|
||||
|
||||
def __init__(self, otherdict):
|
||||
# [(component, count)]
|
||||
self._data = [item for item in otherdict.items()]
|
||||
|
||||
def __getitem__(self, key):
|
||||
for component, count in self._data:
|
||||
if component == key:
|
||||
return count
|
||||
return 0
|
||||
|
||||
def __setitem__(self, component, count):
|
||||
for i, data in enumerate(self._data):
|
||||
if data[0] == component:
|
||||
self._data[i] = component, count
|
||||
return
|
||||
self._data.append((component, count))
|
||||
|
||||
def __delitem__(self, component):
|
||||
for i, data in enumerate(self._data):
|
||||
if data[0] == component:
|
||||
del self._data[i]
|
||||
return
|
||||
raise KeyError(component) # pragma: no cover
|
||||
|
||||
def _defaultdict_int():
|
||||
return defaultdict(int)
|
||||
|
||||
class _UtilityRegistrations(object):
|
||||
|
||||
def __init__(self, utilities, utility_registrations):
|
||||
# {provided -> {component: count}}
|
||||
self._cache = defaultdict(_defaultdict_int)
|
||||
self._utilities = utilities
|
||||
self._utility_registrations = utility_registrations
|
||||
|
||||
self.__populate_cache()
|
||||
|
||||
def __populate_cache(self):
|
||||
for ((p, _), data) in iter(self._utility_registrations.items()):
|
||||
component = data[0]
|
||||
self.__cache_utility(p, component)
|
||||
|
||||
def __cache_utility(self, provided, component):
|
||||
try:
|
||||
self._cache[provided][component] += 1
|
||||
except TypeError:
|
||||
# The component is not hashable, and we have a dict. Switch to a strategy
|
||||
# that doesn't use hashing.
|
||||
prov = self._cache[provided] = _UnhashableComponentCounter(self._cache[provided])
|
||||
prov[component] += 1
|
||||
|
||||
def __uncache_utility(self, provided, component):
|
||||
provided = self._cache[provided]
|
||||
# It seems like this line could raise a TypeError if component isn't
|
||||
# hashable and we haven't yet switched to _UnhashableComponentCounter. However,
|
||||
# we can't actually get in that situation. In order to get here, we would
|
||||
# have had to cache the utility already which would have switched
|
||||
# the datastructure if needed.
|
||||
count = provided[component]
|
||||
count -= 1
|
||||
if count == 0:
|
||||
del provided[component]
|
||||
else:
|
||||
provided[component] = count
|
||||
return count > 0
|
||||
|
||||
def _is_utility_subscribed(self, provided, component):
|
||||
try:
|
||||
return self._cache[provided][component] > 0
|
||||
except TypeError:
|
||||
# Not hashable and we're still using a dict
|
||||
return False
|
||||
|
||||
def registerUtility(self, provided, name, component, info, factory):
|
||||
subscribed = self._is_utility_subscribed(provided, component)
|
||||
|
||||
self._utility_registrations[(provided, name)] = component, info, factory
|
||||
self._utilities.register((), provided, name, component)
|
||||
|
||||
if not subscribed:
|
||||
self._utilities.subscribe((), provided, component)
|
||||
|
||||
self.__cache_utility(provided, component)
|
||||
|
||||
def unregisterUtility(self, provided, name, component):
|
||||
del self._utility_registrations[(provided, name)]
|
||||
self._utilities.unregister((), provided, name)
|
||||
|
||||
subscribed = self.__uncache_utility(provided, component)
|
||||
|
||||
if not subscribed:
|
||||
self._utilities.unsubscribe((), provided, component)
|
||||
|
||||
|
||||
@implementer(IComponents)
|
||||
class Components(object):
|
||||
|
||||
_v_utility_registrations_cache = None
|
||||
|
||||
def __init__(self, name='', bases=()):
|
||||
# __init__ is used for test cleanup as well as initialization.
|
||||
# XXX add a separate API for test cleanup.
|
||||
assert isinstance(name, STRING_TYPES)
|
||||
self.__name__ = name
|
||||
self._init_registries()
|
||||
self._init_registrations()
|
||||
self.__bases__ = tuple(bases)
|
||||
self._v_utility_registrations_cache = None
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (self.__class__.__name__, self.__name__)
|
||||
|
||||
def __reduce__(self):
|
||||
# Mimic what a persistent.Persistent object does and elide
|
||||
# _v_ attributes so that they don't get saved in ZODB.
|
||||
# This allows us to store things that cannot be pickled in such
|
||||
# attributes.
|
||||
reduction = super(Components, self).__reduce__()
|
||||
# (callable, args, state, listiter, dictiter)
|
||||
# We assume the state is always a dict; the last three items
|
||||
# are technically optional and can be missing or None.
|
||||
filtered_state = {k: v for k, v in reduction[2].items()
|
||||
if not k.startswith('_v_')}
|
||||
reduction = list(reduction)
|
||||
reduction[2] = filtered_state
|
||||
return tuple(reduction)
|
||||
|
||||
def _init_registries(self):
|
||||
# Subclasses have never been required to call this method
|
||||
# if they override it, merely to fill in these two attributes.
|
||||
self.adapters = AdapterRegistry()
|
||||
self.utilities = AdapterRegistry()
|
||||
|
||||
def _init_registrations(self):
|
||||
self._utility_registrations = {}
|
||||
self._adapter_registrations = {}
|
||||
self._subscription_registrations = []
|
||||
self._handler_registrations = []
|
||||
|
||||
@property
|
||||
def _utility_registrations_cache(self):
|
||||
# We use a _v_ attribute internally so that data aren't saved in ZODB,
|
||||
# because this object cannot be pickled.
|
||||
cache = self._v_utility_registrations_cache
|
||||
if (cache is None
|
||||
or cache._utilities is not self.utilities
|
||||
or cache._utility_registrations is not self._utility_registrations):
|
||||
cache = self._v_utility_registrations_cache = _UtilityRegistrations(
|
||||
self.utilities,
|
||||
self._utility_registrations)
|
||||
return cache
|
||||
|
||||
def _getBases(self):
|
||||
# Subclasses might override
|
||||
return self.__dict__.get('__bases__', ())
|
||||
|
||||
def _setBases(self, bases):
|
||||
# Subclasses might override
|
||||
self.adapters.__bases__ = tuple([
|
||||
base.adapters for base in bases])
|
||||
self.utilities.__bases__ = tuple([
|
||||
base.utilities for base in bases])
|
||||
self.__dict__['__bases__'] = tuple(bases)
|
||||
|
||||
__bases__ = property(
|
||||
lambda self: self._getBases(),
|
||||
lambda self, bases: self._setBases(bases),
|
||||
)
|
||||
|
||||
def registerUtility(self, component=None, provided=None, name=u'',
|
||||
info=u'', event=True, factory=None):
|
||||
if factory:
|
||||
if component:
|
||||
raise TypeError("Can't specify factory and component.")
|
||||
component = factory()
|
||||
|
||||
if provided is None:
|
||||
provided = _getUtilityProvided(component)
|
||||
|
||||
if name == u'':
|
||||
name = _getName(component)
|
||||
|
||||
reg = self._utility_registrations.get((provided, name))
|
||||
if reg is not None:
|
||||
if reg[:2] == (component, info):
|
||||
# already registered
|
||||
return
|
||||
self.unregisterUtility(reg[0], provided, name)
|
||||
|
||||
self._utility_registrations_cache.registerUtility(
|
||||
provided, name, component, info, factory)
|
||||
|
||||
if event:
|
||||
notify(Registered(
|
||||
UtilityRegistration(self, provided, name, component, info,
|
||||
factory)
|
||||
))
|
||||
|
||||
def unregisterUtility(self, component=None, provided=None, name=u'',
|
||||
factory=None):
|
||||
if factory:
|
||||
if component:
|
||||
raise TypeError("Can't specify factory and component.")
|
||||
component = factory()
|
||||
|
||||
if provided is None:
|
||||
if component is None:
|
||||
raise TypeError("Must specify one of component, factory and "
|
||||
"provided")
|
||||
provided = _getUtilityProvided(component)
|
||||
|
||||
old = self._utility_registrations.get((provided, name))
|
||||
if (old is None) or ((component is not None) and
|
||||
(component != old[0])):
|
||||
return False
|
||||
|
||||
if component is None:
|
||||
component = old[0]
|
||||
|
||||
# Note that component is now the old thing registered
|
||||
self._utility_registrations_cache.unregisterUtility(
|
||||
provided, name, component)
|
||||
|
||||
notify(Unregistered(
|
||||
UtilityRegistration(self, provided, name, component, *old[1:])
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
def registeredUtilities(self):
|
||||
for ((provided, name), data
|
||||
) in iter(self._utility_registrations.items()):
|
||||
yield UtilityRegistration(self, provided, name, *data)
|
||||
|
||||
def queryUtility(self, provided, name=u'', default=None):
|
||||
return self.utilities.lookup((), provided, name, default)
|
||||
|
||||
def getUtility(self, provided, name=u''):
|
||||
utility = self.utilities.lookup((), provided, name)
|
||||
if utility is None:
|
||||
raise ComponentLookupError(provided, name)
|
||||
return utility
|
||||
|
||||
def getUtilitiesFor(self, interface):
|
||||
for name, utility in self.utilities.lookupAll((), interface):
|
||||
yield name, utility
|
||||
|
||||
def getAllUtilitiesRegisteredFor(self, interface):
|
||||
return self.utilities.subscriptions((), interface)
|
||||
|
||||
def registerAdapter(self, factory, required=None, provided=None,
|
||||
name=u'', info=u'', event=True):
|
||||
if provided is None:
|
||||
provided = _getAdapterProvided(factory)
|
||||
required = _getAdapterRequired(factory, required)
|
||||
if name == u'':
|
||||
name = _getName(factory)
|
||||
self._adapter_registrations[(required, provided, name)
|
||||
] = factory, info
|
||||
self.adapters.register(required, provided, name, factory)
|
||||
|
||||
if event:
|
||||
notify(Registered(
|
||||
AdapterRegistration(self, required, provided, name,
|
||||
factory, info)
|
||||
))
|
||||
|
||||
|
||||
def unregisterAdapter(self, factory=None,
|
||||
required=None, provided=None, name=u'',
|
||||
):
|
||||
if provided is None:
|
||||
if factory is None:
|
||||
raise TypeError("Must specify one of factory and provided")
|
||||
provided = _getAdapterProvided(factory)
|
||||
|
||||
if (required is None) and (factory is None):
|
||||
raise TypeError("Must specify one of factory and required")
|
||||
|
||||
required = _getAdapterRequired(factory, required)
|
||||
old = self._adapter_registrations.get((required, provided, name))
|
||||
if (old is None) or ((factory is not None) and
|
||||
(factory != old[0])):
|
||||
return False
|
||||
|
||||
del self._adapter_registrations[(required, provided, name)]
|
||||
self.adapters.unregister(required, provided, name)
|
||||
|
||||
notify(Unregistered(
|
||||
AdapterRegistration(self, required, provided, name,
|
||||
*old)
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
def registeredAdapters(self):
|
||||
for ((required, provided, name), (component, info)
|
||||
) in iter(self._adapter_registrations.items()):
|
||||
yield AdapterRegistration(self, required, provided, name,
|
||||
component, info)
|
||||
|
||||
def queryAdapter(self, object, interface, name=u'', default=None):
|
||||
return self.adapters.queryAdapter(object, interface, name, default)
|
||||
|
||||
def getAdapter(self, object, interface, name=u''):
|
||||
adapter = self.adapters.queryAdapter(object, interface, name)
|
||||
if adapter is None:
|
||||
raise ComponentLookupError(object, interface, name)
|
||||
return adapter
|
||||
|
||||
def queryMultiAdapter(self, objects, interface, name=u'',
|
||||
default=None):
|
||||
return self.adapters.queryMultiAdapter(
|
||||
objects, interface, name, default)
|
||||
|
||||
def getMultiAdapter(self, objects, interface, name=u''):
|
||||
adapter = self.adapters.queryMultiAdapter(objects, interface, name)
|
||||
if adapter is None:
|
||||
raise ComponentLookupError(objects, interface, name)
|
||||
return adapter
|
||||
|
||||
def getAdapters(self, objects, provided):
|
||||
for name, factory in self.adapters.lookupAll(
|
||||
list(map(providedBy, objects)),
|
||||
provided):
|
||||
adapter = factory(*objects)
|
||||
if adapter is not None:
|
||||
yield name, adapter
|
||||
|
||||
def registerSubscriptionAdapter(self,
|
||||
factory, required=None, provided=None,
|
||||
name=u'', info=u'',
|
||||
event=True):
|
||||
if name:
|
||||
raise TypeError("Named subscribers are not yet supported")
|
||||
if provided is None:
|
||||
provided = _getAdapterProvided(factory)
|
||||
required = _getAdapterRequired(factory, required)
|
||||
self._subscription_registrations.append(
|
||||
(required, provided, name, factory, info)
|
||||
)
|
||||
self.adapters.subscribe(required, provided, factory)
|
||||
|
||||
if event:
|
||||
notify(Registered(
|
||||
SubscriptionRegistration(self, required, provided, name,
|
||||
factory, info)
|
||||
))
|
||||
|
||||
def registeredSubscriptionAdapters(self):
|
||||
for data in self._subscription_registrations:
|
||||
yield SubscriptionRegistration(self, *data)
|
||||
|
||||
def unregisterSubscriptionAdapter(self, factory=None,
|
||||
required=None, provided=None, name=u'',
|
||||
):
|
||||
if name:
|
||||
raise TypeError("Named subscribers are not yet supported")
|
||||
if provided is None:
|
||||
if factory is None:
|
||||
raise TypeError("Must specify one of factory and provided")
|
||||
provided = _getAdapterProvided(factory)
|
||||
|
||||
if (required is None) and (factory is None):
|
||||
raise TypeError("Must specify one of factory and required")
|
||||
|
||||
required = _getAdapterRequired(factory, required)
|
||||
|
||||
if factory is None:
|
||||
new = [(r, p, n, f, i)
|
||||
for (r, p, n, f, i)
|
||||
in self._subscription_registrations
|
||||
if not (r == required and p == provided)
|
||||
]
|
||||
else:
|
||||
new = [(r, p, n, f, i)
|
||||
for (r, p, n, f, i)
|
||||
in self._subscription_registrations
|
||||
if not (r == required and p == provided and f == factory)
|
||||
]
|
||||
|
||||
if len(new) == len(self._subscription_registrations):
|
||||
return False
|
||||
|
||||
|
||||
self._subscription_registrations[:] = new
|
||||
self.adapters.unsubscribe(required, provided, factory)
|
||||
|
||||
notify(Unregistered(
|
||||
SubscriptionRegistration(self, required, provided, name,
|
||||
factory, '')
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
def subscribers(self, objects, provided):
|
||||
return self.adapters.subscribers(objects, provided)
|
||||
|
||||
def registerHandler(self,
|
||||
factory, required=None,
|
||||
name=u'', info=u'',
|
||||
event=True):
|
||||
if name:
|
||||
raise TypeError("Named handlers are not yet supported")
|
||||
required = _getAdapterRequired(factory, required)
|
||||
self._handler_registrations.append(
|
||||
(required, name, factory, info)
|
||||
)
|
||||
self.adapters.subscribe(required, None, factory)
|
||||
|
||||
if event:
|
||||
notify(Registered(
|
||||
HandlerRegistration(self, required, name, factory, info)
|
||||
))
|
||||
|
||||
def registeredHandlers(self):
|
||||
for data in self._handler_registrations:
|
||||
yield HandlerRegistration(self, *data)
|
||||
|
||||
def unregisterHandler(self, factory=None, required=None, name=u''):
|
||||
if name:
|
||||
raise TypeError("Named subscribers are not yet supported")
|
||||
|
||||
if (required is None) and (factory is None):
|
||||
raise TypeError("Must specify one of factory and required")
|
||||
|
||||
required = _getAdapterRequired(factory, required)
|
||||
|
||||
if factory is None:
|
||||
new = [(r, n, f, i)
|
||||
for (r, n, f, i)
|
||||
in self._handler_registrations
|
||||
if r != required
|
||||
]
|
||||
else:
|
||||
new = [(r, n, f, i)
|
||||
for (r, n, f, i)
|
||||
in self._handler_registrations
|
||||
if not (r == required and f == factory)
|
||||
]
|
||||
|
||||
if len(new) == len(self._handler_registrations):
|
||||
return False
|
||||
|
||||
self._handler_registrations[:] = new
|
||||
self.adapters.unsubscribe(required, None, factory)
|
||||
|
||||
notify(Unregistered(
|
||||
HandlerRegistration(self, required, name, factory, '')
|
||||
))
|
||||
|
||||
return True
|
||||
|
||||
def handle(self, *objects):
|
||||
self.adapters.subscribers(objects, None)
|
||||
|
||||
|
||||
def _getName(component):
|
||||
try:
|
||||
return component.__component_name__
|
||||
except AttributeError:
|
||||
return u''
|
||||
|
||||
def _getUtilityProvided(component):
|
||||
provided = list(providedBy(component))
|
||||
if len(provided) == 1:
|
||||
return provided[0]
|
||||
raise TypeError(
|
||||
"The utility doesn't provide a single interface "
|
||||
"and no provided interface was specified.")
|
||||
|
||||
def _getAdapterProvided(factory):
|
||||
provided = list(implementedBy(factory))
|
||||
if len(provided) == 1:
|
||||
return provided[0]
|
||||
raise TypeError(
|
||||
"The adapter factory doesn't implement a single interface "
|
||||
"and no provided interface was specified.")
|
||||
|
||||
def _getAdapterRequired(factory, required):
|
||||
if required is None:
|
||||
try:
|
||||
required = factory.__component_adapts__
|
||||
except AttributeError:
|
||||
raise TypeError(
|
||||
"The adapter factory doesn't have a __component_adapts__ "
|
||||
"attribute and no required specifications were specified"
|
||||
)
|
||||
elif ISpecification.providedBy(required):
|
||||
raise TypeError("the required argument should be a list of "
|
||||
"interfaces, not a single interface")
|
||||
|
||||
result = []
|
||||
for r in required:
|
||||
if r is None:
|
||||
r = Interface
|
||||
elif not ISpecification.providedBy(r):
|
||||
if isinstance(r, CLASS_TYPES):
|
||||
r = implementedBy(r)
|
||||
else:
|
||||
raise TypeError("Required specification must be a "
|
||||
"specification or class."
|
||||
)
|
||||
result.append(r)
|
||||
return tuple(result)
|
||||
|
||||
|
||||
@implementer(IUtilityRegistration)
|
||||
class UtilityRegistration(object):
|
||||
|
||||
def __init__(self, registry, provided, name, component, doc, factory=None):
|
||||
(self.registry, self.provided, self.name, self.component, self.info,
|
||||
self.factory
|
||||
) = registry, provided, name, component, doc, factory
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %s, %r, %s, %r, %r)' % (
|
||||
self.__class__.__name__,
|
||||
self.registry,
|
||||
getattr(self.provided, '__name__', None), self.name,
|
||||
getattr(self.component, '__name__', repr(self.component)),
|
||||
self.factory, self.info,
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
return repr(self) == repr(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return repr(self) != repr(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
return repr(self) < repr(other)
|
||||
|
||||
def __le__(self, other):
|
||||
return repr(self) <= repr(other)
|
||||
|
||||
def __gt__(self, other):
|
||||
return repr(self) > repr(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return repr(self) >= repr(other)
|
||||
|
||||
@implementer(IAdapterRegistration)
|
||||
class AdapterRegistration(object):
|
||||
|
||||
def __init__(self, registry, required, provided, name, component, doc):
|
||||
(self.registry, self.required, self.provided, self.name,
|
||||
self.factory, self.info
|
||||
) = registry, required, provided, name, component, doc
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %s, %s, %r, %s, %r)' % (
|
||||
self.__class__.__name__,
|
||||
self.registry,
|
||||
'[' + ", ".join([r.__name__ for r in self.required]) + ']',
|
||||
getattr(self.provided, '__name__', None), self.name,
|
||||
getattr(self.factory, '__name__', repr(self.factory)), self.info,
|
||||
)
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
return repr(self) == repr(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return repr(self) != repr(other)
|
||||
|
||||
def __lt__(self, other):
|
||||
return repr(self) < repr(other)
|
||||
|
||||
def __le__(self, other):
|
||||
return repr(self) <= repr(other)
|
||||
|
||||
def __gt__(self, other):
|
||||
return repr(self) > repr(other)
|
||||
|
||||
def __ge__(self, other):
|
||||
return repr(self) >= repr(other)
|
||||
|
||||
@implementer_only(ISubscriptionAdapterRegistration)
|
||||
class SubscriptionRegistration(AdapterRegistration):
|
||||
pass
|
||||
|
||||
|
||||
@implementer_only(IHandlerRegistration)
|
||||
class HandlerRegistration(AdapterRegistration):
|
||||
|
||||
def __init__(self, registry, required, name, handler, doc):
|
||||
(self.registry, self.required, self.name, self.handler, self.info
|
||||
) = registry, required, name, handler, doc
|
||||
|
||||
@property
|
||||
def factory(self):
|
||||
return self.handler
|
||||
|
||||
provided = None
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %s, %r, %s, %r)' % (
|
||||
self.__class__.__name__,
|
||||
self.registry,
|
||||
'[' + ", ".join([r.__name__ for r in self.required]) + ']',
|
||||
self.name,
|
||||
getattr(self.factory, '__name__', repr(self.factory)), self.info,
|
||||
)
|
64
lib/zope/interface/ro.py
Normal file
64
lib/zope/interface/ro.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Compute a resolution order for an object and its bases
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
def _mergeOrderings(orderings):
|
||||
"""Merge multiple orderings so that within-ordering order is preserved
|
||||
|
||||
Orderings are constrained in such a way that if an object appears
|
||||
in two or more orderings, then the suffix that begins with the
|
||||
object must be in both orderings.
|
||||
|
||||
For example:
|
||||
|
||||
>>> _mergeOrderings([
|
||||
... ['x', 'y', 'z'],
|
||||
... ['q', 'z'],
|
||||
... [1, 3, 5],
|
||||
... ['z']
|
||||
... ])
|
||||
['x', 'y', 'q', 1, 3, 5, 'z']
|
||||
|
||||
"""
|
||||
|
||||
seen = {}
|
||||
result = []
|
||||
for ordering in reversed(orderings):
|
||||
for o in reversed(ordering):
|
||||
if o not in seen:
|
||||
seen[o] = 1
|
||||
result.insert(0, o)
|
||||
|
||||
return result
|
||||
|
||||
def _flatten(ob):
|
||||
result = [ob]
|
||||
i = 0
|
||||
for ob in iter(result):
|
||||
i += 1
|
||||
# The recursive calls can be avoided by inserting the base classes
|
||||
# into the dynamically growing list directly after the currently
|
||||
# considered object; the iterator makes sure this will keep working
|
||||
# in the future, since it cannot rely on the length of the list
|
||||
# by definition.
|
||||
result[i:i] = ob.__bases__
|
||||
return result
|
||||
|
||||
|
||||
def ro(object):
|
||||
"""Compute a "resolution order" for an object
|
||||
"""
|
||||
return _mergeOrderings([_flatten(object)])
|
1
lib/zope/interface/tests/__init__.py
Normal file
1
lib/zope/interface/tests/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
# Make this directory a package.
|
42
lib/zope/interface/tests/advisory_testing.py
Normal file
42
lib/zope/interface/tests/advisory_testing.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
import sys
|
||||
|
||||
from zope.interface.advice import addClassAdvisor
|
||||
from zope.interface.advice import getFrameInfo
|
||||
|
||||
my_globals = globals()
|
||||
|
||||
def ping(log, value):
|
||||
|
||||
def pong(klass):
|
||||
log.append((value,klass))
|
||||
return [klass]
|
||||
|
||||
addClassAdvisor(pong)
|
||||
|
||||
try:
|
||||
from types import ClassType
|
||||
|
||||
class ClassicClass:
|
||||
__metaclass__ = ClassType
|
||||
classLevelFrameInfo = getFrameInfo(sys._getframe())
|
||||
except ImportError:
|
||||
ClassicClass = None
|
||||
|
||||
class NewStyleClass:
|
||||
__metaclass__ = type
|
||||
classLevelFrameInfo = getFrameInfo(sys._getframe())
|
||||
|
||||
moduleLevelFrameInfo = getFrameInfo(sys._getframe())
|
23
lib/zope/interface/tests/dummy.py
Normal file
23
lib/zope/interface/tests/dummy.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" Dummy Module
|
||||
"""
|
||||
from zope.interface import moduleProvides
|
||||
from zope.interface.tests.idummy import IDummyModule
|
||||
|
||||
moduleProvides(IDummyModule)
|
||||
|
||||
def bar(baz):
|
||||
# Note: no 'self', because the module provides the interface directly.
|
||||
raise NotImplementedError()
|
23
lib/zope/interface/tests/idummy.py
Normal file
23
lib/zope/interface/tests/idummy.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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 describing API of zope.interface.tests.dummy test module
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
|
||||
class IDummyModule(Interface):
|
||||
""" Dummy interface for unit tests.
|
||||
"""
|
||||
def bar(baz):
|
||||
""" Just a note.
|
||||
"""
|
26
lib/zope/interface/tests/ifoo.py
Normal file
26
lib/zope/interface/tests/ifoo.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""IFoo test module
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
|
||||
class IFoo(Interface):
|
||||
"""
|
||||
Dummy interface for unit tests.
|
||||
"""
|
||||
|
||||
def bar(baz):
|
||||
"""
|
||||
Just a note.
|
||||
"""
|
26
lib/zope/interface/tests/ifoo_other.py
Normal file
26
lib/zope/interface/tests/ifoo_other.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""IFoo test module
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
|
||||
class IFoo(Interface):
|
||||
"""
|
||||
Dummy interface for unit tests.
|
||||
"""
|
||||
|
||||
def bar(baz):
|
||||
"""
|
||||
Just a note.
|
||||
"""
|
21
lib/zope/interface/tests/m1.py
Normal file
21
lib/zope/interface/tests/m1.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test module that declares an interface
|
||||
"""
|
||||
from zope.interface import Interface, moduleProvides
|
||||
|
||||
class I1(Interface): pass
|
||||
class I2(Interface): pass
|
||||
|
||||
moduleProvides(I1, I2)
|
15
lib/zope/interface/tests/m2.py
Normal file
15
lib/zope/interface/tests/m2.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test module that doesn't declare an interface
|
||||
"""
|
128
lib/zope/interface/tests/odd.py
Normal file
128
lib/zope/interface/tests/odd.py
Normal file
|
@ -0,0 +1,128 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Odd meta class that doesn't subclass type.
|
||||
|
||||
This is used for testing support for ExtensionClass in new interfaces.
|
||||
|
||||
>>> class A(object):
|
||||
... __metaclass__ = MetaClass
|
||||
... a = 1
|
||||
...
|
||||
>>> A.__name__
|
||||
'A'
|
||||
>>> A.__bases__ == (object,)
|
||||
True
|
||||
>>> class B(object):
|
||||
... __metaclass__ = MetaClass
|
||||
... b = 1
|
||||
...
|
||||
>>> class C(A, B): pass
|
||||
...
|
||||
>>> C.__name__
|
||||
'C'
|
||||
>>> int(C.__bases__ == (A, B))
|
||||
1
|
||||
>>> a = A()
|
||||
>>> aa = A()
|
||||
>>> a.a
|
||||
1
|
||||
>>> aa.a
|
||||
1
|
||||
>>> aa.a = 2
|
||||
>>> a.a
|
||||
1
|
||||
>>> aa.a
|
||||
2
|
||||
>>> c = C()
|
||||
>>> c.a
|
||||
1
|
||||
>>> c.b
|
||||
1
|
||||
>>> c.b = 2
|
||||
>>> c.b
|
||||
2
|
||||
>>> C.c = 1
|
||||
>>> c.c
|
||||
1
|
||||
>>> import sys
|
||||
>>> if sys.version[0] == '2': # This test only makes sense under Python 2.x
|
||||
... from types import ClassType
|
||||
... assert not isinstance(C, (type, ClassType))
|
||||
|
||||
>>> int(C.__class__.__class__ is C.__class__)
|
||||
1
|
||||
"""
|
||||
|
||||
# class OddClass is an odd meta class
|
||||
|
||||
class MetaMetaClass(type):
|
||||
|
||||
def __getattribute__(cls, name):
|
||||
if name == '__class__':
|
||||
return cls
|
||||
# Under Python 3.6, __prepare__ gets requested
|
||||
return type.__getattribute__(cls, name)
|
||||
|
||||
|
||||
class MetaClass(object):
|
||||
"""Odd classes
|
||||
"""
|
||||
|
||||
def __init__(self, name, bases, dict):
|
||||
self.__name__ = name
|
||||
self.__bases__ = bases
|
||||
self.__dict__.update(dict)
|
||||
|
||||
def __call__(self):
|
||||
return OddInstance(self)
|
||||
|
||||
def __getattr__(self, name):
|
||||
for b in self.__bases__:
|
||||
v = getattr(b, name, self)
|
||||
if v is not self:
|
||||
return v
|
||||
raise AttributeError(name)
|
||||
|
||||
def __repr__(self): # pragma: no cover
|
||||
return "<odd class %s at %s>" % (self.__name__, hex(id(self)))
|
||||
|
||||
|
||||
MetaClass = MetaMetaClass('MetaClass',
|
||||
MetaClass.__bases__,
|
||||
{k: v for k, v in MetaClass.__dict__.items()
|
||||
if k not in ('__dict__',)})
|
||||
|
||||
class OddInstance(object):
|
||||
|
||||
def __init__(self, cls):
|
||||
self.__dict__['__class__'] = cls
|
||||
|
||||
def __getattribute__(self, name):
|
||||
dict = object.__getattribute__(self, '__dict__')
|
||||
if name == '__dict__':
|
||||
return dict
|
||||
v = dict.get(name, self)
|
||||
if v is not self:
|
||||
return v
|
||||
return getattr(dict['__class__'], name)
|
||||
|
||||
def __setattr__(self, name, v):
|
||||
self.__dict__[name] = v
|
||||
|
||||
def __delattr__(self, name):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __repr__(self): # pragma: no cover
|
||||
return "<odd %s instance at %s>" % (
|
||||
self.__class__.__name__, hex(id(self)))
|
1419
lib/zope/interface/tests/test_adapter.py
Normal file
1419
lib/zope/interface/tests/test_adapter.py
Normal file
File diff suppressed because it is too large
Load diff
355
lib/zope/interface/tests/test_advice.py
Normal file
355
lib/zope/interface/tests/test_advice.py
Normal file
|
@ -0,0 +1,355 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Tests for advice
|
||||
|
||||
This module was adapted from 'protocols.tests.advice', part of the Python
|
||||
Enterprise Application Kit (PEAK). Please notify the PEAK authors
|
||||
(pje@telecommunity.com and tsarna@sarna.org) if bugs are found or
|
||||
Zope-specific changes are required, so that the PEAK version of this module
|
||||
can be kept in sync.
|
||||
|
||||
PEAK is a Python application framework that interoperates with (but does
|
||||
not require) Zope 3 and Twisted. It provides tools for manipulating UML
|
||||
models, object-relational persistence, aspect-oriented programming, and more.
|
||||
Visit the PEAK home page at http://peak.telecommunity.com for more information.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
from zope.interface._compat import _skip_under_py2
|
||||
from zope.interface._compat import _skip_under_py3k
|
||||
|
||||
|
||||
class FrameInfoTest(unittest.TestCase):
|
||||
|
||||
def test_w_module(self):
|
||||
from zope.interface.tests import advisory_testing
|
||||
(kind, module,
|
||||
f_locals, f_globals) = advisory_testing.moduleLevelFrameInfo
|
||||
self.assertEqual(kind, "module")
|
||||
for d in module.__dict__, f_locals, f_globals:
|
||||
self.assertTrue(d is advisory_testing.my_globals)
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_w_ClassicClass(self):
|
||||
from zope.interface.tests import advisory_testing
|
||||
(kind,
|
||||
module,
|
||||
f_locals,
|
||||
f_globals) = advisory_testing.ClassicClass.classLevelFrameInfo
|
||||
self.assertEqual(kind, "class")
|
||||
|
||||
self.assertTrue(
|
||||
f_locals is advisory_testing.ClassicClass.__dict__) # ???
|
||||
for d in module.__dict__, f_globals:
|
||||
self.assertTrue(d is advisory_testing.my_globals)
|
||||
|
||||
def test_w_NewStyleClass(self):
|
||||
from zope.interface.tests import advisory_testing
|
||||
(kind,
|
||||
module,
|
||||
f_locals,
|
||||
f_globals) = advisory_testing.NewStyleClass.classLevelFrameInfo
|
||||
self.assertEqual(kind, "class")
|
||||
|
||||
for d in module.__dict__, f_globals:
|
||||
self.assertTrue(d is advisory_testing.my_globals)
|
||||
|
||||
def test_inside_function_call(self):
|
||||
from zope.interface.advice import getFrameInfo
|
||||
kind, module, f_locals, f_globals = getFrameInfo(sys._getframe())
|
||||
self.assertEqual(kind, "function call")
|
||||
self.assertTrue(f_locals is locals()) # ???
|
||||
for d in module.__dict__, f_globals:
|
||||
self.assertTrue(d is globals())
|
||||
|
||||
def test_inside_exec(self):
|
||||
from zope.interface.advice import getFrameInfo
|
||||
_globals = {'getFrameInfo': getFrameInfo}
|
||||
_locals = {}
|
||||
exec(_FUNKY_EXEC, _globals, _locals)
|
||||
self.assertEqual(_locals['kind'], "exec")
|
||||
self.assertTrue(_locals['f_locals'] is _locals)
|
||||
self.assertTrue(_locals['module'] is None)
|
||||
self.assertTrue(_locals['f_globals'] is _globals)
|
||||
|
||||
|
||||
_FUNKY_EXEC = """\
|
||||
import sys
|
||||
kind, module, f_locals, f_globals = getFrameInfo(sys._getframe())
|
||||
"""
|
||||
|
||||
class AdviceTests(unittest.TestCase):
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_order(self):
|
||||
from zope.interface.tests.advisory_testing import ping
|
||||
log = []
|
||||
class Foo(object):
|
||||
ping(log, 1)
|
||||
ping(log, 2)
|
||||
ping(log, 3)
|
||||
|
||||
# Strip the list nesting
|
||||
for i in 1, 2, 3:
|
||||
self.assertTrue(isinstance(Foo, list))
|
||||
Foo, = Foo
|
||||
|
||||
self.assertEqual(log, [(1, Foo), (2, [Foo]), (3, [[Foo]])])
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_single_explicit_meta(self):
|
||||
from zope.interface.tests.advisory_testing import ping
|
||||
|
||||
class Metaclass(type):
|
||||
pass
|
||||
|
||||
class Concrete(Metaclass):
|
||||
__metaclass__ = Metaclass
|
||||
ping([],1)
|
||||
|
||||
Concrete, = Concrete
|
||||
self.assertTrue(Concrete.__class__ is Metaclass)
|
||||
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_mixed_metas(self):
|
||||
from zope.interface.tests.advisory_testing import ping
|
||||
|
||||
class Metaclass1(type):
|
||||
pass
|
||||
|
||||
class Metaclass2(type):
|
||||
pass
|
||||
|
||||
class Base1:
|
||||
__metaclass__ = Metaclass1
|
||||
|
||||
class Base2:
|
||||
__metaclass__ = Metaclass2
|
||||
|
||||
try:
|
||||
class Derived(Base1, Base2):
|
||||
ping([], 1)
|
||||
self.fail("Should have gotten incompatibility error")
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
class Metaclass3(Metaclass1, Metaclass2):
|
||||
pass
|
||||
|
||||
class Derived(Base1, Base2):
|
||||
__metaclass__ = Metaclass3
|
||||
ping([], 1)
|
||||
|
||||
self.assertTrue(isinstance(Derived, list))
|
||||
Derived, = Derived
|
||||
self.assertTrue(isinstance(Derived, Metaclass3))
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_meta_no_bases(self):
|
||||
from zope.interface.tests.advisory_testing import ping
|
||||
from types import ClassType
|
||||
class Thing:
|
||||
ping([], 1)
|
||||
klass, = Thing # unpack list created by pong
|
||||
self.assertEqual(type(klass), ClassType)
|
||||
|
||||
|
||||
class Test_isClassAdvisor(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.interface.advice import isClassAdvisor
|
||||
return isClassAdvisor(*args, **kw)
|
||||
|
||||
def test_w_non_function(self):
|
||||
self.assertEqual(self._callFUT(self), False)
|
||||
|
||||
def test_w_normal_function(self):
|
||||
def foo():
|
||||
raise NotImplementedError()
|
||||
self.assertEqual(self._callFUT(foo), False)
|
||||
|
||||
def test_w_advisor_function(self):
|
||||
def bar():
|
||||
raise NotImplementedError()
|
||||
bar.previousMetaclass = object()
|
||||
self.assertEqual(self._callFUT(bar), True)
|
||||
|
||||
|
||||
class Test_determineMetaclass(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, *args, **kw):
|
||||
from zope.interface.advice import determineMetaclass
|
||||
return determineMetaclass(*args, **kw)
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_empty(self):
|
||||
from types import ClassType
|
||||
self.assertEqual(self._callFUT(()), ClassType)
|
||||
|
||||
def test_empty_w_explicit_metatype(self):
|
||||
class Meta(type):
|
||||
pass
|
||||
self.assertEqual(self._callFUT((), Meta), Meta)
|
||||
|
||||
def test_single(self):
|
||||
class Meta(type):
|
||||
pass
|
||||
self.assertEqual(self._callFUT((Meta,)), type)
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_meta_of_class(self):
|
||||
class Metameta(type):
|
||||
pass
|
||||
|
||||
class Meta(type):
|
||||
__metaclass__ = Metameta
|
||||
|
||||
self.assertEqual(self._callFUT((Meta, type)), Metameta)
|
||||
|
||||
@_skip_under_py2
|
||||
def test_meta_of_class_py3k(self):
|
||||
# Work around SyntaxError under Python2.
|
||||
EXEC = '\n'.join([
|
||||
'class Metameta(type):',
|
||||
' pass',
|
||||
'class Meta(type, metaclass=Metameta):',
|
||||
' pass',
|
||||
])
|
||||
globs = {}
|
||||
exec(EXEC, globs)
|
||||
Meta = globs['Meta']
|
||||
Metameta = globs['Metameta']
|
||||
|
||||
self.assertEqual(self._callFUT((Meta, type)), Metameta)
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_multiple_in_hierarchy(self):
|
||||
class Meta_A(type):
|
||||
pass
|
||||
class Meta_B(Meta_A):
|
||||
pass
|
||||
class A(type):
|
||||
__metaclass__ = Meta_A
|
||||
class B(type):
|
||||
__metaclass__ = Meta_B
|
||||
self.assertEqual(self._callFUT((A, B,)), Meta_B)
|
||||
|
||||
@_skip_under_py2
|
||||
def test_multiple_in_hierarchy_py3k(self):
|
||||
# Work around SyntaxError under Python2.
|
||||
EXEC = '\n'.join([
|
||||
'class Meta_A(type):',
|
||||
' pass',
|
||||
'class Meta_B(Meta_A):',
|
||||
' pass',
|
||||
'class A(type, metaclass=Meta_A):',
|
||||
' pass',
|
||||
'class B(type, metaclass=Meta_B):',
|
||||
' pass',
|
||||
])
|
||||
globs = {}
|
||||
exec(EXEC, globs)
|
||||
Meta_A = globs['Meta_A']
|
||||
Meta_B = globs['Meta_B']
|
||||
A = globs['A']
|
||||
B = globs['B']
|
||||
self.assertEqual(self._callFUT((A, B)), Meta_B)
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_multiple_not_in_hierarchy(self):
|
||||
class Meta_A(type):
|
||||
pass
|
||||
class Meta_B(type):
|
||||
pass
|
||||
class A(type):
|
||||
__metaclass__ = Meta_A
|
||||
class B(type):
|
||||
__metaclass__ = Meta_B
|
||||
self.assertRaises(TypeError, self._callFUT, (A, B,))
|
||||
|
||||
@_skip_under_py2
|
||||
def test_multiple_not_in_hierarchy_py3k(self):
|
||||
# Work around SyntaxError under Python2.
|
||||
EXEC = '\n'.join([
|
||||
'class Meta_A(type):',
|
||||
' pass',
|
||||
'class Meta_B(type):',
|
||||
' pass',
|
||||
'class A(type, metaclass=Meta_A):',
|
||||
' pass',
|
||||
'class B(type, metaclass=Meta_B):',
|
||||
' pass',
|
||||
])
|
||||
globs = {}
|
||||
exec(EXEC, globs)
|
||||
Meta_A = globs['Meta_A']
|
||||
Meta_B = globs['Meta_B']
|
||||
A = globs['A']
|
||||
B = globs['B']
|
||||
self.assertRaises(TypeError, self._callFUT, (A, B))
|
||||
|
||||
|
||||
class Test_minimalBases(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, klasses):
|
||||
from zope.interface.advice import minimalBases
|
||||
return minimalBases(klasses)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual(self._callFUT([]), [])
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_w_oldstyle_meta(self):
|
||||
class C:
|
||||
pass
|
||||
self.assertEqual(self._callFUT([type(C)]), [])
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_w_oldstyle_class(self):
|
||||
class C:
|
||||
pass
|
||||
self.assertEqual(self._callFUT([C]), [C])
|
||||
|
||||
def test_w_newstyle_meta(self):
|
||||
self.assertEqual(self._callFUT([type]), [type])
|
||||
|
||||
def test_w_newstyle_class(self):
|
||||
class C(object):
|
||||
pass
|
||||
self.assertEqual(self._callFUT([C]), [C])
|
||||
|
||||
def test_simple_hierarchy_skips_implied(self):
|
||||
class A(object):
|
||||
pass
|
||||
class B(A):
|
||||
pass
|
||||
class C(B):
|
||||
pass
|
||||
class D(object):
|
||||
pass
|
||||
self.assertEqual(self._callFUT([A, B, C]), [C])
|
||||
self.assertEqual(self._callFUT([A, C]), [C])
|
||||
self.assertEqual(self._callFUT([B, C]), [C])
|
||||
self.assertEqual(self._callFUT([A, B]), [B])
|
||||
self.assertEqual(self._callFUT([D, B, D]), [B, D])
|
||||
|
||||
def test_repeats_kicked_to_end_of_queue(self):
|
||||
class A(object):
|
||||
pass
|
||||
class B(object):
|
||||
pass
|
||||
self.assertEqual(self._callFUT([A, B, A]), [B, A])
|
1658
lib/zope/interface/tests/test_declarations.py
Normal file
1658
lib/zope/interface/tests/test_declarations.py
Normal file
File diff suppressed because it is too large
Load diff
505
lib/zope/interface/tests/test_document.py
Normal file
505
lib/zope/interface/tests/test_document.py
Normal file
|
@ -0,0 +1,505 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Documentation tests.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
class Test_asStructuredText(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, iface):
|
||||
from zope.interface.document import asStructuredText
|
||||
return asStructuredText(iface)
|
||||
|
||||
def test_asStructuredText_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"INoDocstring",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class INoDocstring(Interface):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(INoDocstring), EXPECTED)
|
||||
|
||||
def test_asStructuredText_empty_with_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IEmpty",
|
||||
" This is an empty interface.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IEmpty(Interface):
|
||||
""" This is an empty interface.
|
||||
"""
|
||||
self.assertEqual(self._callFUT(IEmpty), EXPECTED)
|
||||
|
||||
def test_asStructuredText_empty_with_multiline_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n'.join([
|
||||
"IEmpty",
|
||||
"",
|
||||
" This is an empty interface.",
|
||||
" ",
|
||||
(" It can be used to annotate any class or object, "
|
||||
"because it promises"),
|
||||
" nothing.",
|
||||
"",
|
||||
" Attributes:",
|
||||
"",
|
||||
" Methods:",
|
||||
"",
|
||||
""
|
||||
])
|
||||
class IEmpty(Interface):
|
||||
""" This is an empty interface.
|
||||
|
||||
It can be used to annotate any class or object, because it promises
|
||||
nothing.
|
||||
"""
|
||||
self.assertEqual(self._callFUT(IEmpty), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_attribute_no_docstring(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasAttribute",
|
||||
" This interface has an attribute.",
|
||||
" Attributes:",
|
||||
" an_attribute -- no documentation",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IHasAttribute(Interface):
|
||||
""" This interface has an attribute.
|
||||
"""
|
||||
an_attribute = Attribute('an_attribute')
|
||||
|
||||
self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_attribute_with_docstring(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasAttribute",
|
||||
" This interface has an attribute.",
|
||||
" Attributes:",
|
||||
" an_attribute -- This attribute is documented.",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IHasAttribute(Interface):
|
||||
""" This interface has an attribute.
|
||||
"""
|
||||
an_attribute = Attribute('an_attribute',
|
||||
'This attribute is documented.')
|
||||
|
||||
self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_method_no_args_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasMethod",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" aMethod() -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod():
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_method_positional_args_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasMethod",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" aMethod(first, second) -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_method_starargs_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasMethod",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" aMethod(first, second, *rest) -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second, *rest):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_method_kwargs_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasMethod",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" aMethod(first, second, **kw) -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second, **kw):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asStructuredText_with_method_with_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IHasMethod",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" aMethod() -- This method is documented.",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod():
|
||||
"""This method is documented.
|
||||
"""
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asStructuredText_derived_ignores_base(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"IDerived",
|
||||
" IDerived doc",
|
||||
" This interface extends:",
|
||||
" o IBase",
|
||||
" Attributes:",
|
||||
" attr1 -- no documentation",
|
||||
" attr2 -- attr2 doc",
|
||||
" Methods:",
|
||||
" method3() -- method3 doc",
|
||||
" method4() -- no documentation",
|
||||
" method5() -- method5 doc",
|
||||
"",
|
||||
])
|
||||
|
||||
class IBase(Interface):
|
||||
def method1():
|
||||
pass
|
||||
def method2():
|
||||
pass
|
||||
|
||||
class IDerived(IBase):
|
||||
"IDerived doc"
|
||||
attr1 = Attribute('attr1')
|
||||
attr2 = Attribute('attr2', 'attr2 doc')
|
||||
|
||||
def method3():
|
||||
"method3 doc"
|
||||
def method4():
|
||||
pass
|
||||
def method5():
|
||||
"method5 doc"
|
||||
|
||||
self.assertEqual(self._callFUT(IDerived), EXPECTED)
|
||||
|
||||
|
||||
class Test_asReStructuredText(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, iface):
|
||||
from zope.interface.document import asReStructuredText
|
||||
return asReStructuredText(iface)
|
||||
|
||||
def test_asReStructuredText_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``INoDocstring``",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class INoDocstring(Interface):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(INoDocstring), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_empty_with_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IEmpty``",
|
||||
" This is an empty interface.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IEmpty(Interface):
|
||||
""" This is an empty interface.
|
||||
"""
|
||||
self.assertEqual(self._callFUT(IEmpty), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_empty_with_multiline_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n'.join([
|
||||
"``IEmpty``",
|
||||
"",
|
||||
" This is an empty interface.",
|
||||
" ",
|
||||
(" It can be used to annotate any class or object, "
|
||||
"because it promises"),
|
||||
" nothing.",
|
||||
"",
|
||||
" Attributes:",
|
||||
"",
|
||||
" Methods:",
|
||||
"",
|
||||
""
|
||||
])
|
||||
class IEmpty(Interface):
|
||||
""" This is an empty interface.
|
||||
|
||||
It can be used to annotate any class or object, because it promises
|
||||
nothing.
|
||||
"""
|
||||
self.assertEqual(self._callFUT(IEmpty), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_attribute_no_docstring(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasAttribute``",
|
||||
" This interface has an attribute.",
|
||||
" Attributes:",
|
||||
" ``an_attribute`` -- no documentation",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IHasAttribute(Interface):
|
||||
""" This interface has an attribute.
|
||||
"""
|
||||
an_attribute = Attribute('an_attribute')
|
||||
|
||||
self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_attribute_with_docstring(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasAttribute``",
|
||||
" This interface has an attribute.",
|
||||
" Attributes:",
|
||||
" ``an_attribute`` -- This attribute is documented.",
|
||||
" Methods:",
|
||||
""
|
||||
])
|
||||
class IHasAttribute(Interface):
|
||||
""" This interface has an attribute.
|
||||
"""
|
||||
an_attribute = Attribute('an_attribute',
|
||||
'This attribute is documented.')
|
||||
|
||||
self.assertEqual(self._callFUT(IHasAttribute), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_method_no_args_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasMethod``",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" ``aMethod()`` -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod():
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_method_positional_args_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasMethod``",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" ``aMethod(first, second)`` -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_method_starargs_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasMethod``",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" ``aMethod(first, second, *rest)`` -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second, *rest):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_method_kwargs_no_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasMethod``",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" ``aMethod(first, second, **kw)`` -- no documentation",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod(first, second, **kw):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_with_method_with_docstring(self):
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IHasMethod``",
|
||||
" This interface has a method.",
|
||||
" Attributes:",
|
||||
" Methods:",
|
||||
" ``aMethod()`` -- This method is documented.",
|
||||
""
|
||||
])
|
||||
class IHasMethod(Interface):
|
||||
""" This interface has a method.
|
||||
"""
|
||||
def aMethod():
|
||||
"""This method is documented.
|
||||
"""
|
||||
|
||||
self.assertEqual(self._callFUT(IHasMethod), EXPECTED)
|
||||
|
||||
def test_asReStructuredText_derived_ignores_base(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
EXPECTED = '\n\n'.join([
|
||||
"``IDerived``",
|
||||
" IDerived doc",
|
||||
" This interface extends:",
|
||||
" o ``IBase``",
|
||||
" Attributes:",
|
||||
" ``attr1`` -- no documentation",
|
||||
" ``attr2`` -- attr2 doc",
|
||||
" Methods:",
|
||||
" ``method3()`` -- method3 doc",
|
||||
" ``method4()`` -- no documentation",
|
||||
" ``method5()`` -- method5 doc",
|
||||
"",
|
||||
])
|
||||
|
||||
class IBase(Interface):
|
||||
def method1():
|
||||
pass
|
||||
def method2():
|
||||
pass
|
||||
|
||||
class IDerived(IBase):
|
||||
"IDerived doc"
|
||||
attr1 = Attribute('attr1')
|
||||
attr2 = Attribute('attr2', 'attr2 doc')
|
||||
|
||||
def method3():
|
||||
"method3 doc"
|
||||
def method4():
|
||||
pass
|
||||
def method5():
|
||||
"method5 doc"
|
||||
|
||||
self.assertEqual(self._callFUT(IDerived), EXPECTED)
|
||||
|
||||
|
||||
class Test__justify_and_indent(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, text, level, **kw):
|
||||
from zope.interface.document import _justify_and_indent
|
||||
return _justify_and_indent(text, level, **kw)
|
||||
|
||||
def test_simple_level_0(self):
|
||||
LINES = ['Three blind mice', 'See how they run']
|
||||
text = '\n'.join(LINES)
|
||||
self.assertEqual(self._callFUT(text, 0), text)
|
||||
|
||||
def test_simple_level_1(self):
|
||||
LINES = ['Three blind mice', 'See how they run']
|
||||
text = '\n'.join(LINES)
|
||||
self.assertEqual(self._callFUT(text, 1),
|
||||
'\n'.join([' ' + line for line in LINES]))
|
||||
|
||||
def test_simple_level_2(self):
|
||||
LINES = ['Three blind mice', 'See how they run']
|
||||
text = '\n'.join(LINES)
|
||||
self.assertEqual(self._callFUT(text, 1),
|
||||
'\n'.join([' ' + line for line in LINES]))
|
||||
|
||||
def test_simple_w_CRLF(self):
|
||||
LINES = ['Three blind mice', 'See how they run']
|
||||
text = '\r\n'.join(LINES)
|
||||
self.assertEqual(self._callFUT(text, 1),
|
||||
'\n'.join([' ' + line for line in LINES]))
|
||||
|
||||
def test_with_munge(self):
|
||||
TEXT = ("This is a piece of text longer than 15 characters, \n"
|
||||
"and split across multiple lines.")
|
||||
EXPECTED = (" This is a piece\n"
|
||||
" of text longer\n"
|
||||
" than 15 characters,\n"
|
||||
" and split across\n"
|
||||
" multiple lines.\n"
|
||||
" ")
|
||||
self.assertEqual(self._callFUT(TEXT, 1, munge=1, width=15), EXPECTED)
|
31
lib/zope/interface/tests/test_element.py
Normal file
31
lib/zope/interface/tests/test_element.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test Element meta-class.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from zope.interface.interface import Element
|
||||
|
||||
class TestElement(unittest.TestCase):
|
||||
|
||||
def test_taggedValues(self):
|
||||
"""Test that we can update tagged values of more than one element
|
||||
"""
|
||||
|
||||
e1 = Element("foo")
|
||||
e2 = Element("bar")
|
||||
e1.setTaggedValue("x", 1)
|
||||
e2.setTaggedValue("x", 2)
|
||||
self.assertEqual(e1.getTaggedValue("x"), 1)
|
||||
self.assertEqual(e2.getTaggedValue("x"), 2)
|
72
lib/zope/interface/tests/test_exceptions.py
Normal file
72
lib/zope/interface/tests/test_exceptions.py
Normal file
|
@ -0,0 +1,72 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2010 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" zope.interface.exceptions unit tests
|
||||
"""
|
||||
import unittest
|
||||
|
||||
def _makeIface():
|
||||
from zope.interface import Interface
|
||||
class IDummy(Interface):
|
||||
pass
|
||||
return IDummy
|
||||
|
||||
class DoesNotImplementTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import DoesNotImplement
|
||||
return DoesNotImplement
|
||||
|
||||
def _makeOne(self):
|
||||
iface = _makeIface()
|
||||
return self._getTargetClass()(iface)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
# XXX The trailing newlines and blank spaces are a stupid artifact.
|
||||
self.assertEqual(str(dni),
|
||||
'An object does not implement interface <InterfaceClass '
|
||||
'zope.interface.tests.test_exceptions.IDummy>\n\n ')
|
||||
|
||||
class BrokenImplementationTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import BrokenImplementation
|
||||
return BrokenImplementation
|
||||
|
||||
def _makeOne(self, name='missing'):
|
||||
iface = _makeIface()
|
||||
return self._getTargetClass()(iface, name)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
# XXX The trailing newlines and blank spaces are a stupid artifact.
|
||||
self.assertEqual(str(dni),
|
||||
'An object has failed to implement interface <InterfaceClass '
|
||||
'zope.interface.tests.test_exceptions.IDummy>\n\n'
|
||||
' The missing attribute was not provided.\n ')
|
||||
|
||||
class BrokenMethodImplementationTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
return BrokenMethodImplementation
|
||||
|
||||
def _makeOne(self, method='aMethod', mess='I said so'):
|
||||
return self._getTargetClass()(method, mess)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
self.assertEqual(str(dni),
|
||||
'The implementation of aMethod violates its contract\n'
|
||||
' because I said so.\n ')
|
2123
lib/zope/interface/tests/test_interface.py
Normal file
2123
lib/zope/interface/tests/test_interface.py
Normal file
File diff suppressed because it is too large
Load diff
95
lib/zope/interface/tests/test_interfaces.py
Normal file
95
lib/zope/interface/tests/test_interfaces.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
import unittest
|
||||
|
||||
|
||||
class _ConformsToIObjectEvent(object):
|
||||
|
||||
def _makeOne(self, target=None):
|
||||
if target is None:
|
||||
target = object()
|
||||
return self._getTargetClass()(target)
|
||||
|
||||
def test_class_conforms_to_IObjectEvent(self):
|
||||
from zope.interface.interfaces import IObjectEvent
|
||||
from zope.interface.verify import verifyClass
|
||||
verifyClass(IObjectEvent, self._getTargetClass())
|
||||
|
||||
def test_instance_conforms_to_IObjectEvent(self):
|
||||
from zope.interface.interfaces import IObjectEvent
|
||||
from zope.interface.verify import verifyObject
|
||||
verifyObject(IObjectEvent, self._makeOne())
|
||||
|
||||
|
||||
class _ConformsToIRegistrationEvent(_ConformsToIObjectEvent):
|
||||
|
||||
def test_class_conforms_to_IRegistrationEvent(self):
|
||||
from zope.interface.interfaces import IRegistrationEvent
|
||||
from zope.interface.verify import verifyClass
|
||||
verifyClass(IRegistrationEvent, self._getTargetClass())
|
||||
|
||||
def test_instance_conforms_to_IRegistrationEvent(self):
|
||||
from zope.interface.interfaces import IRegistrationEvent
|
||||
from zope.interface.verify import verifyObject
|
||||
verifyObject(IRegistrationEvent, self._makeOne())
|
||||
|
||||
|
||||
class ObjectEventTests(unittest.TestCase, _ConformsToIObjectEvent):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.interfaces import ObjectEvent
|
||||
return ObjectEvent
|
||||
|
||||
def test_ctor(self):
|
||||
target = object()
|
||||
event = self._makeOne(target)
|
||||
self.assertTrue(event.object is target)
|
||||
|
||||
|
||||
class RegistrationEventTests(unittest.TestCase,
|
||||
_ConformsToIRegistrationEvent):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.interfaces import RegistrationEvent
|
||||
return RegistrationEvent
|
||||
|
||||
def test___repr__(self):
|
||||
target = object()
|
||||
event = self._makeOne(target)
|
||||
r = repr(event)
|
||||
self.assertEqual(r.splitlines(),
|
||||
['RegistrationEvent event:', repr(target)])
|
||||
|
||||
|
||||
class RegisteredTests(unittest.TestCase,
|
||||
_ConformsToIRegistrationEvent):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.interfaces import Registered
|
||||
return Registered
|
||||
|
||||
def test_class_conforms_to_IRegistered(self):
|
||||
from zope.interface.interfaces import IRegistered
|
||||
from zope.interface.verify import verifyClass
|
||||
verifyClass(IRegistered, self._getTargetClass())
|
||||
|
||||
def test_instance_conforms_to_IRegistered(self):
|
||||
from zope.interface.interfaces import IRegistered
|
||||
from zope.interface.verify import verifyObject
|
||||
verifyObject(IRegistered, self._makeOne())
|
||||
|
||||
|
||||
class UnregisteredTests(unittest.TestCase,
|
||||
_ConformsToIRegistrationEvent):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.interfaces import Unregistered
|
||||
return Unregistered
|
||||
|
||||
def test_class_conforms_to_IUnregistered(self):
|
||||
from zope.interface.interfaces import IUnregistered
|
||||
from zope.interface.verify import verifyClass
|
||||
verifyClass(IUnregistered, self._getTargetClass())
|
||||
|
||||
def test_instance_conforms_to_IUnregistered(self):
|
||||
from zope.interface.interfaces import IUnregistered
|
||||
from zope.interface.verify import verifyObject
|
||||
verifyObject(IUnregistered, self._makeOne())
|
268
lib/zope/interface/tests/test_odd_declarations.py
Normal file
268
lib/zope/interface/tests/test_odd_declarations.py
Normal file
|
@ -0,0 +1,268 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test interface declarations against ExtensionClass-like classes.
|
||||
|
||||
These tests are to make sure we do something sane in the presence of
|
||||
classic ExtensionClass classes and instances.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from zope.interface.tests import odd
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface import directlyProvides
|
||||
from zope.interface import providedBy
|
||||
from zope.interface import directlyProvidedBy
|
||||
from zope.interface import classImplements
|
||||
from zope.interface import classImplementsOnly
|
||||
from zope.interface import implementedBy
|
||||
from zope.interface._compat import _skip_under_py3k
|
||||
|
||||
class I1(Interface): pass
|
||||
class I2(Interface): pass
|
||||
class I3(Interface): pass
|
||||
class I31(I3): pass
|
||||
class I4(Interface): pass
|
||||
class I5(Interface): pass
|
||||
|
||||
class Odd(object):
|
||||
pass
|
||||
Odd = odd.MetaClass('Odd', Odd.__bases__, {})
|
||||
|
||||
|
||||
class B(Odd): __implemented__ = I2
|
||||
|
||||
|
||||
# TODO: We are going to need more magic to make classProvides work with odd
|
||||
# classes. This will work in the next iteration. For now, we'll use
|
||||
# a different mechanism.
|
||||
|
||||
# from zope.interface import classProvides
|
||||
class A(Odd):
|
||||
pass
|
||||
classImplements(A, I1)
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
classImplements(C, I31)
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def test_ObjectSpecification(self):
|
||||
c = C()
|
||||
directlyProvides(c, I4)
|
||||
self.assertEqual([i.getName() for i in providedBy(c)],
|
||||
['I4', 'I31', 'I1', 'I2']
|
||||
)
|
||||
self.assertEqual([i.getName() for i in providedBy(c).flattened()],
|
||||
['I4', 'I31', 'I3', 'I1', 'I2', 'Interface']
|
||||
)
|
||||
self.assertTrue(I1 in providedBy(c))
|
||||
self.assertFalse(I3 in providedBy(c))
|
||||
self.assertTrue(providedBy(c).extends(I3))
|
||||
self.assertTrue(providedBy(c).extends(I31))
|
||||
self.assertFalse(providedBy(c).extends(I5))
|
||||
|
||||
class COnly(A, B):
|
||||
pass
|
||||
classImplementsOnly(COnly, I31)
|
||||
|
||||
class D(COnly):
|
||||
pass
|
||||
classImplements(D, I5)
|
||||
|
||||
classImplements(D, I5)
|
||||
|
||||
c = D()
|
||||
directlyProvides(c, I4)
|
||||
self.assertEqual([i.getName() for i in providedBy(c)],
|
||||
['I4', 'I5', 'I31'])
|
||||
self.assertEqual([i.getName() for i in providedBy(c).flattened()],
|
||||
['I4', 'I5', 'I31', 'I3', 'Interface'])
|
||||
self.assertFalse(I1 in providedBy(c))
|
||||
self.assertFalse(I3 in providedBy(c))
|
||||
self.assertTrue(providedBy(c).extends(I3))
|
||||
self.assertFalse(providedBy(c).extends(I1))
|
||||
self.assertTrue(providedBy(c).extends(I31))
|
||||
self.assertTrue(providedBy(c).extends(I5))
|
||||
|
||||
class COnly(A, B): __implemented__ = I31
|
||||
class D(COnly):
|
||||
pass
|
||||
classImplements(D, I5)
|
||||
|
||||
classImplements(D, I5)
|
||||
c = D()
|
||||
directlyProvides(c, I4)
|
||||
self.assertEqual([i.getName() for i in providedBy(c)],
|
||||
['I4', 'I5', 'I31'])
|
||||
self.assertEqual([i.getName() for i in providedBy(c).flattened()],
|
||||
['I4', 'I5', 'I31', 'I3', 'Interface'])
|
||||
self.assertFalse(I1 in providedBy(c))
|
||||
self.assertFalse(I3 in providedBy(c))
|
||||
self.assertTrue(providedBy(c).extends(I3))
|
||||
self.assertFalse(providedBy(c).extends(I1))
|
||||
self.assertTrue(providedBy(c).extends(I31))
|
||||
self.assertTrue(providedBy(c).extends(I5))
|
||||
|
||||
def test_classImplements(self):
|
||||
|
||||
@implementer(I3)
|
||||
class A(Odd):
|
||||
pass
|
||||
|
||||
@implementer(I4)
|
||||
class B(Odd):
|
||||
pass
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
classImplements(C, I1, I2)
|
||||
self.assertEqual([i.getName() for i in implementedBy(C)],
|
||||
['I1', 'I2', 'I3', 'I4'])
|
||||
classImplements(C, I5)
|
||||
self.assertEqual([i.getName() for i in implementedBy(C)],
|
||||
['I1', 'I2', 'I5', 'I3', 'I4'])
|
||||
|
||||
def test_classImplementsOnly(self):
|
||||
@implementer(I3)
|
||||
class A(Odd):
|
||||
pass
|
||||
|
||||
@implementer(I4)
|
||||
class B(Odd):
|
||||
pass
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
classImplementsOnly(C, I1, I2)
|
||||
self.assertEqual([i.__name__ for i in implementedBy(C)],
|
||||
['I1', 'I2'])
|
||||
|
||||
|
||||
def test_directlyProvides(self):
|
||||
class IA1(Interface): pass
|
||||
class IA2(Interface): pass
|
||||
class IB(Interface): pass
|
||||
class IC(Interface): pass
|
||||
class A(Odd):
|
||||
pass
|
||||
classImplements(A, IA1, IA2)
|
||||
|
||||
class B(Odd):
|
||||
pass
|
||||
classImplements(B, IB)
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
classImplements(C, IC)
|
||||
|
||||
|
||||
ob = C()
|
||||
directlyProvides(ob, I1, I2)
|
||||
self.assertTrue(I1 in providedBy(ob))
|
||||
self.assertTrue(I2 in providedBy(ob))
|
||||
self.assertTrue(IA1 in providedBy(ob))
|
||||
self.assertTrue(IA2 in providedBy(ob))
|
||||
self.assertTrue(IB in providedBy(ob))
|
||||
self.assertTrue(IC in providedBy(ob))
|
||||
|
||||
directlyProvides(ob, directlyProvidedBy(ob)-I2)
|
||||
self.assertTrue(I1 in providedBy(ob))
|
||||
self.assertFalse(I2 in providedBy(ob))
|
||||
self.assertFalse(I2 in providedBy(ob))
|
||||
directlyProvides(ob, directlyProvidedBy(ob), I2)
|
||||
self.assertTrue(I2 in providedBy(ob))
|
||||
|
||||
@_skip_under_py3k
|
||||
def test_directlyProvides_fails_for_odd_class(self):
|
||||
self.assertRaises(TypeError, directlyProvides, C, I5)
|
||||
|
||||
# see above
|
||||
#def TODO_test_classProvides_fails_for_odd_class(self):
|
||||
# try:
|
||||
# class A(Odd):
|
||||
# classProvides(I1)
|
||||
# except TypeError:
|
||||
# pass # Sucess
|
||||
# self.assert_(False,
|
||||
# "Shouldn't be able to use directlyProvides on odd class."
|
||||
# )
|
||||
|
||||
def test_implementedBy(self):
|
||||
class I2(I1): pass
|
||||
|
||||
class C1(Odd):
|
||||
pass
|
||||
classImplements(C1, I2)
|
||||
|
||||
class C2(C1):
|
||||
pass
|
||||
classImplements(C2, I3)
|
||||
|
||||
self.assertEqual([i.getName() for i in implementedBy(C2)],
|
||||
['I3', 'I2'])
|
||||
|
||||
def test_odd_metaclass_that_doesnt_subclass_type(self):
|
||||
# This was originally a doctest in odd.py.
|
||||
# It verifies that the metaclass the rest of these tests use
|
||||
# works as expected.
|
||||
|
||||
# This is used for testing support for ExtensionClass in new interfaces.
|
||||
|
||||
class A(object):
|
||||
a = 1
|
||||
|
||||
A = odd.MetaClass('A', A.__bases__, A.__dict__)
|
||||
|
||||
class B(object):
|
||||
b = 1
|
||||
|
||||
B = odd.MetaClass('B', B.__bases__, B.__dict__)
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
|
||||
self.assertEqual(C.__bases__, (A, B))
|
||||
|
||||
a = A()
|
||||
aa = A()
|
||||
self.assertEqual(a.a, 1)
|
||||
self.assertEqual(aa.a, 1)
|
||||
|
||||
aa.a = 2
|
||||
self.assertEqual(a.a, 1)
|
||||
self.assertEqual(aa.a, 2)
|
||||
|
||||
c = C()
|
||||
self.assertEqual(c.a, 1)
|
||||
self.assertEqual(c.b, 1)
|
||||
|
||||
c.b = 2
|
||||
self.assertEqual(c.b, 2)
|
||||
|
||||
C.c = 1
|
||||
self.assertEqual(c.c, 1)
|
||||
c.c
|
||||
|
||||
try:
|
||||
from types import ClassType
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# This test only makes sense under Python 2.x
|
||||
assert not isinstance(C, (type, ClassType))
|
||||
|
||||
self.assertIs(C.__class__.__class__, C.__class__)
|
2788
lib/zope/interface/tests/test_registry.py
Normal file
2788
lib/zope/interface/tests/test_registry.py
Normal file
File diff suppressed because it is too large
Load diff
115
lib/zope/interface/tests/test_ro.py
Normal file
115
lib/zope/interface/tests/test_ro.py
Normal file
|
@ -0,0 +1,115 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2014 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Resolution ordering utility tests"""
|
||||
import unittest
|
||||
|
||||
|
||||
class Test__mergeOrderings(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, orderings):
|
||||
from zope.interface.ro import _mergeOrderings
|
||||
return _mergeOrderings(orderings)
|
||||
|
||||
def test_empty(self):
|
||||
self.assertEqual(self._callFUT([]), [])
|
||||
|
||||
def test_single(self):
|
||||
self.assertEqual(self._callFUT(['a', 'b', 'c']), ['a', 'b', 'c'])
|
||||
|
||||
def test_w_duplicates(self):
|
||||
self.assertEqual(self._callFUT([['a'], ['b', 'a']]), ['b', 'a'])
|
||||
|
||||
def test_suffix_across_multiple_duplicats(self):
|
||||
O1 = ['x', 'y', 'z']
|
||||
O2 = ['q', 'z']
|
||||
O3 = [1, 3, 5]
|
||||
O4 = ['z']
|
||||
self.assertEqual(self._callFUT([O1, O2, O3, O4]),
|
||||
['x', 'y', 'q', 1, 3, 5, 'z'])
|
||||
|
||||
|
||||
class Test__flatten(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, ob):
|
||||
from zope.interface.ro import _flatten
|
||||
return _flatten(ob)
|
||||
|
||||
def test_w_empty_bases(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
foo = Foo()
|
||||
foo.__bases__ = ()
|
||||
self.assertEqual(self._callFUT(foo), [foo])
|
||||
|
||||
def test_w_single_base(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Foo), [Foo, object])
|
||||
|
||||
def test_w_bases(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])
|
||||
|
||||
def test_w_diamond(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
class Baz(Foo):
|
||||
pass
|
||||
class Qux(Bar, Baz):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Qux),
|
||||
[Qux, Bar, Foo, object, Baz, Foo, object])
|
||||
|
||||
|
||||
class Test_ro(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, ob):
|
||||
from zope.interface.ro import ro
|
||||
return ro(ob)
|
||||
|
||||
def test_w_empty_bases(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
foo = Foo()
|
||||
foo.__bases__ = ()
|
||||
self.assertEqual(self._callFUT(foo), [foo])
|
||||
|
||||
def test_w_single_base(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Foo), [Foo, object])
|
||||
|
||||
def test_w_bases(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])
|
||||
|
||||
def test_w_diamond(self):
|
||||
class Foo(object):
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
class Baz(Foo):
|
||||
pass
|
||||
class Qux(Bar, Baz):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Qux),
|
||||
[Qux, Bar, Baz, Foo, object])
|
47
lib/zope/interface/tests/test_sorting.py
Normal file
47
lib/zope/interface/tests/test_sorting.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test interface sorting
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from zope.interface import Interface
|
||||
|
||||
class I1(Interface): pass
|
||||
class I2(I1): pass
|
||||
class I3(I1): pass
|
||||
class I4(Interface): pass
|
||||
class I5(I4): pass
|
||||
class I6(I2): pass
|
||||
|
||||
|
||||
class Test(unittest.TestCase):
|
||||
|
||||
def test(self):
|
||||
l = [I1, I3, I5, I6, I4, I2]
|
||||
l.sort()
|
||||
self.assertEqual(l, [I1, I2, I3, I4, I5, I6])
|
||||
|
||||
def test_w_None(self):
|
||||
l = [I1, None, I3, I5, I6, I4, I2]
|
||||
l.sort()
|
||||
self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None])
|
||||
|
||||
def test_w_equal_names(self):
|
||||
# interfaces with equal names but different modules should sort by
|
||||
# module name
|
||||
from zope.interface.tests.m1 import I1 as m1_I1
|
||||
l = [I1, m1_I1]
|
||||
l.sort()
|
||||
self.assertEqual(l, [m1_I1, I1])
|
582
lib/zope/interface/tests/test_verify.py
Normal file
582
lib/zope/interface/tests/test_verify.py
Normal file
|
@ -0,0 +1,582 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
""" zope.interface.verify unit tests
|
||||
"""
|
||||
import unittest
|
||||
|
||||
|
||||
class Test_verifyClass(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, iface, klass):
|
||||
from zope.interface.verify import verifyClass
|
||||
return verifyClass(iface, klass)
|
||||
|
||||
def test_class_doesnt_implement(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.exceptions import DoesNotImplement
|
||||
|
||||
class ICurrent(Interface):
|
||||
pass
|
||||
|
||||
class Current(object):
|
||||
pass
|
||||
|
||||
self.assertRaises(DoesNotImplement, self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_class_doesnt_implement_but_classImplements_later(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import classImplements
|
||||
|
||||
class ICurrent(Interface):
|
||||
pass
|
||||
|
||||
class Current(object):
|
||||
pass
|
||||
|
||||
classImplements(Current, ICurrent)
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_class_doesnt_have_required_method_simple(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
def method(): pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
pass
|
||||
|
||||
self.assertRaises(BrokenImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_class_has_required_method_simple(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
def method(): pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_class_doesnt_have_required_method_derived(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenImplementation
|
||||
|
||||
class IBase(Interface):
|
||||
def method():
|
||||
pass
|
||||
|
||||
class IDerived(IBase):
|
||||
pass
|
||||
|
||||
@implementer(IDerived)
|
||||
class Current(object):
|
||||
pass
|
||||
|
||||
self.assertRaises(BrokenImplementation,
|
||||
self._callFUT, IDerived, Current)
|
||||
|
||||
def test_class_has_required_method_derived(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class IBase(Interface):
|
||||
def method():
|
||||
pass
|
||||
|
||||
class IDerived(IBase):
|
||||
pass
|
||||
|
||||
@implementer(IDerived)
|
||||
class Current(object):
|
||||
|
||||
def method(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(IDerived, Current)
|
||||
|
||||
def test_method_takes_wrong_arg_names_but_OK(self):
|
||||
# We no longer require names to match.
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, b):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_not_enough_args(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_doesnt_take_required_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(*args):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_doesnt_take_required_only_kwargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(**kw):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_takes_extra_arg(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, b):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_takes_extra_arg_with_default(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, b=None):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_only_positional_args(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_only_kwargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, **kw):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_takes_extra_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_extra_starargs_and_kwargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, *args, **kw):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_doesnt_take_required_positional_and_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a, *args):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_method_takes_required_positional_and_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a, *args):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_only_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a, *args):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_required_kwargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(**kwargs):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, **kw):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_method_takes_positional_plus_required_starargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(*args):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a, *args):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
|
||||
def test_method_doesnt_take_required_kwargs(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(**kwargs):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
def method(self, a):
|
||||
raise NotImplementedError()
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
|
||||
def test_class_has_method_for_iface_attr(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
attr = Attribute("The foo Attribute")
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
|
||||
def attr(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_class_has_nonmethod_for_method(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
def method():
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
method = 1
|
||||
|
||||
self.assertRaises(BrokenMethodImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_class_has_attribute_for_attribute(self):
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
attr = Attribute("The foo Attribute")
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
|
||||
attr = 1
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_class_misses_attribute_for_attribute(self):
|
||||
# This check *passes* for verifyClass
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class ICurrent(Interface):
|
||||
attr = Attribute("The foo Attribute")
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
pass
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
def test_w_callable_non_func_method(self):
|
||||
from zope.interface.interface import Method
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
class QuasiMethod(Method):
|
||||
def __call__(self, *args, **kw):
|
||||
raise NotImplementedError()
|
||||
|
||||
class QuasiCallable(object):
|
||||
def __call__(self, *args, **kw):
|
||||
raise NotImplementedError()
|
||||
|
||||
class ICurrent(Interface):
|
||||
attr = QuasiMethod('This is callable')
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
attr = QuasiCallable()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
|
||||
def test_w_decorated_method(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
|
||||
def decorator(func):
|
||||
# this is, in fact, zope.proxy.non_overridable
|
||||
return property(lambda self: func.__get__(self))
|
||||
|
||||
class ICurrent(Interface):
|
||||
|
||||
def method(a):
|
||||
pass
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current(object):
|
||||
|
||||
@decorator
|
||||
def method(self, a):
|
||||
raise NotImplementedError()
|
||||
|
||||
self._callFUT(ICurrent, Current)
|
||||
|
||||
class Test_verifyObject(Test_verifyClass):
|
||||
|
||||
def _callFUT(self, iface, target):
|
||||
from zope.interface.verify import verifyObject
|
||||
if isinstance(target, (type, type(OldSkool))):
|
||||
target = target()
|
||||
return verifyObject(iface, target)
|
||||
|
||||
def test_class_misses_attribute_for_attribute(self):
|
||||
# This check *fails* for verifyObject
|
||||
from zope.interface import Attribute
|
||||
from zope.interface import Interface
|
||||
from zope.interface import implementer
|
||||
from zope.interface.exceptions import BrokenImplementation
|
||||
|
||||
class ICurrent(Interface):
|
||||
attr = Attribute("The foo Attribute")
|
||||
|
||||
@implementer(ICurrent)
|
||||
class Current:
|
||||
pass
|
||||
|
||||
self.assertRaises(BrokenImplementation,
|
||||
self._callFUT, ICurrent, Current)
|
||||
|
||||
def test_module_hit(self):
|
||||
from zope.interface.tests.idummy import IDummyModule
|
||||
from zope.interface.tests import dummy
|
||||
|
||||
self._callFUT(IDummyModule, dummy)
|
||||
|
||||
def test_module_miss(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface.tests import dummy
|
||||
from zope.interface.exceptions import DoesNotImplement
|
||||
|
||||
# same name, different object
|
||||
class IDummyModule(Interface):
|
||||
pass
|
||||
|
||||
self.assertRaises(DoesNotImplement,
|
||||
self._callFUT, IDummyModule, dummy)
|
||||
|
||||
def test_staticmethod_hit_on_class(self):
|
||||
from zope.interface import Interface
|
||||
from zope.interface import provider
|
||||
from zope.interface.verify import verifyObject
|
||||
|
||||
class IFoo(Interface):
|
||||
|
||||
def bar(a, b):
|
||||
"The bar method"
|
||||
|
||||
@provider(IFoo)
|
||||
class Foo(object):
|
||||
|
||||
@staticmethod
|
||||
def bar(a, b):
|
||||
raise AssertionError("We're never actually called")
|
||||
|
||||
# Don't use self._callFUT, we don't want to instantiate the
|
||||
# class.
|
||||
verifyObject(IFoo, Foo)
|
||||
|
||||
class OldSkool:
|
||||
pass
|
123
lib/zope/interface/verify.py
Normal file
123
lib/zope/interface/verify.py
Normal file
|
@ -0,0 +1,123 @@
|
|||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""Verify interface implementations
|
||||
"""
|
||||
from zope.interface.exceptions import BrokenImplementation, DoesNotImplement
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
from types import FunctionType, MethodType
|
||||
from zope.interface.interface import fromMethod, fromFunction, Method
|
||||
import sys
|
||||
|
||||
# This will be monkey-patched when running under Zope 2, so leave this
|
||||
# here:
|
||||
MethodTypes = (MethodType, )
|
||||
|
||||
|
||||
def _verify(iface, candidate, tentative=0, vtype=None):
|
||||
"""Verify that 'candidate' might correctly implements 'iface'.
|
||||
|
||||
This involves:
|
||||
|
||||
o Making sure the candidate defines all the necessary methods
|
||||
|
||||
o Making sure the methods have the correct signature
|
||||
|
||||
o Making sure the candidate asserts that it implements the interface
|
||||
|
||||
Note that this isn't the same as verifying that the class does
|
||||
implement the interface.
|
||||
|
||||
If optional tentative is true, suppress the "is implemented by" test.
|
||||
"""
|
||||
|
||||
if vtype == 'c':
|
||||
tester = iface.implementedBy
|
||||
else:
|
||||
tester = iface.providedBy
|
||||
|
||||
if not tentative and not tester(candidate):
|
||||
raise DoesNotImplement(iface)
|
||||
|
||||
# Here the `desc` is either an `Attribute` or `Method` instance
|
||||
for name, desc in iface.namesAndDescriptions(1):
|
||||
try:
|
||||
attr = getattr(candidate, name)
|
||||
except AttributeError:
|
||||
if (not isinstance(desc, Method)) and vtype == 'c':
|
||||
# We can't verify non-methods on classes, since the
|
||||
# class may provide attrs in it's __init__.
|
||||
continue
|
||||
|
||||
raise BrokenImplementation(iface, name)
|
||||
|
||||
if not isinstance(desc, Method):
|
||||
# If it's not a method, there's nothing else we can test
|
||||
continue
|
||||
|
||||
if isinstance(attr, FunctionType):
|
||||
if sys.version_info[0] >= 3 and isinstance(candidate, type) and vtype == 'c':
|
||||
# This is an "unbound method" in Python 3.
|
||||
# Only unwrap this if we're verifying implementedBy;
|
||||
# otherwise we can unwrap @staticmethod on classes that directly
|
||||
# provide an interface.
|
||||
meth = fromFunction(attr, iface, name=name,
|
||||
imlevel=1)
|
||||
else:
|
||||
# Nope, just a normal function
|
||||
meth = fromFunction(attr, iface, name=name)
|
||||
elif (isinstance(attr, MethodTypes)
|
||||
and type(attr.__func__) is FunctionType):
|
||||
meth = fromMethod(attr, iface, name)
|
||||
elif isinstance(attr, property) and vtype == 'c':
|
||||
# We without an instance we cannot be sure it's not a
|
||||
# callable.
|
||||
continue
|
||||
else:
|
||||
if not callable(attr):
|
||||
raise BrokenMethodImplementation(name, "Not a method")
|
||||
# sigh, it's callable, but we don't know how to introspect it, so
|
||||
# we have to give it a pass.
|
||||
continue
|
||||
|
||||
# Make sure that the required and implemented method signatures are
|
||||
# the same.
|
||||
desc = desc.getSignatureInfo()
|
||||
meth = meth.getSignatureInfo()
|
||||
|
||||
mess = _incompat(desc, meth)
|
||||
if mess:
|
||||
raise BrokenMethodImplementation(name, mess)
|
||||
|
||||
return True
|
||||
|
||||
def verifyClass(iface, candidate, tentative=0):
|
||||
return _verify(iface, candidate, tentative, vtype='c')
|
||||
|
||||
def verifyObject(iface, candidate, tentative=0):
|
||||
return _verify(iface, candidate, tentative, vtype='o')
|
||||
|
||||
def _incompat(required, implemented):
|
||||
#if (required['positional'] !=
|
||||
# implemented['positional'][:len(required['positional'])]
|
||||
# and implemented['kwargs'] is None):
|
||||
# return 'imlementation has different argument names'
|
||||
if len(implemented['required']) > len(required['required']):
|
||||
return 'implementation requires too many arguments'
|
||||
if ((len(implemented['positional']) < len(required['positional']))
|
||||
and not implemented['varargs']):
|
||||
return "implementation doesn't allow enough arguments"
|
||||
if required['kwargs'] and not implemented['kwargs']:
|
||||
return "implementation doesn't support keyword arguments"
|
||||
if required['varargs'] and not implemented['varargs']:
|
||||
return "implementation doesn't support variable arguments"
|
Loading…
Add table
Add a link
Reference in a new issue