Primer commit
This commit is contained in:
93
venv/lib/python3.11/site-packages/zope/interface/__init__.py
Normal file
93
venv/lib/python3.11/site-packages/zope/interface/__init__.py
Normal file
@@ -0,0 +1,93 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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'
|
||||
# pylint:disable=wrong-import-position,unused-import
|
||||
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 classImplementsFirst
|
||||
from zope.interface.declarations import classImplementsOnly
|
||||
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 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 interfacemethod
|
||||
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)
|
||||
|
||||
assert all(k in globals() for k in __all__)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
135
venv/lib/python3.11/site-packages/zope/interface/_compat.py
Normal file
135
venv/lib/python3.11/site-packages/zope/interface/_compat.py
Normal file
@@ -0,0 +1,135 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
##############################################################################
|
||||
"""
|
||||
Support functions for dealing with differences in platforms, including Python
|
||||
versions and implementations.
|
||||
|
||||
This file should have no imports from the rest of zope.interface because it is
|
||||
used during early bootstrapping.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
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")
|
||||
|
||||
PYPY = hasattr(sys, 'pypy_version_info')
|
||||
|
||||
|
||||
def _c_optimizations_required():
|
||||
"""
|
||||
Return a true value if the C optimizations are required.
|
||||
|
||||
This uses the ``PURE_PYTHON`` variable as documented in `_use_c_impl`.
|
||||
"""
|
||||
pure_env = os.environ.get('PURE_PYTHON')
|
||||
require_c = pure_env == "0"
|
||||
return require_c
|
||||
|
||||
|
||||
def _c_optimizations_available():
|
||||
"""
|
||||
Return the C optimization module, if available, otherwise
|
||||
a false value.
|
||||
|
||||
If the optimizations are required but not available, this
|
||||
raises the ImportError.
|
||||
|
||||
This does not say whether they should be used or not.
|
||||
"""
|
||||
catch = () if _c_optimizations_required() else (ImportError,)
|
||||
try:
|
||||
from zope.interface import _zope_interface_coptimizations as c_opt
|
||||
return c_opt
|
||||
except catch: # pragma: no cover (only Jython doesn't build extensions)
|
||||
return False
|
||||
|
||||
|
||||
def _c_optimizations_ignored():
|
||||
"""
|
||||
The opposite of `_c_optimizations_required`.
|
||||
"""
|
||||
pure_env = os.environ.get('PURE_PYTHON')
|
||||
return pure_env is not None and pure_env != "0"
|
||||
|
||||
|
||||
def _should_attempt_c_optimizations():
|
||||
"""
|
||||
Return a true value if we should attempt to use the C optimizations.
|
||||
|
||||
This takes into account whether we're on PyPy and the value of the
|
||||
``PURE_PYTHON`` environment variable, as defined in `_use_c_impl`.
|
||||
"""
|
||||
is_pypy = hasattr(sys, 'pypy_version_info')
|
||||
|
||||
if _c_optimizations_required():
|
||||
return True
|
||||
if is_pypy:
|
||||
return False
|
||||
return not _c_optimizations_ignored()
|
||||
|
||||
|
||||
def _use_c_impl(py_impl, name=None, globs=None):
|
||||
"""
|
||||
Decorator. Given an object implemented in Python, with a name like
|
||||
``Foo``, import the corresponding C implementation from
|
||||
``zope.interface._zope_interface_coptimizations`` with the name
|
||||
``Foo`` and use it instead.
|
||||
|
||||
If the ``PURE_PYTHON`` environment variable is set to any value
|
||||
other than ``"0"``, or we're on PyPy, ignore the C implementation
|
||||
and return the Python version. If the C implementation cannot be
|
||||
imported, return the Python version. If ``PURE_PYTHON`` is set to
|
||||
0, *require* the C implementation (let the ImportError propagate);
|
||||
note that PyPy can import the C implementation in this case (and all
|
||||
tests pass).
|
||||
|
||||
In all cases, the Python version is kept available. in the module
|
||||
globals with the name ``FooPy`` and the name ``FooFallback`` (both
|
||||
conventions have been used; the C implementation of some functions
|
||||
looks for the ``Fallback`` version, as do some of the Sphinx
|
||||
documents).
|
||||
|
||||
Example::
|
||||
|
||||
@_use_c_impl
|
||||
class Foo(object):
|
||||
...
|
||||
"""
|
||||
name = name or py_impl.__name__
|
||||
globs = globs or sys._getframe(1).f_globals
|
||||
|
||||
def find_impl():
|
||||
if not _should_attempt_c_optimizations():
|
||||
return py_impl
|
||||
|
||||
c_opt = _c_optimizations_available()
|
||||
if not c_opt: # pragma: no cover (only Jython doesn't build extensions)
|
||||
return py_impl
|
||||
|
||||
__traceback_info__ = c_opt
|
||||
return getattr(c_opt, name)
|
||||
|
||||
c_impl = find_impl()
|
||||
# Always make available by the FooPy name and FooFallback
|
||||
# name (for testing and documentation)
|
||||
globs[name + 'Py'] = py_impl
|
||||
globs[name + 'Fallback'] = py_impl
|
||||
|
||||
return c_impl
|
||||
35
venv/lib/python3.11/site-packages/zope/interface/_flatten.py
Normal file
35
venv/lib/python3.11/site-packages/zope/interface/_flatten.py
Normal file
@@ -0,0 +1,35 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2002 Zope Foundation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##############################################################################
|
||||
"""Adapter-style interface registry
|
||||
|
||||
See Adapter class.
|
||||
"""
|
||||
from zope.interface import Declaration
|
||||
|
||||
def _flatten(implements, include_None=0):
|
||||
|
||||
try:
|
||||
r = implements.flattened()
|
||||
except AttributeError:
|
||||
if implements is None:
|
||||
r=()
|
||||
else:
|
||||
r = Declaration(implements).flattened()
|
||||
|
||||
if not include_None:
|
||||
return r
|
||||
|
||||
r = list(r)
|
||||
r.append(None)
|
||||
return r
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
1015
venv/lib/python3.11/site-packages/zope/interface/adapter.py
Normal file
1015
venv/lib/python3.11/site-packages/zope/interface/adapter.py
Normal file
File diff suppressed because it is too large
Load Diff
118
venv/lib/python3.11/site-packages/zope/interface/advice.py
Normal file
118
venv/lib/python3.11/site-packages/zope/interface/advice.py
Normal file
@@ -0,0 +1,118 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
__all__ = [
|
||||
'determineMetaclass',
|
||||
'getFrameInfo',
|
||||
'isClassAdvisor',
|
||||
'minimalBases',
|
||||
]
|
||||
|
||||
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 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 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"""
|
||||
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
|
||||
@@ -0,0 +1,272 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 itertools
|
||||
from types import FunctionType
|
||||
|
||||
from zope.interface import classImplements
|
||||
from zope.interface import Interface
|
||||
from zope.interface.interface import fromFunction
|
||||
from zope.interface.interface import InterfaceClass
|
||||
from zope.interface.interface import _decorator_non_return
|
||||
|
||||
__all__ = [
|
||||
# Nothing public here.
|
||||
]
|
||||
|
||||
|
||||
# pylint:disable=inherit-non-class,
|
||||
# pylint:disable=no-self-argument,no-method-argument
|
||||
# pylint:disable=unexpected-special-method-signature
|
||||
|
||||
class optional:
|
||||
# Apply this decorator to a method definition to make it
|
||||
# optional (remove it from the list of required names), overriding
|
||||
# the definition inherited from the ABC.
|
||||
def __init__(self, method):
|
||||
self.__doc__ = method.__doc__
|
||||
|
||||
|
||||
class ABCInterfaceClass(InterfaceClass):
|
||||
"""
|
||||
An interface that is automatically derived from a
|
||||
:class:`abc.ABCMeta` type.
|
||||
|
||||
Internal use only.
|
||||
|
||||
The body of the interface definition *must* define
|
||||
a property ``abc`` that is the ABC to base the interface on.
|
||||
|
||||
If ``abc`` is *not* in the interface definition, a regular
|
||||
interface will be defined instead (but ``extra_classes`` is still
|
||||
respected).
|
||||
|
||||
Use the ``@optional`` decorator on method definitions if
|
||||
the ABC defines methods that are not actually required in all cases
|
||||
because the Python language has multiple ways to implement a protocol.
|
||||
For example, the ``iter()`` protocol can be implemented with
|
||||
``__iter__`` or the pair ``__len__`` and ``__getitem__``.
|
||||
|
||||
When created, any existing classes that are registered to conform
|
||||
to the ABC are declared to implement this interface. This is *not*
|
||||
automatically updated as the ABC registry changes. If the body of the
|
||||
interface definition defines ``extra_classes``, it should be a
|
||||
tuple giving additional classes to declare implement the interface.
|
||||
|
||||
Note that this is not fully symmetric. For example, it is usually
|
||||
the case that a subclass relationship carries the interface
|
||||
declarations over::
|
||||
|
||||
>>> from zope.interface import Interface
|
||||
>>> class I1(Interface):
|
||||
... pass
|
||||
...
|
||||
>>> from zope.interface import implementer
|
||||
>>> @implementer(I1)
|
||||
... class Root(object):
|
||||
... pass
|
||||
...
|
||||
>>> class Child(Root):
|
||||
... pass
|
||||
...
|
||||
>>> child = Child()
|
||||
>>> isinstance(child, Root)
|
||||
True
|
||||
>>> from zope.interface import providedBy
|
||||
>>> list(providedBy(child))
|
||||
[<InterfaceClass __main__.I1>]
|
||||
|
||||
However, that's not the case with ABCs and ABC interfaces. Just
|
||||
because ``isinstance(A(), AnABC)`` and ``isinstance(B(), AnABC)``
|
||||
are both true, that doesn't mean there's any class hierarchy
|
||||
relationship between ``A`` and ``B``, or between either of them
|
||||
and ``AnABC``. Thus, if ``AnABC`` implemented ``IAnABC``, it would
|
||||
not follow that either ``A`` or ``B`` implements ``IAnABC`` (nor
|
||||
their instances provide it)::
|
||||
|
||||
>>> class SizedClass(object):
|
||||
... def __len__(self): return 1
|
||||
...
|
||||
>>> from collections.abc import Sized
|
||||
>>> isinstance(SizedClass(), Sized)
|
||||
True
|
||||
>>> from zope.interface import classImplements
|
||||
>>> classImplements(Sized, I1)
|
||||
None
|
||||
>>> list(providedBy(SizedClass()))
|
||||
[]
|
||||
|
||||
Thus, to avoid conflicting assumptions, ABCs should not be
|
||||
declared to implement their parallel ABC interface. Only concrete
|
||||
classes specifically registered with the ABC should be declared to
|
||||
do so.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
|
||||
# If we could figure out invalidation, and used some special
|
||||
# Specification/Declaration instances, and override the method ``providedBy`` here,
|
||||
# perhaps we could more closely integrate with ABC virtual inheritance?
|
||||
|
||||
def __init__(self, name, bases, attrs):
|
||||
# go ahead and give us a name to ease debugging.
|
||||
self.__name__ = name
|
||||
extra_classes = attrs.pop('extra_classes', ())
|
||||
ignored_classes = attrs.pop('ignored_classes', ())
|
||||
|
||||
if 'abc' not in attrs:
|
||||
# Something like ``IList(ISequence)``: We're extending
|
||||
# abc interfaces but not an ABC interface ourself.
|
||||
InterfaceClass.__init__(self, name, bases, attrs)
|
||||
ABCInterfaceClass.__register_classes(self, extra_classes, ignored_classes)
|
||||
self.__class__ = InterfaceClass
|
||||
return
|
||||
|
||||
based_on = attrs.pop('abc')
|
||||
self.__abc = based_on
|
||||
self.__extra_classes = tuple(extra_classes)
|
||||
self.__ignored_classes = tuple(ignored_classes)
|
||||
|
||||
assert name[1:] == based_on.__name__, (name, based_on)
|
||||
methods = {
|
||||
# Passing the name is important in case of aliases,
|
||||
# e.g., ``__ror__ = __or__``.
|
||||
k: self.__method_from_function(v, k)
|
||||
for k, v in vars(based_on).items()
|
||||
if isinstance(v, FunctionType) and not self.__is_private_name(k)
|
||||
and not self.__is_reverse_protocol_name(k)
|
||||
}
|
||||
|
||||
methods['__doc__'] = self.__create_class_doc(attrs)
|
||||
# Anything specified in the body takes precedence.
|
||||
methods.update(attrs)
|
||||
InterfaceClass.__init__(self, name, bases, methods)
|
||||
self.__register_classes()
|
||||
|
||||
@staticmethod
|
||||
def __optional_methods_to_docs(attrs):
|
||||
optionals = {k: v for k, v in attrs.items() if isinstance(v, optional)}
|
||||
for k in optionals:
|
||||
attrs[k] = _decorator_non_return
|
||||
|
||||
if not optionals:
|
||||
return ''
|
||||
|
||||
docs = "\n\nThe following methods are optional:\n - " + "\n-".join(
|
||||
"{}\n{}".format(k, v.__doc__) for k, v in optionals.items()
|
||||
)
|
||||
return docs
|
||||
|
||||
def __create_class_doc(self, attrs):
|
||||
based_on = self.__abc
|
||||
def ref(c):
|
||||
mod = c.__module__
|
||||
name = c.__name__
|
||||
if mod == str.__module__:
|
||||
return "`%s`" % name
|
||||
if mod == '_io':
|
||||
mod = 'io'
|
||||
return "`{}.{}`".format(mod, name)
|
||||
implementations_doc = "\n - ".join(
|
||||
ref(c)
|
||||
for c in sorted(self.getRegisteredConformers(), key=ref)
|
||||
)
|
||||
if implementations_doc:
|
||||
implementations_doc = "\n\nKnown implementations are:\n\n - " + implementations_doc
|
||||
|
||||
based_on_doc = (based_on.__doc__ or '')
|
||||
based_on_doc = based_on_doc.splitlines()
|
||||
based_on_doc = based_on_doc[0] if based_on_doc else ''
|
||||
|
||||
doc = """Interface for the ABC `{}.{}`.\n\n{}{}{}""".format(
|
||||
based_on.__module__, based_on.__name__,
|
||||
attrs.get('__doc__', based_on_doc),
|
||||
self.__optional_methods_to_docs(attrs),
|
||||
implementations_doc
|
||||
)
|
||||
return doc
|
||||
|
||||
|
||||
@staticmethod
|
||||
def __is_private_name(name):
|
||||
if name.startswith('__') and name.endswith('__'):
|
||||
return False
|
||||
return name.startswith('_')
|
||||
|
||||
@staticmethod
|
||||
def __is_reverse_protocol_name(name):
|
||||
# The reverse names, like __rand__,
|
||||
# aren't really part of the protocol. The interpreter has
|
||||
# very complex behaviour around invoking those. PyPy
|
||||
# doesn't always even expose them as attributes.
|
||||
return name.startswith('__r') and name.endswith('__')
|
||||
|
||||
def __method_from_function(self, function, name):
|
||||
method = fromFunction(function, self, name=name)
|
||||
# Eliminate the leading *self*, which is implied in
|
||||
# an interface, but explicit in an ABC.
|
||||
method.positional = method.positional[1:]
|
||||
return method
|
||||
|
||||
def __register_classes(self, conformers=None, ignored_classes=None):
|
||||
# Make the concrete classes already present in our ABC's registry
|
||||
# declare that they implement this interface.
|
||||
conformers = conformers if conformers is not None else self.getRegisteredConformers()
|
||||
ignored = ignored_classes if ignored_classes is not None else self.__ignored_classes
|
||||
for cls in conformers:
|
||||
if cls in ignored:
|
||||
continue
|
||||
classImplements(cls, self)
|
||||
|
||||
def getABC(self):
|
||||
"""
|
||||
Return the ABC this interface represents.
|
||||
"""
|
||||
return self.__abc
|
||||
|
||||
def getRegisteredConformers(self):
|
||||
"""
|
||||
Return an iterable of the classes that are known to conform to
|
||||
the ABC this interface parallels.
|
||||
"""
|
||||
based_on = self.__abc
|
||||
|
||||
# The registry only contains things that aren't already
|
||||
# known to be subclasses of the ABC. But the ABC is in charge
|
||||
# of checking that, so its quite possible that registrations
|
||||
# are in fact ignored, winding up just in the _abc_cache.
|
||||
try:
|
||||
registered = list(based_on._abc_registry) + list(based_on._abc_cache)
|
||||
except AttributeError:
|
||||
# Rewritten in C in CPython 3.7.
|
||||
# These expose the underlying weakref.
|
||||
from abc import _get_dump
|
||||
data = _get_dump(based_on)
|
||||
registry = data[0]
|
||||
cache = data[1]
|
||||
registered = [x() for x in itertools.chain(registry, cache)]
|
||||
registered = [x for x in registered if x is not None]
|
||||
|
||||
return set(itertools.chain(registered, self.__extra_classes))
|
||||
|
||||
|
||||
def _create_ABCInterface():
|
||||
# It's a two-step process to create the root ABCInterface, because
|
||||
# without specifying a corresponding ABC, using the normal constructor
|
||||
# gets us a plain InterfaceClass object, and there is no ABC to associate with the
|
||||
# root.
|
||||
abc_name_bases_attrs = ('ABCInterface', (Interface,), {})
|
||||
instance = ABCInterfaceClass.__new__(ABCInterfaceClass, *abc_name_bases_attrs)
|
||||
InterfaceClass.__init__(instance, *abc_name_bases_attrs)
|
||||
return instance
|
||||
|
||||
ABCInterface = _create_ABCInterface()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,119 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 definitions for builtin types.
|
||||
|
||||
After this module is imported, the standard library types will declare
|
||||
that they implement the appropriate interface.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
|
||||
from zope.interface import classImplements
|
||||
|
||||
from zope.interface.common import collections
|
||||
from zope.interface.common import numbers
|
||||
from zope.interface.common import io
|
||||
|
||||
__all__ = [
|
||||
'IList',
|
||||
'ITuple',
|
||||
'ITextString',
|
||||
'IByteString',
|
||||
'INativeString',
|
||||
'IBool',
|
||||
'IDict',
|
||||
'IFile',
|
||||
]
|
||||
|
||||
# pylint:disable=no-self-argument
|
||||
class IList(collections.IMutableSequence):
|
||||
"""
|
||||
Interface for :class:`list`
|
||||
"""
|
||||
extra_classes = (list,)
|
||||
|
||||
def sort(key=None, reverse=False):
|
||||
"""
|
||||
Sort the list in place and return None.
|
||||
|
||||
*key* and *reverse* must be passed by name only.
|
||||
"""
|
||||
|
||||
|
||||
class ITuple(collections.ISequence):
|
||||
"""
|
||||
Interface for :class:`tuple`
|
||||
"""
|
||||
extra_classes = (tuple,)
|
||||
|
||||
|
||||
class ITextString(collections.ISequence):
|
||||
"""
|
||||
Interface for text ("unicode") strings.
|
||||
|
||||
This is :class:`str`
|
||||
"""
|
||||
extra_classes = (str,)
|
||||
|
||||
|
||||
class IByteString(collections.IByteString):
|
||||
"""
|
||||
Interface for immutable byte strings.
|
||||
|
||||
On all Python versions this is :class:`bytes`.
|
||||
|
||||
Unlike :class:`zope.interface.common.collections.IByteString`
|
||||
(the parent of this interface) this does *not* include
|
||||
:class:`bytearray`.
|
||||
"""
|
||||
extra_classes = (bytes,)
|
||||
|
||||
|
||||
class INativeString(ITextString):
|
||||
"""
|
||||
Interface for native strings.
|
||||
|
||||
On all Python versions, this is :class:`str`. Tt extends
|
||||
:class:`ITextString`.
|
||||
"""
|
||||
# We're not extending ABCInterface so extra_classes won't work
|
||||
classImplements(str, INativeString)
|
||||
|
||||
|
||||
class IBool(numbers.IIntegral):
|
||||
"""
|
||||
Interface for :class:`bool`
|
||||
"""
|
||||
extra_classes = (bool,)
|
||||
|
||||
|
||||
class IDict(collections.IMutableMapping):
|
||||
"""
|
||||
Interface for :class:`dict`
|
||||
"""
|
||||
extra_classes = (dict,)
|
||||
|
||||
|
||||
class IFile(io.IIOBase):
|
||||
"""
|
||||
Interface for :class:`file`.
|
||||
|
||||
It is recommended to use the interfaces from :mod:`zope.interface.common.io`
|
||||
instead of this interface.
|
||||
|
||||
On Python 3, there is no single implementation of this interface;
|
||||
depending on the arguments, the :func:`open` builtin can return
|
||||
many different classes that implement different interfaces from
|
||||
:mod:`zope.interface.common.io`.
|
||||
"""
|
||||
extra_classes = ()
|
||||
@@ -0,0 +1,253 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
|
||||
:mod:`collections.abc`.
|
||||
|
||||
After this module is imported, the standard library types will declare
|
||||
that they implement the appropriate interface. While most standard
|
||||
library types will properly implement that interface (that
|
||||
is, ``verifyObject(ISequence, list()))`` will pass, for example), a few might not:
|
||||
|
||||
- `memoryview` doesn't feature all the defined methods of
|
||||
``ISequence`` such as ``count``; it is still declared to provide
|
||||
``ISequence`` though.
|
||||
|
||||
- `collections.deque.pop` doesn't accept the ``index`` argument of
|
||||
`collections.abc.MutableSequence.pop`
|
||||
|
||||
- `range.index` does not accept the ``start`` and ``stop`` arguments.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
from abc import ABCMeta
|
||||
from collections import abc
|
||||
from collections import OrderedDict
|
||||
from collections import UserList
|
||||
from collections import UserDict
|
||||
from collections import UserString
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import optional
|
||||
|
||||
# pylint:disable=inherit-non-class,
|
||||
# pylint:disable=no-self-argument,no-method-argument
|
||||
# pylint:disable=unexpected-special-method-signature
|
||||
# pylint:disable=no-value-for-parameter
|
||||
|
||||
|
||||
def _new_in_ver(name, ver,
|
||||
bases_if_missing=(ABCMeta,),
|
||||
register_if_missing=()):
|
||||
if ver:
|
||||
return getattr(abc, name)
|
||||
|
||||
# TODO: It's a shame to have to repeat the bases when
|
||||
# the ABC is missing. Can we DRY that?
|
||||
missing = ABCMeta(name, bases_if_missing, {
|
||||
'__doc__': "The ABC %s is not defined in this version of Python." % (
|
||||
name
|
||||
),
|
||||
})
|
||||
|
||||
for c in register_if_missing:
|
||||
missing.register(c)
|
||||
|
||||
return missing
|
||||
|
||||
__all__ = [
|
||||
'IAsyncGenerator',
|
||||
'IAsyncIterable',
|
||||
'IAsyncIterator',
|
||||
'IAwaitable',
|
||||
'ICollection',
|
||||
'IContainer',
|
||||
'ICoroutine',
|
||||
'IGenerator',
|
||||
'IHashable',
|
||||
'IItemsView',
|
||||
'IIterable',
|
||||
'IIterator',
|
||||
'IKeysView',
|
||||
'IMapping',
|
||||
'IMappingView',
|
||||
'IMutableMapping',
|
||||
'IMutableSequence',
|
||||
'IMutableSet',
|
||||
'IReversible',
|
||||
'ISequence',
|
||||
'ISet',
|
||||
'ISized',
|
||||
'IValuesView',
|
||||
]
|
||||
|
||||
class IContainer(ABCInterface):
|
||||
abc = abc.Container
|
||||
|
||||
@optional
|
||||
def __contains__(other):
|
||||
"""
|
||||
Optional method. If not provided, the interpreter will use
|
||||
``__iter__`` or the old ``__getitem__`` protocol
|
||||
to implement ``in``.
|
||||
"""
|
||||
|
||||
class IHashable(ABCInterface):
|
||||
abc = abc.Hashable
|
||||
|
||||
class IIterable(ABCInterface):
|
||||
abc = abc.Iterable
|
||||
|
||||
@optional
|
||||
def __iter__():
|
||||
"""
|
||||
Optional method. If not provided, the interpreter will
|
||||
implement `iter` using the old ``__getitem__`` protocol.
|
||||
"""
|
||||
|
||||
class IIterator(IIterable):
|
||||
abc = abc.Iterator
|
||||
|
||||
class IReversible(IIterable):
|
||||
abc = _new_in_ver('Reversible', True, (IIterable.getABC(),))
|
||||
|
||||
@optional
|
||||
def __reversed__():
|
||||
"""
|
||||
Optional method. If this isn't present, the interpreter
|
||||
will use ``__len__`` and ``__getitem__`` to implement the
|
||||
`reversed` builtin.
|
||||
"""
|
||||
|
||||
class IGenerator(IIterator):
|
||||
# New in Python 3.5
|
||||
abc = _new_in_ver('Generator', True, (IIterator.getABC(),))
|
||||
|
||||
|
||||
class ISized(ABCInterface):
|
||||
abc = abc.Sized
|
||||
|
||||
|
||||
# ICallable is not defined because there's no standard signature.
|
||||
|
||||
class ICollection(ISized,
|
||||
IIterable,
|
||||
IContainer):
|
||||
abc = _new_in_ver('Collection', True,
|
||||
(ISized.getABC(), IIterable.getABC(), IContainer.getABC()))
|
||||
|
||||
|
||||
class ISequence(IReversible,
|
||||
ICollection):
|
||||
abc = abc.Sequence
|
||||
extra_classes = (UserString,)
|
||||
# On Python 2, basestring is registered as an ISequence, and
|
||||
# its subclass str is an IByteString. If we also register str as
|
||||
# an ISequence, that tends to lead to inconsistent resolution order.
|
||||
ignored_classes = (basestring,) if str is bytes else () # pylint:disable=undefined-variable
|
||||
|
||||
@optional
|
||||
def __reversed__():
|
||||
"""
|
||||
Optional method. If this isn't present, the interpreter
|
||||
will use ``__len__`` and ``__getitem__`` to implement the
|
||||
`reversed` builtin.
|
||||
"""
|
||||
|
||||
@optional
|
||||
def __iter__():
|
||||
"""
|
||||
Optional method. If not provided, the interpreter will
|
||||
implement `iter` using the old ``__getitem__`` protocol.
|
||||
"""
|
||||
|
||||
class IMutableSequence(ISequence):
|
||||
abc = abc.MutableSequence
|
||||
extra_classes = (UserList,)
|
||||
|
||||
|
||||
class IByteString(ISequence):
|
||||
"""
|
||||
This unifies `bytes` and `bytearray`.
|
||||
"""
|
||||
abc = _new_in_ver('ByteString', True,
|
||||
(ISequence.getABC(),),
|
||||
(bytes, bytearray))
|
||||
|
||||
|
||||
class ISet(ICollection):
|
||||
abc = abc.Set
|
||||
|
||||
|
||||
class IMutableSet(ISet):
|
||||
abc = abc.MutableSet
|
||||
|
||||
|
||||
class IMapping(ICollection):
|
||||
abc = abc.Mapping
|
||||
extra_classes = (dict,)
|
||||
# OrderedDict is a subclass of dict. On CPython 2,
|
||||
# it winds up registered as a IMutableMapping, which
|
||||
# produces an inconsistent IRO if we also try to register it
|
||||
# here.
|
||||
ignored_classes = (OrderedDict,)
|
||||
|
||||
|
||||
class IMutableMapping(IMapping):
|
||||
abc = abc.MutableMapping
|
||||
extra_classes = (dict, UserDict,)
|
||||
ignored_classes = (OrderedDict,)
|
||||
|
||||
class IMappingView(ISized):
|
||||
abc = abc.MappingView
|
||||
|
||||
|
||||
class IItemsView(IMappingView, ISet):
|
||||
abc = abc.ItemsView
|
||||
|
||||
|
||||
class IKeysView(IMappingView, ISet):
|
||||
abc = abc.KeysView
|
||||
|
||||
|
||||
class IValuesView(IMappingView, ICollection):
|
||||
abc = abc.ValuesView
|
||||
|
||||
@optional
|
||||
def __contains__(other):
|
||||
"""
|
||||
Optional method. If not provided, the interpreter will use
|
||||
``__iter__`` or the old ``__len__`` and ``__getitem__`` protocol
|
||||
to implement ``in``.
|
||||
"""
|
||||
|
||||
class IAwaitable(ABCInterface):
|
||||
abc = _new_in_ver('Awaitable', True)
|
||||
|
||||
|
||||
class ICoroutine(IAwaitable):
|
||||
abc = _new_in_ver('Coroutine', True)
|
||||
|
||||
|
||||
class IAsyncIterable(ABCInterface):
|
||||
abc = _new_in_ver('AsyncIterable', True)
|
||||
|
||||
|
||||
class IAsyncIterator(IAsyncIterable):
|
||||
abc = _new_in_ver('AsyncIterator', True)
|
||||
|
||||
|
||||
class IAsyncGenerator(IAsyncIterator):
|
||||
abc = _new_in_ver('AsyncGenerator', True)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,208 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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` (no longer existing.)"
|
||||
|
||||
|
||||
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)
|
||||
@@ -0,0 +1,43 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
|
||||
:mod:`io`.
|
||||
|
||||
After this module is imported, the standard library types will declare
|
||||
that they implement the appropriate interface.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
|
||||
import io as abc
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
|
||||
# pylint:disable=inherit-non-class,
|
||||
# pylint:disable=no-member
|
||||
|
||||
class IIOBase(ABCInterface):
|
||||
abc = abc.IOBase
|
||||
|
||||
|
||||
class IRawIOBase(IIOBase):
|
||||
abc = abc.RawIOBase
|
||||
|
||||
|
||||
class IBufferedIOBase(IIOBase):
|
||||
abc = abc.BufferedIOBase
|
||||
extra_classes = ()
|
||||
|
||||
|
||||
class ITextIOBase(IIOBase):
|
||||
abc = abc.TextIOBase
|
||||
@@ -0,0 +1,168 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
|
||||
While this module is not deprecated, new code should generally use
|
||||
:mod:`zope.interface.common.collections`, specifically
|
||||
:class:`~zope.interface.common.collections.IMapping` and
|
||||
:class:`~zope.interface.common.collections.IMutableMapping`. This
|
||||
module is occasionally useful for its extremely fine grained breakdown
|
||||
of interfaces.
|
||||
|
||||
The standard library :class:`dict` and :class:`collections.UserDict`
|
||||
implement ``IMutableMapping``, but *do not* implement any of the
|
||||
interfaces in this module.
|
||||
"""
|
||||
from zope.interface import Interface
|
||||
from zope.interface.common import collections
|
||||
|
||||
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(collections.IContainer, IItemMapping):
|
||||
"""
|
||||
Basic mapping interface.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Extend ``IContainer``
|
||||
"""
|
||||
|
||||
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."""
|
||||
# Optional in IContainer, required by this interface.
|
||||
|
||||
|
||||
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(collections.ISized, IReadMapping):
|
||||
"""
|
||||
Mapping objects whose items can be enumerated.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Extend ``ISized``
|
||||
"""
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
class IMapping(IWriteMapping, IEnumerableMapping):
|
||||
''' Simple mapping interface '''
|
||||
|
||||
class IIterableMapping(IEnumerableMapping):
|
||||
"""A mapping that has distinct methods for iterating
|
||||
without copying.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
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` provided the ``has_key`` method, but it was removed
|
||||
in Python 3.
|
||||
"""
|
||||
|
||||
|
||||
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, default=None):
|
||||
"""
|
||||
pop(k[,default]) -> value
|
||||
|
||||
Remove specified key and return the corresponding value.
|
||||
|
||||
If key is not found, *default* is returned if given, otherwise
|
||||
`KeyError` is raised. Note that *default* must not be passed by
|
||||
name.
|
||||
"""
|
||||
|
||||
def popitem():
|
||||
"""remove and return some (key, value) pair as a
|
||||
2-tuple; but raise KeyError if mapping is empty"""
|
||||
|
||||
class IFullMapping(
|
||||
collections.IMutableMapping,
|
||||
IExtendedReadMapping, IExtendedWriteMapping, IClonableMapping, IMapping,):
|
||||
"""
|
||||
Full mapping interface.
|
||||
|
||||
Most uses of this interface should instead use
|
||||
:class:`~zope.interface.commons.collections.IMutableMapping` (one of the
|
||||
bases of this interface). The required methods are the same.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Extend ``IMutableMapping``
|
||||
"""
|
||||
@@ -0,0 +1,65 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 definitions paralleling the abstract base classes defined in
|
||||
:mod:`numbers`.
|
||||
|
||||
After this module is imported, the standard library types will declare
|
||||
that they implement the appropriate interface.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
|
||||
import numbers as abc
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import optional
|
||||
|
||||
|
||||
# pylint:disable=inherit-non-class,
|
||||
# pylint:disable=no-self-argument,no-method-argument
|
||||
# pylint:disable=unexpected-special-method-signature
|
||||
# pylint:disable=no-value-for-parameter
|
||||
|
||||
|
||||
class INumber(ABCInterface):
|
||||
abc = abc.Number
|
||||
|
||||
|
||||
class IComplex(INumber):
|
||||
abc = abc.Complex
|
||||
|
||||
@optional
|
||||
def __complex__():
|
||||
"""
|
||||
Rarely implemented, even in builtin types.
|
||||
"""
|
||||
|
||||
|
||||
class IReal(IComplex):
|
||||
abc = abc.Real
|
||||
|
||||
@optional
|
||||
def __complex__():
|
||||
"""
|
||||
Rarely implemented, even in builtin types.
|
||||
"""
|
||||
|
||||
__floor__ = __ceil__ = __complex__
|
||||
|
||||
|
||||
class IRational(IReal):
|
||||
abc = abc.Rational
|
||||
|
||||
|
||||
class IIntegral(IRational):
|
||||
abc = abc.Integral
|
||||
@@ -0,0 +1,189 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
|
||||
While this module is not deprecated, new code should generally use
|
||||
:mod:`zope.interface.common.collections`, specifically
|
||||
:class:`~zope.interface.common.collections.ISequence` and
|
||||
:class:`~zope.interface.common.collections.IMutableSequence`. This
|
||||
module is occasionally useful for its fine-grained breakdown of interfaces.
|
||||
|
||||
The standard library :class:`list`, :class:`tuple` and
|
||||
:class:`collections.UserList`, among others, implement ``ISequence``
|
||||
or ``IMutableSequence`` but *do not* implement any of the interfaces
|
||||
in this module.
|
||||
"""
|
||||
|
||||
__docformat__ = 'restructuredtext'
|
||||
from zope.interface import Interface
|
||||
from zope.interface.common import collections
|
||||
|
||||
class IMinimalSequence(collections.IIterable):
|
||||
"""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(collections.ISized, IMinimalSequence):
|
||||
"""
|
||||
A sequence of bound size.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Extend ``ISized``
|
||||
"""
|
||||
|
||||
class IReadSequence(collections.IContainer, IFiniteSequence):
|
||||
"""
|
||||
read interface shared by tuple and list
|
||||
|
||||
This interface is similar to
|
||||
:class:`~zope.interface.common.collections.ISequence`, but
|
||||
requires that all instances be totally ordered. Most users
|
||||
should prefer ``ISequence``.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Extend ``IContainer``
|
||||
"""
|
||||
|
||||
def __contains__(item):
|
||||
"""``x.__contains__(item) <==> item in x``"""
|
||||
# Optional in IContainer, required here.
|
||||
|
||||
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``"""
|
||||
|
||||
|
||||
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 __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.
|
||||
|
||||
New code should prefer
|
||||
:class:`~zope.interface.common.collections.IMutableSequence`.
|
||||
|
||||
Compared to that interface, which is implemented by :class:`list`
|
||||
(:class:`~zope.interface.common.builtins.IList`), among others,
|
||||
this interface is missing the following methods:
|
||||
|
||||
- clear
|
||||
|
||||
- count
|
||||
|
||||
- index
|
||||
|
||||
This interface adds the following methods:
|
||||
|
||||
- sort
|
||||
"""
|
||||
@@ -0,0 +1,136 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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
|
||||
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.interface.verify import verifyObject
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import ABCInterfaceClass
|
||||
|
||||
|
||||
def iter_abc_interfaces(predicate=lambda iface: True):
|
||||
# Iterate ``(iface, classes)``, where ``iface`` is a descendent of
|
||||
# the ABCInterfaceClass passing the *predicate* and ``classes`` is
|
||||
# an iterable of classes registered to conform to that interface.
|
||||
#
|
||||
# Note that some builtin classes are registered for two distinct
|
||||
# parts of the ABC/interface tree. For example, bytearray is both ByteString
|
||||
# and MutableSequence.
|
||||
seen = set()
|
||||
stack = list(ABCInterface.dependents) # subclasses, but also implementedBy objects
|
||||
while stack:
|
||||
iface = stack.pop(0)
|
||||
if iface in seen or not isinstance(iface, ABCInterfaceClass):
|
||||
continue
|
||||
seen.add(iface)
|
||||
stack.extend(list(iface.dependents))
|
||||
if not predicate(iface):
|
||||
continue
|
||||
|
||||
registered = set(iface.getRegisteredConformers())
|
||||
registered -= set(iface._ABCInterfaceClass__ignored_classes)
|
||||
if registered:
|
||||
yield iface, registered
|
||||
|
||||
|
||||
def add_abc_interface_tests(cls, module):
|
||||
def predicate(iface):
|
||||
return iface.__module__ == module
|
||||
add_verify_tests(cls, iter_abc_interfaces(predicate))
|
||||
|
||||
|
||||
def add_verify_tests(cls, iface_classes_iter):
|
||||
cls.maxDiff = None
|
||||
for iface, registered_classes in iface_classes_iter:
|
||||
for stdlib_class in registered_classes:
|
||||
def test(self, stdlib_class=stdlib_class, iface=iface):
|
||||
if stdlib_class in self.UNVERIFIABLE or stdlib_class.__name__ in self.UNVERIFIABLE:
|
||||
self.skipTest("Unable to verify %s" % stdlib_class)
|
||||
|
||||
self.assertTrue(self.verify(iface, stdlib_class))
|
||||
|
||||
suffix = "{}_{}_{}_{}".format(
|
||||
stdlib_class.__module__.replace('.', '_'),
|
||||
stdlib_class.__name__,
|
||||
iface.__module__.replace('.', '_'),
|
||||
iface.__name__
|
||||
)
|
||||
name = 'test_auto_' + suffix
|
||||
test.__name__ = name
|
||||
assert not hasattr(cls, name), (name, list(cls.__dict__))
|
||||
setattr(cls, name, test)
|
||||
|
||||
def test_ro(self, stdlib_class=stdlib_class, iface=iface):
|
||||
from zope.interface import ro
|
||||
from zope.interface import implementedBy
|
||||
from zope.interface import Interface
|
||||
self.assertEqual(
|
||||
tuple(ro.ro(iface, strict=True)),
|
||||
iface.__sro__)
|
||||
implements = implementedBy(stdlib_class)
|
||||
sro = implements.__sro__
|
||||
self.assertIs(sro[-1], Interface)
|
||||
|
||||
if stdlib_class not in self.UNVERIFIABLE_RO:
|
||||
# Check that we got the strict C3 resolution order, unless
|
||||
# we know we cannot. Note that 'Interface' is virtual base
|
||||
# that doesn't necessarily appear at the same place in the
|
||||
# calculated SRO as in the final SRO.
|
||||
strict = stdlib_class not in self.NON_STRICT_RO
|
||||
isro = ro.ro(implements, strict=strict)
|
||||
isro.remove(Interface)
|
||||
isro.append(Interface)
|
||||
|
||||
self.assertEqual(tuple(isro), sro)
|
||||
|
||||
name = 'test_auto_ro_' + suffix
|
||||
test_ro.__name__ = name
|
||||
assert not hasattr(cls, name)
|
||||
setattr(cls, name, test_ro)
|
||||
|
||||
class VerifyClassMixin(unittest.TestCase):
|
||||
verifier = staticmethod(verifyClass)
|
||||
UNVERIFIABLE = ()
|
||||
NON_STRICT_RO = ()
|
||||
UNVERIFIABLE_RO = ()
|
||||
|
||||
def _adjust_object_before_verify(self, iface, x):
|
||||
return x
|
||||
|
||||
def verify(self, iface, klass, **kwargs):
|
||||
return self.verifier(iface,
|
||||
self._adjust_object_before_verify(iface, klass),
|
||||
**kwargs)
|
||||
|
||||
|
||||
class VerifyObjectMixin(VerifyClassMixin):
|
||||
verifier = staticmethod(verifyObject)
|
||||
CONSTRUCTORS = {
|
||||
}
|
||||
|
||||
def _adjust_object_before_verify(self, iface, x):
|
||||
constructor = self.CONSTRUCTORS.get(x)
|
||||
if not constructor:
|
||||
constructor = self.CONSTRUCTORS.get(iface)
|
||||
if not constructor:
|
||||
constructor = self.CONSTRUCTORS.get(x.__name__)
|
||||
if not constructor:
|
||||
constructor = x
|
||||
if constructor is unittest.SkipTest:
|
||||
self.skipTest("Cannot create " + str(x))
|
||||
|
||||
result = constructor()
|
||||
if hasattr(result, 'close'):
|
||||
self.addCleanup(result.close)
|
||||
return result
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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:
|
||||
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()
|
||||
@@ -0,0 +1,43 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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
|
||||
|
||||
from zope.interface.common import builtins
|
||||
|
||||
from . import VerifyClassMixin
|
||||
from . import VerifyObjectMixin
|
||||
from . import add_verify_tests
|
||||
|
||||
|
||||
class TestVerifyClass(VerifyClassMixin,
|
||||
unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
add_verify_tests(TestVerifyClass, (
|
||||
(builtins.IList, (list,)),
|
||||
(builtins.ITuple, (tuple,)),
|
||||
(builtins.ITextString, (str,)),
|
||||
(builtins.IByteString, (bytes,)),
|
||||
(builtins.INativeString, (str,)),
|
||||
(builtins.IBool, (bool,)),
|
||||
(builtins.IDict, (dict,)),
|
||||
(builtins.IFile, ()),
|
||||
))
|
||||
|
||||
|
||||
class TestVerifyObject(VerifyObjectMixin,
|
||||
TestVerifyClass):
|
||||
CONSTRUCTORS = {
|
||||
builtins.IFile: lambda: open(__file__)
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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 array
|
||||
import unittest
|
||||
from collections import abc
|
||||
from collections import deque
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
from types import MappingProxyType
|
||||
|
||||
from zope.interface import Invalid
|
||||
|
||||
|
||||
# Note that importing z.i.c.collections does work on import.
|
||||
from zope.interface.common import collections
|
||||
|
||||
|
||||
from zope.interface._compat import PYPY
|
||||
|
||||
|
||||
from . import add_abc_interface_tests
|
||||
from . import VerifyClassMixin
|
||||
from . import VerifyObjectMixin
|
||||
|
||||
class TestVerifyClass(VerifyClassMixin, unittest.TestCase):
|
||||
|
||||
# Here we test some known builtin classes that are defined to implement
|
||||
# various collection interfaces as a quick sanity test.
|
||||
def test_frozenset(self):
|
||||
self.assertIsInstance(frozenset(), abc.Set)
|
||||
self.assertTrue(self.verify(collections.ISet, frozenset))
|
||||
|
||||
def test_list(self):
|
||||
self.assertIsInstance(list(), abc.MutableSequence)
|
||||
self.assertTrue(self.verify(collections.IMutableSequence, list))
|
||||
|
||||
# Here we test some derived classes.
|
||||
def test_UserList(self):
|
||||
self.assertTrue(self.verify(collections.IMutableSequence,
|
||||
collections.UserList))
|
||||
|
||||
def test_UserDict(self):
|
||||
self.assertTrue(self.verify(collections.IMutableMapping,
|
||||
collections.UserDict))
|
||||
|
||||
def test_UserString(self):
|
||||
self.assertTrue(self.verify(collections.ISequence,
|
||||
collections.UserString))
|
||||
|
||||
# Now we go through the registry, which should have several things,
|
||||
# mostly builtins, but if we've imported other libraries already,
|
||||
# it could contain things from outside of there too. We aren't concerned
|
||||
# about third-party code here, just standard library types. We start with a
|
||||
# blacklist of things to exclude, but if that gets out of hand we can figure
|
||||
# out a better whitelisting.
|
||||
UNVERIFIABLE = {
|
||||
# This is declared to be an ISequence, but is missing lots of methods,
|
||||
# including some that aren't part of a language protocol, such as
|
||||
# ``index`` and ``count``.
|
||||
memoryview,
|
||||
# 'pkg_resources._vendor.pyparsing.ParseResults' is registered as a
|
||||
# MutableMapping but is missing methods like ``popitem`` and ``setdefault``.
|
||||
# It's imported due to namespace packages.
|
||||
'ParseResults',
|
||||
# sqlite3.Row claims ISequence but also misses ``index`` and ``count``.
|
||||
# It's imported because...? Coverage imports it, but why do we have it without
|
||||
# coverage?
|
||||
'Row',
|
||||
# In Python 3.10 ``array.array`` appears as ``IMutableSequence`` but it
|
||||
# does not provide a ``clear()`` method and it cannot be instantiated
|
||||
# using ``array.array()``.
|
||||
array.array,
|
||||
}
|
||||
|
||||
if PYPY:
|
||||
UNVERIFIABLE.update({
|
||||
# collections.deque.pop() doesn't support the index= argument to
|
||||
# MutableSequence.pop(). We can't verify this on CPython because we can't
|
||||
# get the signature, but on PyPy we /can/ get the signature, and of course
|
||||
# it doesn't match.
|
||||
deque,
|
||||
# Likewise for index
|
||||
range,
|
||||
})
|
||||
UNVERIFIABLE_RO = {
|
||||
# ``array.array`` fails the ``test_auto_ro_*`` tests with and
|
||||
# without strict RO but only on Windows (AppVeyor) on Python 3.10.0
|
||||
# (in older versions ``array.array`` does not appear as
|
||||
# ``IMutableSequence``).
|
||||
array.array,
|
||||
}
|
||||
|
||||
add_abc_interface_tests(TestVerifyClass, collections.ISet.__module__)
|
||||
|
||||
|
||||
class TestVerifyObject(VerifyObjectMixin,
|
||||
TestVerifyClass):
|
||||
CONSTRUCTORS = {
|
||||
collections.IValuesView: {}.values,
|
||||
collections.IItemsView: {}.items,
|
||||
collections.IKeysView: {}.keys,
|
||||
memoryview: lambda: memoryview(b'abc'),
|
||||
range: lambda: range(10),
|
||||
MappingProxyType: lambda: MappingProxyType({}),
|
||||
collections.UserString: lambda: collections.UserString('abc'),
|
||||
type(iter(bytearray())): lambda: iter(bytearray()),
|
||||
type(iter(b'abc')): lambda: iter(b'abc'),
|
||||
'coroutine': unittest.SkipTest,
|
||||
type(iter({}.keys())): lambda: iter({}.keys()),
|
||||
type(iter({}.items())): lambda: iter({}.items()),
|
||||
type(iter({}.values())): lambda: iter({}.values()),
|
||||
type(i for i in range(1)): lambda: (i for i in range(3)),
|
||||
type(iter([])): lambda: iter([]),
|
||||
type(reversed([])): lambda: reversed([]),
|
||||
'longrange_iterator': unittest.SkipTest,
|
||||
'range_iterator': lambda: iter(range(3)),
|
||||
'rangeiterator': lambda: iter(range(3)),
|
||||
type(iter(set())): lambda: iter(set()),
|
||||
type(iter('')): lambda: iter(''),
|
||||
'async_generator': unittest.SkipTest,
|
||||
type(iter(tuple())): lambda: iter(tuple()),
|
||||
}
|
||||
|
||||
UNVERIFIABLE_RO = {
|
||||
# ``array.array`` fails the ``test_auto_ro_*`` tests with and
|
||||
# without strict RO but only on Windows (AppVeyor) on Python 3.10.0
|
||||
# (in older versions ``array.array`` does not appear as
|
||||
# ``IMutableSequence``).
|
||||
array.array,
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,42 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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
|
||||
import io as abc
|
||||
|
||||
# Note that importing z.i.c.io does work on import.
|
||||
from zope.interface.common import io
|
||||
|
||||
from . import add_abc_interface_tests
|
||||
from . import VerifyClassMixin
|
||||
from . import VerifyObjectMixin
|
||||
|
||||
|
||||
class TestVerifyClass(VerifyClassMixin,
|
||||
unittest.TestCase):
|
||||
pass
|
||||
|
||||
add_abc_interface_tests(TestVerifyClass, io.IIOBase.__module__)
|
||||
|
||||
|
||||
class TestVerifyObject(VerifyObjectMixin,
|
||||
TestVerifyClass):
|
||||
CONSTRUCTORS = {
|
||||
abc.BufferedWriter: lambda: abc.BufferedWriter(abc.StringIO()),
|
||||
abc.BufferedReader: lambda: abc.BufferedReader(abc.StringIO()),
|
||||
abc.TextIOWrapper: lambda: abc.TextIOWrapper(abc.BytesIO()),
|
||||
abc.BufferedRandom: lambda: abc.BufferedRandom(abc.BytesIO()),
|
||||
abc.BufferedRWPair: lambda: abc.BufferedRWPair(abc.BytesIO(), abc.BytesIO()),
|
||||
abc.FileIO: lambda: abc.FileIO(__file__),
|
||||
'_WindowsConsoleIO': unittest.SkipTest,
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2020 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
|
||||
import numbers as abc
|
||||
|
||||
# Note that importing z.i.c.numbers does work on import.
|
||||
from zope.interface.common import numbers
|
||||
|
||||
from . import add_abc_interface_tests
|
||||
from . import VerifyClassMixin
|
||||
from . import VerifyObjectMixin
|
||||
|
||||
|
||||
class TestVerifyClass(VerifyClassMixin,
|
||||
unittest.TestCase):
|
||||
|
||||
def test_int(self):
|
||||
self.assertIsInstance(int(), abc.Integral)
|
||||
self.assertTrue(self.verify(numbers.IIntegral, int))
|
||||
|
||||
def test_float(self):
|
||||
self.assertIsInstance(float(), abc.Real)
|
||||
self.assertTrue(self.verify(numbers.IReal, float))
|
||||
|
||||
add_abc_interface_tests(TestVerifyClass, numbers.INumber.__module__)
|
||||
|
||||
|
||||
class TestVerifyObject(VerifyObjectMixin,
|
||||
TestVerifyClass):
|
||||
pass
|
||||
1188
venv/lib/python3.11/site-packages/zope/interface/declarations.py
Normal file
1188
venv/lib/python3.11/site-packages/zope/interface/declarations.py
Normal file
File diff suppressed because it is too large
Load Diff
124
venv/lib/python3.11/site-packages/zope/interface/document.py
Normal file
124
venv/lib/python3.11/site-packages/zope/interface/document.py
Normal file
@@ -0,0 +1,124 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
__all__ = [
|
||||
'asReStructuredText',
|
||||
'asStructuredText',
|
||||
]
|
||||
|
||||
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: "``{}``".format(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 = "{} -- {}".format(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 = "{}{}".format(desc.getName(), desc.getSignatureString())
|
||||
item = "{} -- {}".format(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)
|
||||
275
venv/lib/python3.11/site-packages/zope/interface/exceptions.py
Normal file
275
venv/lib/python3.11/site-packages/zope/interface/exceptions.py
Normal file
@@ -0,0 +1,275 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
# Invalid tree
|
||||
'Invalid',
|
||||
'DoesNotImplement',
|
||||
'BrokenImplementation',
|
||||
'BrokenMethodImplementation',
|
||||
'MultipleInvalid',
|
||||
# Other
|
||||
'BadImplements',
|
||||
'InvalidInterface',
|
||||
]
|
||||
|
||||
class Invalid(Exception):
|
||||
"""A specification is violated
|
||||
"""
|
||||
|
||||
|
||||
class _TargetInvalid(Invalid):
|
||||
# Internal use. Subclass this when you're describing
|
||||
# a particular target object that's invalid according
|
||||
# to a specific interface.
|
||||
#
|
||||
# For backwards compatibility, the *target* and *interface* are
|
||||
# optional, and the signatures are inconsistent in their ordering.
|
||||
#
|
||||
# We deal with the inconsistency in ordering by defining the index
|
||||
# of the two values in ``self.args``. *target* uses a marker object to
|
||||
# distinguish "not given" from "given, but None", because the latter
|
||||
# can be a value that gets passed to validation. For this reason, it must
|
||||
# always be the last argument (we detect absence by the ``IndexError``).
|
||||
|
||||
_IX_INTERFACE = 0
|
||||
_IX_TARGET = 1
|
||||
# The exception to catch when indexing self.args indicating that
|
||||
# an argument was not given. If all arguments are expected,
|
||||
# a subclass should set this to ().
|
||||
_NOT_GIVEN_CATCH = IndexError
|
||||
_NOT_GIVEN = '<Not Given>'
|
||||
|
||||
def _get_arg_or_default(self, ix, default=None):
|
||||
try:
|
||||
return self.args[ix] # pylint:disable=unsubscriptable-object
|
||||
except self._NOT_GIVEN_CATCH:
|
||||
return default
|
||||
|
||||
@property
|
||||
def interface(self):
|
||||
return self._get_arg_or_default(self._IX_INTERFACE)
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
return self._get_arg_or_default(self._IX_TARGET, self._NOT_GIVEN)
|
||||
|
||||
###
|
||||
# str
|
||||
#
|
||||
# The ``__str__`` of self is implemented by concatenating (%s), in order,
|
||||
# these properties (none of which should have leading or trailing
|
||||
# whitespace):
|
||||
#
|
||||
# - self._str_subject
|
||||
# Begin the message, including a description of the target.
|
||||
# - self._str_description
|
||||
# Provide a general description of the type of error, including
|
||||
# the interface name if possible and relevant.
|
||||
# - self._str_conjunction
|
||||
# Join the description to the details. Defaults to ": ".
|
||||
# - self._str_details
|
||||
# Provide details about how this particular instance of the error.
|
||||
# - self._str_trailer
|
||||
# End the message. Usually just a period.
|
||||
###
|
||||
|
||||
@property
|
||||
def _str_subject(self):
|
||||
target = self.target
|
||||
if target is self._NOT_GIVEN:
|
||||
return "An object"
|
||||
return "The object {!r}".format(target)
|
||||
|
||||
@property
|
||||
def _str_description(self):
|
||||
return "has failed to implement interface %s" % (
|
||||
self.interface or '<Unknown>'
|
||||
)
|
||||
|
||||
_str_conjunction = ": "
|
||||
_str_details = "<unknown>"
|
||||
_str_trailer = '.'
|
||||
|
||||
def __str__(self):
|
||||
return "{} {}{}{}{}".format(
|
||||
self._str_subject,
|
||||
self._str_description,
|
||||
self._str_conjunction,
|
||||
self._str_details,
|
||||
self._str_trailer
|
||||
)
|
||||
|
||||
|
||||
class DoesNotImplement(_TargetInvalid):
|
||||
"""
|
||||
DoesNotImplement(interface[, target])
|
||||
|
||||
The *target* (optional) does not implement the *interface*.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Add the *target* argument and attribute, and change the resulting
|
||||
string value of this object accordingly.
|
||||
"""
|
||||
|
||||
_str_details = "Does not declaratively implement the interface"
|
||||
|
||||
|
||||
class BrokenImplementation(_TargetInvalid):
|
||||
"""
|
||||
BrokenImplementation(interface, name[, target])
|
||||
|
||||
The *target* (optional) is missing the attribute *name*.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Add the *target* argument and attribute, and change the resulting
|
||||
string value of this object accordingly.
|
||||
|
||||
The *name* can either be a simple string or a ``Attribute`` object.
|
||||
"""
|
||||
|
||||
_IX_NAME = _TargetInvalid._IX_INTERFACE + 1
|
||||
_IX_TARGET = _IX_NAME + 1
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.args[1] # pylint:disable=unsubscriptable-object
|
||||
|
||||
@property
|
||||
def _str_details(self):
|
||||
return "The %s attribute was not provided" % (
|
||||
repr(self.name) if isinstance(self.name, str) else self.name
|
||||
)
|
||||
|
||||
|
||||
class BrokenMethodImplementation(_TargetInvalid):
|
||||
"""
|
||||
BrokenMethodImplementation(method, message[, implementation, interface, target])
|
||||
|
||||
The *target* (optional) has a *method* in *implementation* that violates
|
||||
its contract in a way described by *mess*.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Add the *interface* and *target* argument and attribute,
|
||||
and change the resulting string value of this object accordingly.
|
||||
|
||||
The *method* can either be a simple string or a ``Method`` object.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
If *implementation* is given, then the *message* will have the
|
||||
string "implementation" replaced with an short but informative
|
||||
representation of *implementation*.
|
||||
|
||||
"""
|
||||
|
||||
_IX_IMPL = 2
|
||||
_IX_INTERFACE = _IX_IMPL + 1
|
||||
_IX_TARGET = _IX_INTERFACE + 1
|
||||
|
||||
@property
|
||||
def method(self):
|
||||
return self.args[0] # pylint:disable=unsubscriptable-object
|
||||
|
||||
@property
|
||||
def mess(self):
|
||||
return self.args[1] # pylint:disable=unsubscriptable-object
|
||||
|
||||
@staticmethod
|
||||
def __implementation_str(impl):
|
||||
# It could be a callable or some arbitrary object, we don't
|
||||
# know yet.
|
||||
import inspect # Inspect is a heavy-weight dependency, lots of imports
|
||||
try:
|
||||
sig = inspect.signature
|
||||
formatsig = str
|
||||
except AttributeError:
|
||||
sig = inspect.getargspec
|
||||
f = inspect.formatargspec
|
||||
formatsig = lambda sig: f(*sig) # pylint:disable=deprecated-method
|
||||
|
||||
try:
|
||||
sig = sig(impl)
|
||||
except (ValueError, TypeError):
|
||||
# Unable to introspect. Darn.
|
||||
# This could be a non-callable, or a particular builtin,
|
||||
# or a bound method that doesn't even accept 'self', e.g.,
|
||||
# ``Class.method = lambda: None; Class().method``
|
||||
return repr(impl)
|
||||
|
||||
try:
|
||||
name = impl.__qualname__
|
||||
except AttributeError:
|
||||
name = impl.__name__
|
||||
|
||||
return name + formatsig(sig)
|
||||
|
||||
@property
|
||||
def _str_details(self):
|
||||
impl = self._get_arg_or_default(self._IX_IMPL, self._NOT_GIVEN)
|
||||
message = self.mess
|
||||
if impl is not self._NOT_GIVEN and 'implementation' in message:
|
||||
message = message.replace("implementation", '%r')
|
||||
message = message % (self.__implementation_str(impl),)
|
||||
|
||||
return 'The contract of {} is violated because {}'.format(
|
||||
repr(self.method) if isinstance(self.method, str) else self.method,
|
||||
message,
|
||||
)
|
||||
|
||||
|
||||
class MultipleInvalid(_TargetInvalid):
|
||||
"""
|
||||
The *target* has failed to implement the *interface* in
|
||||
multiple ways.
|
||||
|
||||
The failures are described by *exceptions*, a collection of
|
||||
other `Invalid` instances.
|
||||
|
||||
.. versionadded:: 5.0
|
||||
"""
|
||||
|
||||
_NOT_GIVEN_CATCH = ()
|
||||
|
||||
def __init__(self, interface, target, exceptions):
|
||||
super().__init__(interface, target, tuple(exceptions))
|
||||
|
||||
@property
|
||||
def exceptions(self):
|
||||
return self.args[2] # pylint:disable=unsubscriptable-object
|
||||
|
||||
@property
|
||||
def _str_details(self):
|
||||
# It would be nice to use tabs here, but that
|
||||
# is hard to represent in doctests.
|
||||
return '\n ' + '\n '.join(
|
||||
x._str_details.strip() if isinstance(x, _TargetInvalid) else str(x)
|
||||
for x in self.exceptions
|
||||
)
|
||||
|
||||
_str_conjunction = ':' # We don't want a trailing space, messes up doctests
|
||||
_str_trailer = ''
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
1131
venv/lib/python3.11/site-packages/zope/interface/interface.py
Normal file
1131
venv/lib/python3.11/site-packages/zope/interface/interface.py
Normal file
File diff suppressed because it is too large
Load Diff
1480
venv/lib/python3.11/site-packages/zope/interface/interfaces.py
Normal file
1480
venv/lib/python3.11/site-packages/zope/interface/interfaces.py
Normal file
File diff suppressed because it is too large
Load Diff
723
venv/lib/python3.11/site-packages/zope/interface/registry.py
Normal file
723
venv/lib/python3.11/site-packages/zope/interface/registry.py
Normal file
@@ -0,0 +1,723 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
__all__ = [
|
||||
# Components is public API, but
|
||||
# the *Registration classes are just implementations
|
||||
# of public interfaces.
|
||||
'Components',
|
||||
]
|
||||
|
||||
class _UnhashableComponentCounter:
|
||||
# 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:
|
||||
|
||||
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:
|
||||
|
||||
_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, str)
|
||||
self.__name__ = name
|
||||
self._init_registries()
|
||||
self._init_registrations()
|
||||
self.__bases__ = tuple(bases)
|
||||
self._v_utility_registrations_cache = None
|
||||
|
||||
def __repr__(self):
|
||||
return "<{} {}>".format(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().__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='',
|
||||
info='', 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 == '':
|
||||
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='',
|
||||
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='', default=None):
|
||||
return self.utilities.lookup((), provided, name, default)
|
||||
|
||||
def getUtility(self, provided, name=''):
|
||||
utility = self.utilities.lookup((), provided, name)
|
||||
if utility is None:
|
||||
raise ComponentLookupError(provided, name)
|
||||
return utility
|
||||
|
||||
def getUtilitiesFor(self, interface):
|
||||
yield from self.utilities.lookupAll((), interface)
|
||||
|
||||
def getAllUtilitiesRegisteredFor(self, interface):
|
||||
return self.utilities.subscriptions((), interface)
|
||||
|
||||
def registerAdapter(self, factory, required=None, provided=None,
|
||||
name='', info='', event=True):
|
||||
if provided is None:
|
||||
provided = _getAdapterProvided(factory)
|
||||
required = _getAdapterRequired(factory, required)
|
||||
if name == '':
|
||||
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='',
|
||||
):
|
||||
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='', default=None):
|
||||
return self.adapters.queryAdapter(object, interface, name, default)
|
||||
|
||||
def getAdapter(self, object, interface, name=''):
|
||||
adapter = self.adapters.queryAdapter(object, interface, name)
|
||||
if adapter is None:
|
||||
raise ComponentLookupError(object, interface, name)
|
||||
return adapter
|
||||
|
||||
def queryMultiAdapter(self, objects, interface, name='',
|
||||
default=None):
|
||||
return self.adapters.queryMultiAdapter(
|
||||
objects, interface, name, default)
|
||||
|
||||
def getMultiAdapter(self, objects, interface, name=''):
|
||||
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='', info='',
|
||||
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='',
|
||||
):
|
||||
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='', info='',
|
||||
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=''):
|
||||
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 rebuildUtilityRegistryFromLocalCache(self, rebuild=False):
|
||||
"""
|
||||
Emergency maintenance method to rebuild the ``.utilities``
|
||||
registry from the local copy maintained in this object, or
|
||||
detect the need to do so.
|
||||
|
||||
Most users will never need to call this, but it can be helpful
|
||||
in the event of suspected corruption.
|
||||
|
||||
By default, this method only checks for corruption. To make it
|
||||
actually rebuild the registry, pass `True` for *rebuild*.
|
||||
|
||||
:param bool rebuild: If set to `True` (not the default),
|
||||
this method will actually register and subscribe utilities
|
||||
in the registry as needed to synchronize with the local cache.
|
||||
|
||||
:return: A dictionary that's meant as diagnostic data. The keys
|
||||
and values may change over time. When called with a false *rebuild*,
|
||||
the keys ``"needed_registered"`` and ``"needed_subscribed"`` will be
|
||||
non-zero if any corruption was detected, but that will not be corrected.
|
||||
|
||||
.. versionadded:: 5.3.0
|
||||
"""
|
||||
regs = dict(self._utility_registrations)
|
||||
utils = self.utilities
|
||||
needed_registered = 0
|
||||
did_not_register = 0
|
||||
needed_subscribed = 0
|
||||
did_not_subscribe = 0
|
||||
|
||||
|
||||
# Avoid the expensive change process during this; we'll call
|
||||
# it once at the end if needed.
|
||||
assert 'changed' not in utils.__dict__
|
||||
utils.changed = lambda _: None
|
||||
|
||||
if rebuild:
|
||||
register = utils.register
|
||||
subscribe = utils.subscribe
|
||||
else:
|
||||
register = subscribe = lambda *args: None
|
||||
|
||||
try:
|
||||
for (provided, name), (value, _info, _factory) in regs.items():
|
||||
if utils.registered((), provided, name) != value:
|
||||
register((), provided, name, value)
|
||||
needed_registered += 1
|
||||
else:
|
||||
did_not_register += 1
|
||||
|
||||
if utils.subscribed((), provided, value) is None:
|
||||
needed_subscribed += 1
|
||||
subscribe((), provided, value)
|
||||
else:
|
||||
did_not_subscribe += 1
|
||||
finally:
|
||||
del utils.changed
|
||||
if rebuild and (needed_subscribed or needed_registered):
|
||||
utils.changed(utils)
|
||||
|
||||
return {
|
||||
'needed_registered': needed_registered,
|
||||
'did_not_register': did_not_register,
|
||||
'needed_subscribed': needed_subscribed,
|
||||
'did_not_subscribe': did_not_subscribe
|
||||
}
|
||||
|
||||
def _getName(component):
|
||||
try:
|
||||
return component.__component_name__
|
||||
except AttributeError:
|
||||
return ''
|
||||
|
||||
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, type):
|
||||
r = implementedBy(r)
|
||||
else:
|
||||
raise TypeError("Required specification must be a "
|
||||
"specification or class, not %r" % type(r)
|
||||
)
|
||||
result.append(r)
|
||||
return tuple(result)
|
||||
|
||||
|
||||
@implementer(IUtilityRegistration)
|
||||
class UtilityRegistration:
|
||||
|
||||
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 '{}({!r}, {}, {!r}, {}, {!r}, {!r})'.format(
|
||||
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:
|
||||
|
||||
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 '{}({!r}, {}, {}, {!r}, {}, {!r})'.format(
|
||||
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 '{}({!r}, {}, {!r}, {}, {!r})'.format(
|
||||
self.__class__.__name__,
|
||||
self.registry,
|
||||
'[' + ", ".join([r.__name__ for r in self.required]) + ']',
|
||||
self.name,
|
||||
getattr(self.factory, '__name__', repr(self.factory)), self.info,
|
||||
)
|
||||
665
venv/lib/python3.11/site-packages/zope/interface/ro.py
Normal file
665
venv/lib/python3.11/site-packages/zope/interface/ro.py
Normal file
@@ -0,0 +1,665 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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.
|
||||
|
||||
.. versionchanged:: 5.0
|
||||
The resolution order is now based on the same C3 order that Python
|
||||
uses for classes. In complex instances of multiple inheritance, this
|
||||
may result in a different ordering.
|
||||
|
||||
In older versions, the ordering wasn't required to be C3 compliant,
|
||||
and for backwards compatibility, it still isn't. If the ordering
|
||||
isn't C3 compliant (if it is *inconsistent*), zope.interface will
|
||||
make a best guess to try to produce a reasonable resolution order.
|
||||
Still (just as before), the results in such cases may be
|
||||
surprising.
|
||||
|
||||
.. rubric:: Environment Variables
|
||||
|
||||
Due to the change in 5.0, certain environment variables can be used to control errors
|
||||
and warnings about inconsistent resolution orders. They are listed in priority order, with
|
||||
variables at the bottom generally overriding variables above them.
|
||||
|
||||
ZOPE_INTERFACE_WARN_BAD_IRO
|
||||
If this is set to "1", then if there is at least one inconsistent resolution
|
||||
order discovered, a warning (:class:`InconsistentResolutionOrderWarning`) will
|
||||
be issued. Use the usual warning mechanisms to control this behaviour. The warning
|
||||
text will contain additional information on debugging.
|
||||
ZOPE_INTERFACE_TRACK_BAD_IRO
|
||||
If this is set to "1", then zope.interface will log information about each
|
||||
inconsistent resolution order discovered, and keep those details in memory in this module
|
||||
for later inspection.
|
||||
ZOPE_INTERFACE_STRICT_IRO
|
||||
If this is set to "1", any attempt to use :func:`ro` that would produce a non-C3
|
||||
ordering will fail by raising :class:`InconsistentResolutionOrderError`.
|
||||
|
||||
.. important::
|
||||
|
||||
``ZOPE_INTERFACE_STRICT_IRO`` is intended to become the default in the future.
|
||||
|
||||
There are two environment variables that are independent.
|
||||
|
||||
ZOPE_INTERFACE_LOG_CHANGED_IRO
|
||||
If this is set to "1", then if the C3 resolution order is different from
|
||||
the legacy resolution order for any given object, a message explaining the differences
|
||||
will be logged. This is intended to be used for debugging complicated IROs.
|
||||
ZOPE_INTERFACE_USE_LEGACY_IRO
|
||||
If this is set to "1", then the C3 resolution order will *not* be used. The
|
||||
legacy IRO will be used instead. This is a temporary measure and will be removed in the
|
||||
future. It is intended to help during the transition.
|
||||
It implies ``ZOPE_INTERFACE_LOG_CHANGED_IRO``.
|
||||
|
||||
.. rubric:: Debugging Behaviour Changes in zope.interface 5
|
||||
|
||||
Most behaviour changes from zope.interface 4 to 5 are related to
|
||||
inconsistent resolution orders. ``ZOPE_INTERFACE_STRICT_IRO`` is the
|
||||
most effective tool to find such inconsistent resolution orders, and
|
||||
we recommend running your code with this variable set if at all
|
||||
possible. Doing so will ensure that all interface resolution orders
|
||||
are consistent, and if they're not, will immediately point the way to
|
||||
where this is violated.
|
||||
|
||||
Occasionally, however, this may not be enough. This is because in some
|
||||
cases, a C3 ordering can be found (the resolution order is fully
|
||||
consistent) that is substantially different from the ad-hoc legacy
|
||||
ordering. In such cases, you may find that you get an unexpected value
|
||||
returned when adapting one or more objects to an interface. To debug
|
||||
this, *also* enable ``ZOPE_INTERFACE_LOG_CHANGED_IRO`` and examine the
|
||||
output. The main thing to look for is changes in the relative
|
||||
positions of interfaces for which there are registered adapters.
|
||||
"""
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
__all__ = [
|
||||
'ro',
|
||||
'InconsistentResolutionOrderError',
|
||||
'InconsistentResolutionOrderWarning',
|
||||
]
|
||||
|
||||
__logger = None
|
||||
|
||||
def _logger():
|
||||
global __logger # pylint:disable=global-statement
|
||||
if __logger is None:
|
||||
import logging
|
||||
__logger = logging.getLogger(__name__)
|
||||
return __logger
|
||||
|
||||
def _legacy_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 = set()
|
||||
result = []
|
||||
for ordering in reversed(orderings):
|
||||
for o in reversed(ordering):
|
||||
if o not in seen:
|
||||
seen.add(o)
|
||||
result.insert(0, o)
|
||||
|
||||
return result
|
||||
|
||||
def _legacy_flatten(begin):
|
||||
result = [begin]
|
||||
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 _legacy_ro(ob):
|
||||
return _legacy_mergeOrderings([_legacy_flatten(ob)])
|
||||
|
||||
###
|
||||
# Compare base objects using identity, not equality. This matches what
|
||||
# the CPython MRO algorithm does, and is *much* faster to boot: that,
|
||||
# plus some other small tweaks makes the difference between 25s and 6s
|
||||
# in loading 446 plone/zope interface.py modules (1925 InterfaceClass,
|
||||
# 1200 Implements, 1100 ClassProvides objects)
|
||||
###
|
||||
|
||||
|
||||
class InconsistentResolutionOrderWarning(PendingDeprecationWarning):
|
||||
"""
|
||||
The warning issued when an invalid IRO is requested.
|
||||
"""
|
||||
|
||||
class InconsistentResolutionOrderError(TypeError):
|
||||
"""
|
||||
The error raised when an invalid IRO is requested in strict mode.
|
||||
"""
|
||||
|
||||
def __init__(self, c3, base_tree_remaining):
|
||||
self.C = c3.leaf
|
||||
base_tree = c3.base_tree
|
||||
self.base_ros = {
|
||||
base: base_tree[i + 1]
|
||||
for i, base in enumerate(self.C.__bases__)
|
||||
}
|
||||
# Unfortunately, this doesn't necessarily directly match
|
||||
# up to any transformation on C.__bases__, because
|
||||
# if any were fully used up, they were removed already.
|
||||
self.base_tree_remaining = base_tree_remaining
|
||||
|
||||
TypeError.__init__(self)
|
||||
|
||||
def __str__(self):
|
||||
import pprint
|
||||
return "{}: For object {!r}.\nBase ROs:\n{}\nConflict Location:\n{}".format(
|
||||
self.__class__.__name__,
|
||||
self.C,
|
||||
pprint.pformat(self.base_ros),
|
||||
pprint.pformat(self.base_tree_remaining),
|
||||
)
|
||||
|
||||
|
||||
class _NamedBool(int): # cannot actually inherit bool
|
||||
|
||||
def __new__(cls, val, name):
|
||||
inst = super(cls, _NamedBool).__new__(cls, val)
|
||||
inst.__name__ = name
|
||||
return inst
|
||||
|
||||
|
||||
class _ClassBoolFromEnv:
|
||||
"""
|
||||
Non-data descriptor that reads a transformed environment variable
|
||||
as a boolean, and caches the result in the class.
|
||||
"""
|
||||
|
||||
def __get__(self, inst, klass):
|
||||
import os
|
||||
for cls in klass.__mro__:
|
||||
my_name = None
|
||||
for k in dir(klass):
|
||||
if k in cls.__dict__ and cls.__dict__[k] is self:
|
||||
my_name = k
|
||||
break
|
||||
if my_name is not None:
|
||||
break
|
||||
else: # pragma: no cover
|
||||
raise RuntimeError("Unable to find self")
|
||||
|
||||
env_name = 'ZOPE_INTERFACE_' + my_name
|
||||
val = os.environ.get(env_name, '') == '1'
|
||||
val = _NamedBool(val, my_name)
|
||||
setattr(klass, my_name, val)
|
||||
setattr(klass, 'ORIG_' + my_name, self)
|
||||
return val
|
||||
|
||||
|
||||
class _StaticMRO:
|
||||
# A previously resolved MRO, supplied by the caller.
|
||||
# Used in place of calculating it.
|
||||
|
||||
had_inconsistency = None # We don't know...
|
||||
|
||||
def __init__(self, C, mro):
|
||||
self.leaf = C
|
||||
self.__mro = tuple(mro)
|
||||
|
||||
def mro(self):
|
||||
return list(self.__mro)
|
||||
|
||||
|
||||
class C3:
|
||||
# Holds the shared state during computation of an MRO.
|
||||
|
||||
@staticmethod
|
||||
def resolver(C, strict, base_mros):
|
||||
strict = strict if strict is not None else C3.STRICT_IRO
|
||||
factory = C3
|
||||
if strict:
|
||||
factory = _StrictC3
|
||||
elif C3.TRACK_BAD_IRO:
|
||||
factory = _TrackingC3
|
||||
|
||||
memo = {}
|
||||
base_mros = base_mros or {}
|
||||
for base, mro in base_mros.items():
|
||||
assert base in C.__bases__
|
||||
memo[base] = _StaticMRO(base, mro)
|
||||
|
||||
return factory(C, memo)
|
||||
|
||||
__mro = None
|
||||
__legacy_ro = None
|
||||
direct_inconsistency = False
|
||||
|
||||
def __init__(self, C, memo):
|
||||
self.leaf = C
|
||||
self.memo = memo
|
||||
kind = self.__class__
|
||||
|
||||
base_resolvers = []
|
||||
for base in C.__bases__:
|
||||
if base not in memo:
|
||||
resolver = kind(base, memo)
|
||||
memo[base] = resolver
|
||||
base_resolvers.append(memo[base])
|
||||
|
||||
self.base_tree = [
|
||||
[C]
|
||||
] + [
|
||||
memo[base].mro() for base in C.__bases__
|
||||
] + [
|
||||
list(C.__bases__)
|
||||
]
|
||||
|
||||
self.bases_had_inconsistency = any(base.had_inconsistency for base in base_resolvers)
|
||||
|
||||
if len(C.__bases__) == 1:
|
||||
self.__mro = [C] + memo[C.__bases__[0]].mro()
|
||||
|
||||
@property
|
||||
def had_inconsistency(self):
|
||||
return self.direct_inconsistency or self.bases_had_inconsistency
|
||||
|
||||
@property
|
||||
def legacy_ro(self):
|
||||
if self.__legacy_ro is None:
|
||||
self.__legacy_ro = tuple(_legacy_ro(self.leaf))
|
||||
return list(self.__legacy_ro)
|
||||
|
||||
TRACK_BAD_IRO = _ClassBoolFromEnv()
|
||||
STRICT_IRO = _ClassBoolFromEnv()
|
||||
WARN_BAD_IRO = _ClassBoolFromEnv()
|
||||
LOG_CHANGED_IRO = _ClassBoolFromEnv()
|
||||
USE_LEGACY_IRO = _ClassBoolFromEnv()
|
||||
BAD_IROS = ()
|
||||
|
||||
def _warn_iro(self):
|
||||
if not self.WARN_BAD_IRO:
|
||||
# For the initial release, one must opt-in to see the warning.
|
||||
# In the future (2021?) seeing at least the first warning will
|
||||
# be the default
|
||||
return
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"An inconsistent resolution order is being requested. "
|
||||
"(Interfaces should follow the Python class rules known as C3.) "
|
||||
"For backwards compatibility, zope.interface will allow this, "
|
||||
"making the best guess it can to produce as meaningful an order as possible. "
|
||||
"In the future this might be an error. Set the warning filter to error, or set "
|
||||
"the environment variable 'ZOPE_INTERFACE_TRACK_BAD_IRO' to '1' and examine "
|
||||
"ro.C3.BAD_IROS to debug, or set 'ZOPE_INTERFACE_STRICT_IRO' to raise exceptions.",
|
||||
InconsistentResolutionOrderWarning,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _can_choose_base(base, base_tree_remaining):
|
||||
# From C3:
|
||||
# nothead = [s for s in nonemptyseqs if cand in s[1:]]
|
||||
for bases in base_tree_remaining:
|
||||
if not bases or bases[0] is base:
|
||||
continue
|
||||
|
||||
for b in bases:
|
||||
if b is base:
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _nonempty_bases_ignoring(base_tree, ignoring):
|
||||
return list(filter(None, [
|
||||
[b for b in bases if b is not ignoring]
|
||||
for bases
|
||||
in base_tree
|
||||
]))
|
||||
|
||||
def _choose_next_base(self, base_tree_remaining):
|
||||
"""
|
||||
Return the next base.
|
||||
|
||||
The return value will either fit the C3 constraints or be our best
|
||||
guess about what to do. If we cannot guess, this may raise an exception.
|
||||
"""
|
||||
base = self._find_next_C3_base(base_tree_remaining)
|
||||
if base is not None:
|
||||
return base
|
||||
return self._guess_next_base(base_tree_remaining)
|
||||
|
||||
def _find_next_C3_base(self, base_tree_remaining):
|
||||
"""
|
||||
Return the next base that fits the constraints, or ``None`` if there isn't one.
|
||||
"""
|
||||
for bases in base_tree_remaining:
|
||||
base = bases[0]
|
||||
if self._can_choose_base(base, base_tree_remaining):
|
||||
return base
|
||||
return None
|
||||
|
||||
class _UseLegacyRO(Exception):
|
||||
pass
|
||||
|
||||
def _guess_next_base(self, base_tree_remaining):
|
||||
# Narf. We may have an inconsistent order (we won't know for
|
||||
# sure until we check all the bases). Python cannot create
|
||||
# classes like this:
|
||||
#
|
||||
# class B1:
|
||||
# pass
|
||||
# class B2(B1):
|
||||
# pass
|
||||
# class C(B1, B2): # -> TypeError; this is like saying C(B1, B2, B1).
|
||||
# pass
|
||||
#
|
||||
# However, older versions of zope.interface were fine with this order.
|
||||
# A good example is ``providedBy(IOError())``. Because of the way
|
||||
# ``classImplements`` works, it winds up with ``__bases__`` ==
|
||||
# ``[IEnvironmentError, IIOError, IOSError, <implementedBy Exception>]``
|
||||
# (on Python 3). But ``IEnvironmentError`` is a base of both ``IIOError``
|
||||
# and ``IOSError``. Previously, we would get a resolution order of
|
||||
# ``[IIOError, IOSError, IEnvironmentError, IStandardError, IException, Interface]``
|
||||
# but the standard Python algorithm would forbid creating that order entirely.
|
||||
|
||||
# Unlike Python's MRO, we attempt to resolve the issue. A few
|
||||
# heuristics have been tried. One was:
|
||||
#
|
||||
# Strip off the first (highest priority) base of each direct
|
||||
# base one at a time and seeing if we can come to an agreement
|
||||
# with the other bases. (We're trying for a partial ordering
|
||||
# here.) This often resolves cases (such as the IOSError case
|
||||
# above), and frequently produces the same ordering as the
|
||||
# legacy MRO did. If we looked at all the highest priority
|
||||
# bases and couldn't find any partial ordering, then we strip
|
||||
# them *all* out and begin the C3 step again. We take care not
|
||||
# to promote a common root over all others.
|
||||
#
|
||||
# If we only did the first part, stripped off the first
|
||||
# element of the first item, we could resolve simple cases.
|
||||
# But it tended to fail badly. If we did the whole thing, it
|
||||
# could be extremely painful from a performance perspective
|
||||
# for deep/wide things like Zope's OFS.SimpleItem.Item. Plus,
|
||||
# anytime you get ExtensionClass.Base into the mix, you're
|
||||
# likely to wind up in trouble, because it messes with the MRO
|
||||
# of classes. Sigh.
|
||||
#
|
||||
# So now, we fall back to the old linearization (fast to compute).
|
||||
self._warn_iro()
|
||||
self.direct_inconsistency = InconsistentResolutionOrderError(self, base_tree_remaining)
|
||||
raise self._UseLegacyRO
|
||||
|
||||
def _merge(self):
|
||||
# Returns a merged *list*.
|
||||
result = self.__mro = []
|
||||
base_tree_remaining = self.base_tree
|
||||
base = None
|
||||
while 1:
|
||||
# Take last picked base out of the base tree wherever it is.
|
||||
# This differs slightly from the standard Python MRO and is needed
|
||||
# because we have no other step that prevents duplicates
|
||||
# from coming in (e.g., in the inconsistent fallback path)
|
||||
base_tree_remaining = self._nonempty_bases_ignoring(base_tree_remaining, base)
|
||||
|
||||
if not base_tree_remaining:
|
||||
return result
|
||||
try:
|
||||
base = self._choose_next_base(base_tree_remaining)
|
||||
except self._UseLegacyRO:
|
||||
self.__mro = self.legacy_ro
|
||||
return self.legacy_ro
|
||||
|
||||
result.append(base)
|
||||
|
||||
def mro(self):
|
||||
if self.__mro is None:
|
||||
self.__mro = tuple(self._merge())
|
||||
return list(self.__mro)
|
||||
|
||||
|
||||
class _StrictC3(C3):
|
||||
__slots__ = ()
|
||||
def _guess_next_base(self, base_tree_remaining):
|
||||
raise InconsistentResolutionOrderError(self, base_tree_remaining)
|
||||
|
||||
|
||||
class _TrackingC3(C3):
|
||||
__slots__ = ()
|
||||
def _guess_next_base(self, base_tree_remaining):
|
||||
import traceback
|
||||
bad_iros = C3.BAD_IROS
|
||||
if self.leaf not in bad_iros:
|
||||
if bad_iros == ():
|
||||
import weakref
|
||||
# This is a race condition, but it doesn't matter much.
|
||||
bad_iros = C3.BAD_IROS = weakref.WeakKeyDictionary()
|
||||
bad_iros[self.leaf] = t = (
|
||||
InconsistentResolutionOrderError(self, base_tree_remaining),
|
||||
traceback.format_stack()
|
||||
)
|
||||
_logger().warning("Tracking inconsistent IRO: %s", t[0])
|
||||
return C3._guess_next_base(self, base_tree_remaining)
|
||||
|
||||
|
||||
class _ROComparison:
|
||||
# Exists to compute and print a pretty string comparison
|
||||
# for differing ROs.
|
||||
# Since we're used in a logging context, and may actually never be printed,
|
||||
# this is a class so we can defer computing the diff until asked.
|
||||
|
||||
# Components we use to build up the comparison report
|
||||
class Item:
|
||||
prefix = ' '
|
||||
def __init__(self, item):
|
||||
self.item = item
|
||||
def __str__(self):
|
||||
return "{}{}".format(
|
||||
self.prefix,
|
||||
self.item,
|
||||
)
|
||||
|
||||
class Deleted(Item):
|
||||
prefix = '- '
|
||||
|
||||
class Inserted(Item):
|
||||
prefix = '+ '
|
||||
|
||||
Empty = str
|
||||
|
||||
class ReplacedBy: # pragma: no cover
|
||||
prefix = '- '
|
||||
suffix = ''
|
||||
def __init__(self, chunk, total_count):
|
||||
self.chunk = chunk
|
||||
self.total_count = total_count
|
||||
|
||||
def __iter__(self):
|
||||
lines = [
|
||||
self.prefix + str(item) + self.suffix
|
||||
for item in self.chunk
|
||||
]
|
||||
while len(lines) < self.total_count:
|
||||
lines.append('')
|
||||
|
||||
return iter(lines)
|
||||
|
||||
class Replacing(ReplacedBy):
|
||||
prefix = "+ "
|
||||
suffix = ''
|
||||
|
||||
|
||||
_c3_report = None
|
||||
_legacy_report = None
|
||||
|
||||
def __init__(self, c3, c3_ro, legacy_ro):
|
||||
self.c3 = c3
|
||||
self.c3_ro = c3_ro
|
||||
self.legacy_ro = legacy_ro
|
||||
|
||||
def __move(self, from_, to_, chunk, operation):
|
||||
for x in chunk:
|
||||
to_.append(operation(x))
|
||||
from_.append(self.Empty())
|
||||
|
||||
def _generate_report(self):
|
||||
if self._c3_report is None:
|
||||
import difflib
|
||||
# The opcodes we get describe how to turn 'a' into 'b'. So
|
||||
# the old one (legacy) needs to be first ('a')
|
||||
matcher = difflib.SequenceMatcher(None, self.legacy_ro, self.c3_ro)
|
||||
# The reports are equal length sequences. We're going for a
|
||||
# side-by-side diff.
|
||||
self._c3_report = c3_report = []
|
||||
self._legacy_report = legacy_report = []
|
||||
for opcode, leg1, leg2, c31, c32 in matcher.get_opcodes():
|
||||
c3_chunk = self.c3_ro[c31:c32]
|
||||
legacy_chunk = self.legacy_ro[leg1:leg2]
|
||||
|
||||
if opcode == 'equal':
|
||||
# Guaranteed same length
|
||||
c3_report.extend(self.Item(x) for x in c3_chunk)
|
||||
legacy_report.extend(self.Item(x) for x in legacy_chunk)
|
||||
if opcode == 'delete':
|
||||
# Guaranteed same length
|
||||
assert not c3_chunk
|
||||
self.__move(c3_report, legacy_report, legacy_chunk, self.Deleted)
|
||||
if opcode == 'insert':
|
||||
# Guaranteed same length
|
||||
assert not legacy_chunk
|
||||
self.__move(legacy_report, c3_report, c3_chunk, self.Inserted)
|
||||
if opcode == 'replace': # pragma: no cover (How do you make it output this?)
|
||||
# Either side could be longer.
|
||||
chunk_size = max(len(c3_chunk), len(legacy_chunk))
|
||||
c3_report.extend(self.Replacing(c3_chunk, chunk_size))
|
||||
legacy_report.extend(self.ReplacedBy(legacy_chunk, chunk_size))
|
||||
|
||||
return self._c3_report, self._legacy_report
|
||||
|
||||
@property
|
||||
def _inconsistent_label(self):
|
||||
inconsistent = []
|
||||
if self.c3.direct_inconsistency:
|
||||
inconsistent.append('direct')
|
||||
if self.c3.bases_had_inconsistency:
|
||||
inconsistent.append('bases')
|
||||
return '+'.join(inconsistent) if inconsistent else 'no'
|
||||
|
||||
def __str__(self):
|
||||
c3_report, legacy_report = self._generate_report()
|
||||
assert len(c3_report) == len(legacy_report)
|
||||
|
||||
left_lines = [str(x) for x in legacy_report]
|
||||
right_lines = [str(x) for x in c3_report]
|
||||
|
||||
# We have the same number of lines in the report; this is not
|
||||
# necessarily the same as the number of items in either RO.
|
||||
assert len(left_lines) == len(right_lines)
|
||||
|
||||
padding = ' ' * 2
|
||||
max_left = max(len(x) for x in left_lines)
|
||||
max_right = max(len(x) for x in right_lines)
|
||||
|
||||
left_title = 'Legacy RO (len={})'.format(len(self.legacy_ro))
|
||||
|
||||
right_title = 'C3 RO (len={}; inconsistent={})'.format(
|
||||
len(self.c3_ro),
|
||||
self._inconsistent_label,
|
||||
)
|
||||
lines = [
|
||||
(padding + left_title.ljust(max_left) + padding + right_title.ljust(max_right)),
|
||||
padding + '=' * (max_left + len(padding) + max_right)
|
||||
]
|
||||
lines += [
|
||||
padding + left.ljust(max_left) + padding + right
|
||||
for left, right in zip(left_lines, right_lines)
|
||||
]
|
||||
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
# Set to `Interface` once it is defined. This is used to
|
||||
# avoid logging false positives about changed ROs.
|
||||
_ROOT = None
|
||||
|
||||
def ro(C, strict=None, base_mros=None, log_changed_ro=None, use_legacy_ro=None):
|
||||
"""
|
||||
ro(C) -> list
|
||||
|
||||
Compute the precedence list (mro) according to C3.
|
||||
|
||||
:return: A fresh `list` object.
|
||||
|
||||
.. versionchanged:: 5.0.0
|
||||
Add the *strict*, *log_changed_ro* and *use_legacy_ro*
|
||||
keyword arguments. These are provisional and likely to be
|
||||
removed in the future. They are most useful for testing.
|
||||
"""
|
||||
# The ``base_mros`` argument is for internal optimization and
|
||||
# not documented.
|
||||
resolver = C3.resolver(C, strict, base_mros)
|
||||
mro = resolver.mro()
|
||||
|
||||
log_changed = log_changed_ro if log_changed_ro is not None else resolver.LOG_CHANGED_IRO
|
||||
use_legacy = use_legacy_ro if use_legacy_ro is not None else resolver.USE_LEGACY_IRO
|
||||
|
||||
if log_changed or use_legacy:
|
||||
legacy_ro = resolver.legacy_ro
|
||||
assert isinstance(legacy_ro, list)
|
||||
assert isinstance(mro, list)
|
||||
changed = legacy_ro != mro
|
||||
if changed:
|
||||
# Did only Interface move? The fix for issue #8 made that
|
||||
# somewhat common. It's almost certainly not a problem, though,
|
||||
# so allow ignoring it.
|
||||
legacy_without_root = [x for x in legacy_ro if x is not _ROOT]
|
||||
mro_without_root = [x for x in mro if x is not _ROOT]
|
||||
changed = legacy_without_root != mro_without_root
|
||||
|
||||
if changed:
|
||||
comparison = _ROComparison(resolver, mro, legacy_ro)
|
||||
_logger().warning(
|
||||
"Object %r has different legacy and C3 MROs:\n%s",
|
||||
C, comparison
|
||||
)
|
||||
if resolver.had_inconsistency and legacy_ro == mro:
|
||||
comparison = _ROComparison(resolver, mro, legacy_ro)
|
||||
_logger().warning(
|
||||
"Object %r had inconsistent IRO and used the legacy RO:\n%s"
|
||||
"\nInconsistency entered at:\n%s",
|
||||
C, comparison, resolver.direct_inconsistency
|
||||
)
|
||||
if use_legacy:
|
||||
return legacy_ro
|
||||
|
||||
return mro
|
||||
|
||||
|
||||
def is_consistent(C):
|
||||
"""
|
||||
Check if the resolution order for *C*, as computed by :func:`ro`, is consistent
|
||||
according to C3.
|
||||
"""
|
||||
return not C3.resolver(C, False, None).had_inconsistency
|
||||
@@ -0,0 +1,115 @@
|
||||
from zope.interface._compat import _should_attempt_c_optimizations
|
||||
|
||||
|
||||
class OptimizationTestMixin:
|
||||
"""
|
||||
Helper for testing that C optimizations are used
|
||||
when appropriate.
|
||||
"""
|
||||
|
||||
def _getTargetClass(self):
|
||||
"""
|
||||
Define this to return the implementation in use,
|
||||
without the 'Py' or 'Fallback' suffix.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def _getFallbackClass(self):
|
||||
"""
|
||||
Define this to return the fallback Python implementation.
|
||||
"""
|
||||
# Is there an algorithmic way to do this? The C
|
||||
# objects all come from the same module so I don't see how we can
|
||||
# get the Python object from that.
|
||||
raise NotImplementedError
|
||||
|
||||
def test_optimizations(self):
|
||||
used = self._getTargetClass()
|
||||
fallback = self._getFallbackClass()
|
||||
|
||||
if _should_attempt_c_optimizations():
|
||||
self.assertIsNot(used, fallback)
|
||||
else:
|
||||
self.assertIs(used, fallback)
|
||||
|
||||
|
||||
class MissingSomeAttrs:
|
||||
"""
|
||||
Helper for tests that raises a specific exception
|
||||
for attributes that are missing. This is usually not
|
||||
an AttributeError, and this object is used to test that
|
||||
those errors are not improperly caught and treated like
|
||||
an AttributeError.
|
||||
"""
|
||||
|
||||
def __init__(self, exc_kind, **other_attrs):
|
||||
self.__exc_kind = exc_kind
|
||||
d = object.__getattribute__(self, '__dict__')
|
||||
d.update(other_attrs)
|
||||
|
||||
def __getattribute__(self, name):
|
||||
# Note that we ignore objects found in the class dictionary.
|
||||
d = object.__getattribute__(self, '__dict__')
|
||||
try:
|
||||
return d[name]
|
||||
except KeyError:
|
||||
raise d['_MissingSomeAttrs__exc_kind'](name)
|
||||
|
||||
EXCEPTION_CLASSES = (
|
||||
TypeError,
|
||||
RuntimeError,
|
||||
BaseException,
|
||||
ValueError,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def test_raises(cls, unittest, test_func, expected_missing, **other_attrs):
|
||||
"""
|
||||
Loop through various exceptions, calling *test_func* inside a ``assertRaises`` block.
|
||||
|
||||
:param test_func: A callable of one argument, the instance of this
|
||||
class.
|
||||
:param str expected_missing: The attribute that should fail with the exception.
|
||||
This is used to ensure that we're testing the path we think we are.
|
||||
:param other_attrs: Attributes that should be provided on the test object.
|
||||
Must not contain *expected_missing*.
|
||||
"""
|
||||
assert isinstance(expected_missing, str)
|
||||
assert expected_missing not in other_attrs
|
||||
for exc in cls.EXCEPTION_CLASSES:
|
||||
ob = cls(exc, **other_attrs)
|
||||
with unittest.assertRaises(exc) as ex:
|
||||
test_func(ob)
|
||||
|
||||
unittest.assertEqual(ex.exception.args[0], expected_missing)
|
||||
|
||||
# Now test that the AttributeError for that expected_missing is *not* raised.
|
||||
ob = cls(AttributeError, **other_attrs)
|
||||
try:
|
||||
test_func(ob)
|
||||
except AttributeError as e:
|
||||
unittest.assertNotIn(expected_missing, str(e))
|
||||
except Exception: # pylint:disable=broad-except
|
||||
pass
|
||||
|
||||
# Be sure cleanup functionality is available; classes that use the adapter hook
|
||||
# need to be sure to subclass ``CleanUp``.
|
||||
#
|
||||
# If zope.component is installed and imported when we run our tests
|
||||
# (import chain:
|
||||
# zope.testrunner->zope.security->zope.location->zope.component.api)
|
||||
# it adds an adapter hook that uses its global site manager. That can cause
|
||||
# leakage from one test to another unless its cleanup hooks are run. The symptoms can
|
||||
# be odd, especially if one test used C objects and the next used the Python
|
||||
# implementation. (For example, you can get strange TypeErrors or find inexplicable
|
||||
# comparisons being done.)
|
||||
try:
|
||||
from zope.testing import cleanup
|
||||
except ImportError:
|
||||
class CleanUp:
|
||||
def cleanUp(self):
|
||||
pass
|
||||
|
||||
setUp = tearDown = cleanUp
|
||||
else:
|
||||
CleanUp = cleanup.CleanUp
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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 getFrameInfo
|
||||
|
||||
my_globals = globals()
|
||||
|
||||
ClassicClass = None
|
||||
|
||||
class NewStyleClass:
|
||||
__metaclass__ = type
|
||||
classLevelFrameInfo = getFrameInfo(sys._getframe())
|
||||
|
||||
moduleLevelFrameInfo = getFrameInfo(sys._getframe())
|
||||
@@ -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()
|
||||
@@ -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.
|
||||
"""
|
||||
21
venv/lib/python3.11/site-packages/zope/interface/tests/m1.py
Normal file
21
venv/lib/python3.11/site-packages/zope/interface/tests/m1.py
Normal file
@@ -0,0 +1,21 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2004 Zope Foundation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##############################################################################
|
||||
"""Test module that declares an interface
|
||||
"""
|
||||
from zope.interface import Interface, moduleProvides
|
||||
|
||||
class I1(Interface): pass
|
||||
class I2(Interface): pass
|
||||
|
||||
moduleProvides(I1, I2)
|
||||
124
venv/lib/python3.11/site-packages/zope/interface/tests/odd.py
Normal file
124
venv/lib/python3.11/site-packages/zope/interface/tests/odd.py
Normal file
@@ -0,0 +1,124 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
>>> 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:
|
||||
"""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 {} at {}>".format(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:
|
||||
|
||||
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 {} instance at {}>".format(
|
||||
self.__class__.__name__, hex(id(self)))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,191 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
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)
|
||||
|
||||
def test_w_class(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 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)
|
||||
|
||||
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)
|
||||
|
||||
def test_meta_of_class(self):
|
||||
class Metameta(type):
|
||||
pass
|
||||
class Meta(type, metaclass=Metameta):
|
||||
pass
|
||||
|
||||
self.assertEqual(self._callFUT((Meta, type)), Metameta)
|
||||
|
||||
def test_multiple_in_hierarchy_py3k(self):
|
||||
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
|
||||
|
||||
self.assertEqual(self._callFUT((A, B)), Meta_B)
|
||||
|
||||
|
||||
def test_multiple_not_in_hierarchy_py3k(self):
|
||||
class Meta_A(type):
|
||||
pass
|
||||
|
||||
class Meta_B(type):
|
||||
pass
|
||||
|
||||
class A(type, metaclass=Meta_A):
|
||||
pass
|
||||
|
||||
class B(type, metaclass=Meta_B):
|
||||
pass
|
||||
|
||||
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([]), [])
|
||||
|
||||
def test_w_newstyle_meta(self):
|
||||
self.assertEqual(self._callFUT([type]), [type])
|
||||
|
||||
def test_w_newstyle_class(self):
|
||||
class C:
|
||||
pass
|
||||
self.assertEqual(self._callFUT([C]), [C])
|
||||
|
||||
def test_simple_hierarchy_skips_implied(self):
|
||||
class A:
|
||||
pass
|
||||
class B(A):
|
||||
pass
|
||||
class C(B):
|
||||
pass
|
||||
class D:
|
||||
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:
|
||||
pass
|
||||
class B:
|
||||
pass
|
||||
self.assertEqual(self._callFUT([A, B, A]), [B, A])
|
||||
@@ -0,0 +1,29 @@
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2022 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 struct
|
||||
import unittest
|
||||
|
||||
import zope.interface # noqa: try to load a C module for side effects
|
||||
|
||||
|
||||
class TestFloatingPoint(unittest.TestCase):
|
||||
|
||||
def test_no_fast_math_optimization(self):
|
||||
# Building with -Ofast enables -ffast-math, which sets certain FPU
|
||||
# flags that can cause breakage elsewhere. A library such as BTrees
|
||||
# has no business changing global FPU flags for the entire process.
|
||||
zero_bits = struct.unpack("!Q", struct.pack("!d", 0.0))[0]
|
||||
next_up = zero_bits + 1
|
||||
smallest_subnormal = struct.unpack("!d", struct.pack("!Q", next_up))[0]
|
||||
self.assertNotEqual(smallest_subnormal, 0.0)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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():
|
||||
"""docstring"""
|
||||
def method2():
|
||||
"""docstring"""
|
||||
|
||||
class IDerived(IBase):
|
||||
"IDerived doc"
|
||||
attr1 = Attribute('attr1')
|
||||
attr2 = Attribute('attr2', 'attr2 doc')
|
||||
|
||||
def method3():
|
||||
"method3 doc"
|
||||
def method4():
|
||||
pass # pragma: no cover
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
|
||||
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 # pragma: no cover
|
||||
def method2():
|
||||
pass # pragma: no cover
|
||||
|
||||
class IDerived(IBase):
|
||||
"IDerived doc"
|
||||
attr1 = Attribute('attr1')
|
||||
attr2 = Attribute('attr2', 'attr2 doc')
|
||||
|
||||
def method3():
|
||||
"method3 doc"
|
||||
def method4():
|
||||
pass # pragma: no cover
|
||||
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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1,184 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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, *args):
|
||||
iface = _makeIface()
|
||||
return self._getTargetClass()(iface, *args)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"An object has failed to implement interface "
|
||||
"zope.interface.tests.test_exceptions.IDummy: "
|
||||
"Does not declaratively implement the interface."
|
||||
)
|
||||
|
||||
def test___str__w_candidate(self):
|
||||
dni = self._makeOne('candidate')
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"The object 'candidate' has failed to implement interface "
|
||||
"zope.interface.tests.test_exceptions.IDummy: "
|
||||
"Does not declaratively implement the interface."
|
||||
)
|
||||
|
||||
|
||||
class BrokenImplementationTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import BrokenImplementation
|
||||
return BrokenImplementation
|
||||
|
||||
def _makeOne(self, *args):
|
||||
iface = _makeIface()
|
||||
return self._getTargetClass()(iface, 'missing', *args)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
'An object has failed to implement interface '
|
||||
'zope.interface.tests.test_exceptions.IDummy: '
|
||||
"The 'missing' attribute was not provided.")
|
||||
|
||||
def test___str__w_candidate(self):
|
||||
dni = self._makeOne('candidate')
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
'The object \'candidate\' has failed to implement interface '
|
||||
'zope.interface.tests.test_exceptions.IDummy: '
|
||||
"The 'missing' attribute was not provided.")
|
||||
|
||||
|
||||
def broken_function():
|
||||
"""
|
||||
This is a global function with a simple argument list.
|
||||
|
||||
It exists to be able to report the same information when
|
||||
formatting signatures.
|
||||
"""
|
||||
|
||||
|
||||
class BrokenMethodImplementationTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
return BrokenMethodImplementation
|
||||
|
||||
message = 'I said so'
|
||||
|
||||
def _makeOne(self, *args):
|
||||
return self._getTargetClass()('aMethod', self.message, *args)
|
||||
|
||||
def test___str__(self):
|
||||
dni = self._makeOne()
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"An object has failed to implement interface <Unknown>: "
|
||||
"The contract of 'aMethod' is violated because I said so."
|
||||
)
|
||||
|
||||
def test___str__w_candidate_no_implementation(self):
|
||||
dni = self._makeOne('some_function', '<IFoo>', 'candidate')
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"The object 'candidate' has failed to implement interface <IFoo>: "
|
||||
"The contract of 'aMethod' is violated because I said so."
|
||||
)
|
||||
|
||||
def test___str__w_candidate_w_implementation(self):
|
||||
self.message = 'implementation is wonky'
|
||||
dni = self._makeOne(broken_function, '<IFoo>', 'candidate')
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"The object 'candidate' has failed to implement interface <IFoo>: "
|
||||
"The contract of 'aMethod' is violated because "
|
||||
"'broken_function()' is wonky."
|
||||
)
|
||||
|
||||
def test___str__w_candidate_w_implementation_not_callable(self):
|
||||
self.message = 'implementation is not callable'
|
||||
dni = self._makeOne(42, '<IFoo>', 'candidate')
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"The object 'candidate' has failed to implement interface <IFoo>: "
|
||||
"The contract of 'aMethod' is violated because "
|
||||
"'42' is not callable."
|
||||
)
|
||||
|
||||
def test___repr__w_candidate(self):
|
||||
dni = self._makeOne(None, 'candidate')
|
||||
self.assertEqual(
|
||||
repr(dni),
|
||||
"BrokenMethodImplementation('aMethod', 'I said so', None, 'candidate')"
|
||||
)
|
||||
|
||||
|
||||
class MultipleInvalidTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.exceptions import MultipleInvalid
|
||||
return MultipleInvalid
|
||||
|
||||
def _makeOne(self, excs):
|
||||
iface = _makeIface()
|
||||
return self._getTargetClass()(iface, 'target', excs)
|
||||
|
||||
def test__str__(self):
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
excs = [
|
||||
BrokenMethodImplementation('aMethod', 'I said so'),
|
||||
Exception("Regular exception")
|
||||
]
|
||||
dni = self._makeOne(excs)
|
||||
self.assertEqual(
|
||||
str(dni),
|
||||
"The object 'target' has failed to implement interface "
|
||||
"zope.interface.tests.test_exceptions.IDummy:\n"
|
||||
" The contract of 'aMethod' is violated because I said so\n"
|
||||
" Regular exception"
|
||||
)
|
||||
|
||||
def test__repr__(self):
|
||||
from zope.interface.exceptions import BrokenMethodImplementation
|
||||
excs = [
|
||||
BrokenMethodImplementation('aMethod', 'I said so'),
|
||||
# Use multiple arguments to normalize repr; versions of Python
|
||||
# prior to 3.7 add a trailing comma if there's just one.
|
||||
Exception("Regular", "exception")
|
||||
]
|
||||
dni = self._makeOne(excs)
|
||||
self.assertEqual(
|
||||
repr(dni),
|
||||
"MultipleInvalid(<InterfaceClass zope.interface.tests.test_exceptions.IDummy>,"
|
||||
" 'target',"
|
||||
" (BrokenMethodImplementation('aMethod', 'I said so'),"
|
||||
" Exception('Regular', 'exception')))"
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
import unittest
|
||||
|
||||
|
||||
class _ConformsToIObjectEvent:
|
||||
|
||||
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())
|
||||
|
||||
|
||||
class InterfaceClassTests(unittest.TestCase):
|
||||
|
||||
def _getTargetClass(self):
|
||||
from zope.interface.interface import InterfaceClass
|
||||
return InterfaceClass
|
||||
|
||||
def _getTargetInterface(self):
|
||||
from zope.interface.interfaces import IInterface
|
||||
return IInterface
|
||||
|
||||
def _makeOne(self):
|
||||
from zope.interface.interface import Interface
|
||||
return Interface
|
||||
|
||||
def test_class_conforms(self):
|
||||
from zope.interface.verify import verifyClass
|
||||
verifyClass(self._getTargetInterface(), self._getTargetClass())
|
||||
|
||||
def test_instance_conforms(self):
|
||||
from zope.interface.verify import verifyObject
|
||||
verifyObject(self._getTargetInterface(), self._makeOne())
|
||||
|
||||
def test_instance_consistent__iro__(self):
|
||||
from zope.interface import ro
|
||||
self.assertTrue(ro.is_consistent(self._getTargetInterface()))
|
||||
|
||||
def test_class_consistent__iro__(self):
|
||||
from zope.interface import ro
|
||||
from zope.interface import implementedBy
|
||||
|
||||
self.assertTrue(ro.is_consistent(implementedBy(self._getTargetClass())))
|
||||
@@ -0,0 +1,255 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
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:
|
||||
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))
|
||||
|
||||
# see above
|
||||
#def TODO_test_classProvides_fails_for_odd_class(self):
|
||||
# try:
|
||||
# class A(Odd):
|
||||
# classProvides(I1)
|
||||
# except TypeError:
|
||||
# pass # Success
|
||||
# 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:
|
||||
a = 1
|
||||
|
||||
A = odd.MetaClass('A', A.__bases__, A.__dict__)
|
||||
|
||||
class B:
|
||||
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
|
||||
|
||||
self.assertIs(C.__class__.__class__, C.__class__)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,426 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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
|
||||
|
||||
# pylint:disable=blacklisted-name,protected-access,attribute-defined-outside-init
|
||||
|
||||
class Test__mergeOrderings(unittest.TestCase):
|
||||
|
||||
def _callFUT(self, orderings):
|
||||
from zope.interface.ro import _legacy_mergeOrderings
|
||||
return _legacy_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_duplicates(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 _legacy_flatten
|
||||
return _legacy_flatten(ob)
|
||||
|
||||
def test_w_empty_bases(self):
|
||||
class Foo:
|
||||
pass
|
||||
foo = Foo()
|
||||
foo.__bases__ = ()
|
||||
self.assertEqual(self._callFUT(foo), [foo])
|
||||
|
||||
def test_w_single_base(self):
|
||||
class Foo:
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Foo), [Foo, object])
|
||||
|
||||
def test_w_bases(self):
|
||||
class Foo:
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])
|
||||
|
||||
def test_w_diamond(self):
|
||||
class Foo:
|
||||
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):
|
||||
maxDiff = None
|
||||
def _callFUT(self, ob, **kwargs):
|
||||
from zope.interface.ro import _legacy_ro
|
||||
return _legacy_ro(ob, **kwargs)
|
||||
|
||||
def test_w_empty_bases(self):
|
||||
class Foo:
|
||||
pass
|
||||
foo = Foo()
|
||||
foo.__bases__ = ()
|
||||
self.assertEqual(self._callFUT(foo), [foo])
|
||||
|
||||
def test_w_single_base(self):
|
||||
class Foo:
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Foo), [Foo, object])
|
||||
|
||||
def test_w_bases(self):
|
||||
class Foo:
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Bar), [Bar, Foo, object])
|
||||
|
||||
def test_w_diamond(self):
|
||||
class Foo:
|
||||
pass
|
||||
class Bar(Foo):
|
||||
pass
|
||||
class Baz(Foo):
|
||||
pass
|
||||
class Qux(Bar, Baz):
|
||||
pass
|
||||
self.assertEqual(self._callFUT(Qux),
|
||||
[Qux, Bar, Baz, Foo, object])
|
||||
|
||||
def _make_IOErr(self):
|
||||
# This can't be done in the standard C3 ordering.
|
||||
class Foo:
|
||||
def __init__(self, name, *bases):
|
||||
self.__name__ = name
|
||||
self.__bases__ = bases
|
||||
def __repr__(self): # pragma: no cover
|
||||
return self.__name__
|
||||
|
||||
# Mimic what classImplements(IOError, IIOError)
|
||||
# does.
|
||||
IEx = Foo('IEx')
|
||||
IStdErr = Foo('IStdErr', IEx)
|
||||
IEnvErr = Foo('IEnvErr', IStdErr)
|
||||
IIOErr = Foo('IIOErr', IEnvErr)
|
||||
IOSErr = Foo('IOSErr', IEnvErr)
|
||||
|
||||
IOErr = Foo('IOErr', IEnvErr, IIOErr, IOSErr)
|
||||
return IOErr, [IOErr, IIOErr, IOSErr, IEnvErr, IStdErr, IEx]
|
||||
|
||||
def test_non_orderable(self):
|
||||
IOErr, bases = self._make_IOErr()
|
||||
|
||||
self.assertEqual(self._callFUT(IOErr), bases)
|
||||
|
||||
def test_mixed_inheritance_and_implementation(self):
|
||||
# https://github.com/zopefoundation/zope.interface/issues/8
|
||||
# This test should fail, but doesn't, as described in that issue.
|
||||
# pylint:disable=inherit-non-class
|
||||
from zope.interface import implementer
|
||||
from zope.interface import Interface
|
||||
from zope.interface import providedBy
|
||||
from zope.interface import implementedBy
|
||||
|
||||
class IFoo(Interface):
|
||||
pass
|
||||
|
||||
@implementer(IFoo)
|
||||
class ImplementsFoo:
|
||||
pass
|
||||
|
||||
class ExtendsFoo(ImplementsFoo):
|
||||
pass
|
||||
|
||||
class ImplementsNothing:
|
||||
pass
|
||||
|
||||
class ExtendsFooImplementsNothing(ExtendsFoo, ImplementsNothing):
|
||||
pass
|
||||
|
||||
self.assertEqual(
|
||||
self._callFUT(providedBy(ExtendsFooImplementsNothing())),
|
||||
[implementedBy(ExtendsFooImplementsNothing),
|
||||
implementedBy(ExtendsFoo),
|
||||
implementedBy(ImplementsFoo),
|
||||
IFoo,
|
||||
Interface,
|
||||
implementedBy(ImplementsNothing),
|
||||
implementedBy(object)])
|
||||
|
||||
|
||||
class C3Setting:
|
||||
|
||||
def __init__(self, setting, value):
|
||||
self._setting = setting
|
||||
self._value = value
|
||||
|
||||
def __enter__(self):
|
||||
from zope.interface import ro
|
||||
setattr(ro.C3, self._setting.__name__, self._value)
|
||||
|
||||
def __exit__(self, t, v, tb):
|
||||
from zope.interface import ro
|
||||
setattr(ro.C3, self._setting.__name__, self._setting)
|
||||
|
||||
class Test_c3_ro(Test_ro):
|
||||
|
||||
def setUp(self):
|
||||
Test_ro.setUp(self)
|
||||
from zope.testing.loggingsupport import InstalledHandler
|
||||
self.log_handler = handler = InstalledHandler('zope.interface.ro')
|
||||
self.addCleanup(handler.uninstall)
|
||||
|
||||
def _callFUT(self, ob, **kwargs):
|
||||
from zope.interface.ro import ro
|
||||
return ro(ob, **kwargs)
|
||||
|
||||
def _make_complex_diamond(self, base):
|
||||
# https://github.com/zopefoundation/zope.interface/issues/21
|
||||
O = base
|
||||
class F(O):
|
||||
pass
|
||||
class E(O):
|
||||
pass
|
||||
class D(O):
|
||||
pass
|
||||
class C(D, F):
|
||||
pass
|
||||
class B(D, E):
|
||||
pass
|
||||
class A(B, C):
|
||||
pass
|
||||
|
||||
if hasattr(A, 'mro'):
|
||||
self.assertEqual(A.mro(), self._callFUT(A))
|
||||
|
||||
return A
|
||||
|
||||
def test_complex_diamond_object(self):
|
||||
self._make_complex_diamond(object)
|
||||
|
||||
def test_complex_diamond_interface(self):
|
||||
from zope.interface import Interface
|
||||
|
||||
IA = self._make_complex_diamond(Interface)
|
||||
|
||||
self.assertEqual(
|
||||
[x.__name__ for x in IA.__iro__],
|
||||
['A', 'B', 'C', 'D', 'E', 'F', 'Interface']
|
||||
)
|
||||
|
||||
def test_complex_diamond_use_legacy_argument(self):
|
||||
from zope.interface import Interface
|
||||
|
||||
A = self._make_complex_diamond(Interface)
|
||||
legacy_A_iro = self._callFUT(A, use_legacy_ro=True)
|
||||
self.assertNotEqual(A.__iro__, legacy_A_iro)
|
||||
|
||||
# And logging happened as a side-effect.
|
||||
self._check_handler_complex_diamond()
|
||||
|
||||
def test_complex_diamond_compare_legacy_argument(self):
|
||||
from zope.interface import Interface
|
||||
|
||||
A = self._make_complex_diamond(Interface)
|
||||
computed_A_iro = self._callFUT(A, log_changed_ro=True)
|
||||
# It matches, of course, but we did log a warning.
|
||||
self.assertEqual(tuple(computed_A_iro), A.__iro__)
|
||||
self._check_handler_complex_diamond()
|
||||
|
||||
def _check_handler_complex_diamond(self):
|
||||
handler = self.log_handler
|
||||
self.assertEqual(1, len(handler.records))
|
||||
record = handler.records[0]
|
||||
|
||||
self.assertEqual('\n'.join(l.rstrip() for l in record.getMessage().splitlines()), """\
|
||||
Object <InterfaceClass zope.interface.tests.test_ro.A> has different legacy and C3 MROs:
|
||||
Legacy RO (len=7) C3 RO (len=7; inconsistent=no)
|
||||
==================================================================
|
||||
zope.interface.tests.test_ro.A zope.interface.tests.test_ro.A
|
||||
zope.interface.tests.test_ro.B zope.interface.tests.test_ro.B
|
||||
- zope.interface.tests.test_ro.E
|
||||
zope.interface.tests.test_ro.C zope.interface.tests.test_ro.C
|
||||
zope.interface.tests.test_ro.D zope.interface.tests.test_ro.D
|
||||
+ zope.interface.tests.test_ro.E
|
||||
zope.interface.tests.test_ro.F zope.interface.tests.test_ro.F
|
||||
zope.interface.Interface zope.interface.Interface""")
|
||||
|
||||
def test_ExtendedPathIndex_implement_thing_implementedby_super(self):
|
||||
# See https://github.com/zopefoundation/zope.interface/pull/182#issuecomment-598754056
|
||||
from zope.interface import ro
|
||||
# pylint:disable=inherit-non-class
|
||||
class _Based:
|
||||
__bases__ = ()
|
||||
|
||||
def __init__(self, name, bases=(), attrs=None):
|
||||
self.__name__ = name
|
||||
self.__bases__ = bases
|
||||
|
||||
def __repr__(self):
|
||||
return self.__name__
|
||||
|
||||
Interface = _Based('Interface', (), {})
|
||||
|
||||
class IPluggableIndex(Interface):
|
||||
pass
|
||||
|
||||
class ILimitedResultIndex(IPluggableIndex):
|
||||
pass
|
||||
|
||||
class IQueryIndex(IPluggableIndex):
|
||||
pass
|
||||
|
||||
class IPathIndex(Interface):
|
||||
pass
|
||||
|
||||
# A parent class who implements two distinct interfaces whose
|
||||
# only common ancestor is Interface. An easy case.
|
||||
# @implementer(IPathIndex, IQueryIndex)
|
||||
# class PathIndex(object):
|
||||
# pass
|
||||
obj = _Based('object')
|
||||
PathIndex = _Based('PathIndex', (IPathIndex, IQueryIndex, obj))
|
||||
|
||||
# Child class that tries to put an interface the parent declares
|
||||
# later ahead of the parent.
|
||||
# @implementer(ILimitedResultIndex, IQueryIndex)
|
||||
# class ExtendedPathIndex(PathIndex):
|
||||
# pass
|
||||
ExtendedPathIndex = _Based('ExtendedPathIndex',
|
||||
(ILimitedResultIndex, IQueryIndex, PathIndex))
|
||||
|
||||
# We were able to resolve it, and in exactly the same way as
|
||||
# the legacy RO did, even though it is inconsistent.
|
||||
result = self._callFUT(ExtendedPathIndex, log_changed_ro=True, strict=False)
|
||||
self.assertEqual(result, [
|
||||
ExtendedPathIndex,
|
||||
ILimitedResultIndex,
|
||||
PathIndex,
|
||||
IPathIndex,
|
||||
IQueryIndex,
|
||||
IPluggableIndex,
|
||||
Interface,
|
||||
obj])
|
||||
|
||||
record, = self.log_handler.records
|
||||
self.assertIn('used the legacy', record.getMessage())
|
||||
|
||||
with self.assertRaises(ro.InconsistentResolutionOrderError):
|
||||
self._callFUT(ExtendedPathIndex, strict=True)
|
||||
|
||||
def test_OSError_IOError(self):
|
||||
from zope.interface.common import interfaces
|
||||
from zope.interface import providedBy
|
||||
|
||||
self.assertEqual(
|
||||
list(providedBy(OSError()).flattened()),
|
||||
[
|
||||
interfaces.IOSError,
|
||||
interfaces.IIOError,
|
||||
interfaces.IEnvironmentError,
|
||||
interfaces.IStandardError,
|
||||
interfaces.IException,
|
||||
interfaces.Interface,
|
||||
])
|
||||
|
||||
def test_non_orderable(self):
|
||||
import warnings
|
||||
from zope.interface import ro
|
||||
try:
|
||||
# If we've already warned, we must reset that state.
|
||||
del ro.__warningregistry__
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('error')
|
||||
with C3Setting(ro.C3.WARN_BAD_IRO, True), C3Setting(ro.C3.STRICT_IRO, False):
|
||||
with self.assertRaises(ro.InconsistentResolutionOrderWarning):
|
||||
super().test_non_orderable()
|
||||
|
||||
IOErr, _ = self._make_IOErr()
|
||||
with self.assertRaises(ro.InconsistentResolutionOrderError):
|
||||
self._callFUT(IOErr, strict=True)
|
||||
|
||||
with C3Setting(ro.C3.TRACK_BAD_IRO, True), C3Setting(ro.C3.STRICT_IRO, False):
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
self._callFUT(IOErr)
|
||||
self.assertIn(IOErr, ro.C3.BAD_IROS)
|
||||
|
||||
iro = self._callFUT(IOErr, strict=False)
|
||||
legacy_iro = self._callFUT(IOErr, use_legacy_ro=True, strict=False)
|
||||
self.assertEqual(iro, legacy_iro)
|
||||
|
||||
|
||||
class TestC3(unittest.TestCase):
|
||||
def _makeOne(self, C, strict=False, base_mros=None):
|
||||
from zope.interface.ro import C3
|
||||
return C3.resolver(C, strict, base_mros)
|
||||
|
||||
def test_base_mros_given(self):
|
||||
c3 = self._makeOne(type(self), base_mros={unittest.TestCase: unittest.TestCase.__mro__})
|
||||
memo = c3.memo
|
||||
self.assertIn(unittest.TestCase, memo)
|
||||
# We used the StaticMRO class
|
||||
self.assertIsNone(memo[unittest.TestCase].had_inconsistency)
|
||||
|
||||
def test_one_base_optimization(self):
|
||||
c3 = self._makeOne(type(self))
|
||||
# Even though we didn't call .mro() yet, the MRO has been
|
||||
# computed.
|
||||
self.assertIsNotNone(c3._C3__mro) # pylint:disable=no-member
|
||||
c3._merge = None
|
||||
self.assertEqual(c3.mro(), list(type(self).__mro__))
|
||||
|
||||
|
||||
class Test_ROComparison(unittest.TestCase):
|
||||
|
||||
class MockC3:
|
||||
direct_inconsistency = False
|
||||
bases_had_inconsistency = False
|
||||
|
||||
def _makeOne(self, c3=None, c3_ro=(), legacy_ro=()):
|
||||
from zope.interface.ro import _ROComparison
|
||||
return _ROComparison(c3 or self.MockC3(), c3_ro, legacy_ro)
|
||||
|
||||
def test_inconsistent_label(self):
|
||||
comp = self._makeOne()
|
||||
self.assertEqual('no', comp._inconsistent_label)
|
||||
|
||||
comp.c3.direct_inconsistency = True
|
||||
self.assertEqual("direct", comp._inconsistent_label)
|
||||
|
||||
comp.c3.bases_had_inconsistency = True
|
||||
self.assertEqual("direct+bases", comp._inconsistent_label)
|
||||
|
||||
comp.c3.direct_inconsistency = False
|
||||
self.assertEqual('bases', comp._inconsistent_label)
|
||||
@@ -0,0 +1,64 @@
|
||||
##############################################################################
|
||||
#
|
||||
# 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])
|
||||
|
||||
def test_I1_I2(self):
|
||||
self.assertLess(I1.__name__, I2.__name__)
|
||||
self.assertEqual(I1.__module__, I2.__module__)
|
||||
self.assertEqual(I1.__module__, __name__)
|
||||
self.assertLess(I1, I2)
|
||||
|
||||
def _makeI1(self):
|
||||
class I1(Interface):
|
||||
pass
|
||||
return I1
|
||||
|
||||
def test_nested(self):
|
||||
nested_I1 = self._makeI1()
|
||||
self.assertEqual(I1, nested_I1)
|
||||
self.assertEqual(nested_I1, I1)
|
||||
self.assertEqual(hash(I1), hash(nested_I1))
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user