added forced package imports

This commit is contained in:
Nicholas St. Germain 2018-12-02 13:38:37 -06:00
parent 0e2ffdbbb1
commit ef9022c6eb
943 changed files with 125530 additions and 16 deletions

View 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)

View 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)

View 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

File diff suppressed because it is too large Load diff

View 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)

View 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

View file

@ -0,0 +1,2 @@
#
# This file is necessary to make this directory a package.

View 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)

View 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)

View 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

View 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"""

View file

@ -0,0 +1,2 @@
#
# This file is necessary to make this directory a package.

View 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()

View 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)

View 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)

View 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()

View 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)

View 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.
"""

View 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

File diff suppressed because it is too large Load diff

View 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
View 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)])

View file

@ -0,0 +1 @@
# Make this directory a package.

View 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())

View 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()

View 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.
"""

View 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.
"""

View 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.
"""

View 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)

View 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
"""

View 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)))

File diff suppressed because it is too large Load diff

View 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])

File diff suppressed because it is too large Load diff

View 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)

View 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)

View 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 ')

File diff suppressed because it is too large Load diff

View 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())

View 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__)

File diff suppressed because it is too large Load diff

View 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])

View 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])

View 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

View 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"