From 90a4801441a9dc3e29a160918d3f70c68a8574c5 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Sun, 26 May 2024 01:13:04 -0400 Subject: [PATCH] chore: appease flake8 We should *really* kick pylint to the door: it's comment markers are a huge source of churn, including inducing line-too-long errors. --- setup.cfg | 7 + setup.py | 103 ++-- src/zope/interface/_compat.py | 5 +- src/zope/interface/_flatten.py | 2 +- src/zope/interface/adapter.py | 159 +++-- src/zope/interface/advice.py | 21 +- src/zope/interface/common/__init__.py | 48 +- src/zope/interface/common/builtins.py | 7 +- src/zope/interface/common/collections.py | 36 +- src/zope/interface/common/idatetime.py | 79 +-- src/zope/interface/common/interfaces.py | 72 +-- src/zope/interface/common/mapping.py | 12 +- src/zope/interface/common/sequence.py | 5 + src/zope/interface/common/tests/__init__.py | 17 +- .../interface/common/tests/basemapping.py | 23 +- .../common/tests/test_collections.py | 29 +- src/zope/interface/common/tests/test_io.py | 5 +- .../interface/common/tests/test_numbers.py | 1 + src/zope/interface/declarations.py | 269 +++++---- src/zope/interface/document.py | 40 +- src/zope/interface/exceptions.py | 21 +- src/zope/interface/interface.py | 194 +++--- src/zope/interface/interfaces.py | 86 ++- src/zope/interface/registry.py | 162 +++--- src/zope/interface/ro.py | 165 ++++-- src/zope/interface/tests/__init__.py | 28 +- src/zope/interface/tests/advisory_testing.py | 2 + src/zope/interface/tests/dummy.py | 1 + src/zope/interface/tests/m1.py | 9 +- src/zope/interface/tests/odd.py | 18 +- src/zope/interface/tests/test_adapter.py | 393 ++++++++++--- src/zope/interface/tests/test_advice.py | 24 +- src/zope/interface/tests/test_declarations.py | 368 +++++++++--- src/zope/interface/tests/test_document.py | 43 +- src/zope/interface/tests/test_exceptions.py | 9 +- src/zope/interface/tests/test_interface.py | 550 ++++++++++++------ src/zope/interface/tests/test_interfaces.py | 4 +- .../interface/tests/test_odd_declarations.py | 99 +++- src/zope/interface/tests/test_registry.py | 511 +++++++++++++--- src/zope/interface/tests/test_ro.py | 92 ++- src/zope/interface/tests/test_sorting.py | 48 +- src/zope/interface/tests/test_verify.py | 13 +- src/zope/interface/verify.py | 62 +- 43 files changed, 2650 insertions(+), 1192 deletions(-) diff --git a/setup.cfg b/setup.cfg index a68efef0..159df36d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,6 +6,13 @@ create-wheel = no [flake8] doctests = 1 +ignore = + # module level import not at top of file: we are avoiding cycles + E402, + # import not used: we are publishing APIs, at least from __init__.py + F401, + # line break after binary operator + W504 [check-manifest] ignore = diff --git a/setup.py b/setup.py index c2016ded..6f28be53 100644 --- a/setup.py +++ b/setup.py @@ -94,56 +94,55 @@ def read(*rnames): long_description = ( - read('README.rst') - + '\n' + - read('CHANGES.rst') - ) - -setup(name='zope.interface', - version='6.5.dev0', - url='https://github.com/zopefoundation/zope.interface', - license='ZPL 2.1', - description='Interfaces for Python', - author='Zope Foundation and Contributors', - author_email='zope-dev@zope.org', - long_description=long_description, - classifiers=[ - "Development Status :: 5 - Production/Stable", - "Intended Audience :: Developers", - "License :: OSI Approved :: Zope Public License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", - "Framework :: Zope :: 3", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - packages=find_packages('src'), - package_dir={'': 'src'}, - namespace_packages=["zope"], - cmdclass={ - 'build_ext': optional_build_ext, - }, - test_suite='zope.interface.tests', - include_package_data=True, - zip_safe=False, - tests_require=tests_require, - install_requires=['setuptools'], - python_requires='>=3.7', - extras_require={ - 'docs': ['Sphinx', - 'repoze.sphinx.autointerface', - 'sphinx_rtd_theme'], - 'test': tests_require, - 'testing': testing_extras, - }, - ext_modules=ext_modules, - keywords=['interface', 'components', 'plugins'], + read('README.rst') + '\n' + read('CHANGES.rst') +) + +setup( + name='zope.interface', + version='6.5.dev0', + url='https://github.com/zopefoundation/zope.interface', + license='ZPL 2.1', + description='Interfaces for Python', + author='Zope Foundation and Contributors', + author_email='zope-dev@zope.org', + long_description=long_description, + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: Zope Public License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Framework :: Zope :: 3", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + packages=find_packages('src'), + package_dir={'': 'src'}, + namespace_packages=["zope"], + cmdclass={ + 'build_ext': optional_build_ext, + }, + test_suite='zope.interface.tests', + include_package_data=True, + zip_safe=False, + tests_require=tests_require, + install_requires=['setuptools'], + python_requires='>=3.7', + extras_require={ + 'docs': ['Sphinx', + 'repoze.sphinx.autointerface', + 'sphinx_rtd_theme'], + 'test': tests_require, + 'testing': testing_extras, + }, + ext_modules=ext_modules, + keywords=['interface', 'components', 'plugins'], ) diff --git a/src/zope/interface/_compat.py b/src/zope/interface/_compat.py index 2ff8d83e..bc3f8671 100644 --- a/src/zope/interface/_compat.py +++ b/src/zope/interface/_compat.py @@ -29,6 +29,7 @@ def _normalize_name(name): return name raise TypeError("name must be a string or ASCII-only bytes") + PYPY = hasattr(sys, 'pypy_version_info') @@ -57,7 +58,7 @@ def _c_optimizations_available(): 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) + except catch: # pragma: no cover (only Jython doesn't build extensions) return False @@ -120,7 +121,7 @@ def find_impl(): return py_impl c_opt = _c_optimizations_available() - if not c_opt: # pragma: no cover (only Jython doesn't build extensions) + if not c_opt: # pragma: no cover (Jython doesn't build extensions) return py_impl __traceback_info__ = c_opt diff --git a/src/zope/interface/_flatten.py b/src/zope/interface/_flatten.py index 68b490db..a2cb86b7 100644 --- a/src/zope/interface/_flatten.py +++ b/src/zope/interface/_flatten.py @@ -24,7 +24,7 @@ def _flatten(implements, include_None=0): r = implements.flattened() except AttributeError: if implements is None: - r=() + r = () else: r = Declaration(implements).flattened() diff --git a/src/zope/interface/adapter.py b/src/zope/interface/adapter.py index b02f19d5..a35c3f90 100644 --- a/src/zope/interface/adapter.py +++ b/src/zope/interface/adapter.py @@ -59,7 +59,7 @@ # ``tuple([t fon t in range(10)])`` -> 82ns # ``tuple(t for t in range(10))`` -> 177ns # ``tuple(map(lambda t: t, range(10)))`` -> 168ns -# + class BaseAdapterRegistry: """ @@ -68,36 +68,40 @@ class BaseAdapterRegistry: Subclasses can set the following attributes to control how the data is stored; in particular, these hooks can be helpful for ZODB - persistence. They can be class attributes that are the named (or similar) type, or - they can be methods that act as a constructor for an object that behaves - like the types defined here; this object will not assume that they are type - objects, but subclasses are free to do so: + persistence. They can be class attributes that are the named + (or similar) type, or they can be methods that act as a constructor + for an object that behaves like the types defined here; this object + will not assume that they are type objects, but subclasses are free + to do so: _sequenceType = list This is the type used for our two mutable top-level "byorder" sequences. - Must support mutation operations like ``append()`` and ``del seq[index]``. - These are usually small (< 10). Although at least one of them is - accessed when performing lookups or queries on this object, the other - is untouched. In many common scenarios, both are only required when - mutating registrations and subscriptions (like what + Must support mutation operations like ``append()`` and ``del + seq[index]``. These are usually small (< 10). Although at least one of + them is accessed when performing lookups or queries on this object, the + other is untouched. In many common scenarios, both are only required + when mutating registrations and subscriptions (like what :meth:`zope.interface.interfaces.IComponents.registerUtility` does). This use pattern makes it an ideal candidate to be a :class:`~persistent.list.PersistentList`. + _leafSequenceType = tuple This is the type used for the leaf sequences of subscribers. It could be set to a ``PersistentList`` to avoid many unnecessary data - loads when subscribers aren't being used. Mutation operations are directed - through :meth:`_addValueToLeaf` and :meth:`_removeValueFromLeaf`; if you use - a mutable type, you'll need to override those. + loads when subscribers aren't being used. Mutation operations are + directed through :meth:`_addValueToLeaf` and + :meth:`_removeValueFromLeaf`; if you use a mutable type, you'll need to + override those. + _mappingType = dict - This is the mutable mapping type used for the keyed mappings. - A :class:`~persistent.mapping.PersistentMapping` - could be used to help reduce the number of data loads when the registry is large - and parts of it are rarely used. Further reductions in data loads can come from - using a :class:`~BTrees.OOBTree.OOBTree`, but care is required - to be sure that all required/provided - values are fully ordered (e.g., no required or provided values that are classes - can be used). + This is the mutable mapping type used for the keyed mappings. A + :class:`~persistent.mapping.PersistentMapping` could be used to help + reduce the number of data loads when the registry is large and parts of + it are rarely used. Further reductions in data loads can come from using + a :class:`~BTrees.OOBTree.OOBTree`, but care is required to be sure that + all required/provided values are fully ordered (e.g., no required or + provided values that are classes can be used). + _providedType = dict This is the mutable mapping type used for the ``_provided`` mapping. This is separate from the generic mapping type because the values @@ -106,9 +110,10 @@ class BaseAdapterRegistry: The same caveats regarding key types apply as for ``_mappingType``. - It is possible to also set these on an instance, but because of the need to - potentially also override :meth:`_addValueToLeaf` and :meth:`_removeValueFromLeaf`, - this may be less useful in a persistent scenario; using a subclass is recommended. + It is possible to also set these on an instance, but because of the need + to potentially also override :meth:`_addValueToLeaf` and + :meth:`_removeValueFromLeaf`, this may be less useful in a persistent + scenario; using a subclass is recommended. .. versionchanged:: 5.3.0 Add support for customizing the way internal data @@ -209,18 +214,20 @@ def _addValueToLeaf(self, existing_leaf_sequence, new_item): Add the value *new_item* to the *existing_leaf_sequence*, which may be ``None``. - Subclasses that redefine `_leafSequenceType` should override this method. + Subclasses that redefine `_leafSequenceType` should override this + method. :param existing_leaf_sequence: If *existing_leaf_sequence* is not *None*, it will be an instance - of `_leafSequenceType`. (Unless the object has been unpickled - from an old pickle and the class definition has changed, in which case - it may be an instance of a previous definition, commonly a `tuple`.) + of `_leafSequenceType`. (Unless the object has been unpickled from + an old pickle and the class definition has changed, in which case + it may be an instance of a previous definition, commonly a + `tuple`.) :return: This method returns the new value to be stored. It may mutate the - sequence in place if it was not ``None`` and the type is mutable, but - it must also return it. + sequence in place if it was not ``None`` and the type is mutable, + but it must also return it. .. versionadded:: 5.3.0 """ @@ -337,9 +344,9 @@ def _allKeys(cls, components, i, parent_k=()): def _all_entries(self, byorder): # Recurse through the mapping levels of the `byorder` sequence, - # reconstructing a flattened sequence of ``(required, provided, name, value)`` - # tuples that can be used to reconstruct the sequence with the appropriate - # registration methods. + # reconstructing a flattened sequence of ``(required, provided, name, + # value)`` tuples that can be used to reconstruct the sequence with + # the appropriate registration methods. # # Locally reference the `byorder` data; it might be replaced while # this method is running (see ``rebuild``). @@ -461,7 +468,9 @@ def allSubscriptions(self): .. versionadded:: 5.3.0 """ - for required, provided, _name, value in self._all_entries(self._subscribers): + for required, provided, _name, value in self._all_entries( + self._subscribers, + ): for v in value: yield (required, provided, v) @@ -570,7 +579,6 @@ def buffer(it): registrations = buffer(registrations) subscriptions = buffer(subscriptions) - # Replace the base data structures as well as _v_lookup. self.__init__(self.__bases__) # Re-register everything previously registered and subscribed. @@ -584,12 +592,13 @@ def buffer(it): # part of passing that notification to the change of objects.) for args in registrations: self.register(*args) + for args in subscriptions: self.subscribe(*args) - # XXX hack to fake out twisted's use of a private api. We need to get them - # to use the new registered method. - def get(self, _): # pragma: no cover + # XXX hack to fake out twisted's use of a private api. + # We need to get them to use the new registered method. + def get(self, _): # pragma: no cover class XXXTwistedFakeOut: selfImplied = {} return XXXTwistedFakeOut @@ -597,6 +606,7 @@ class XXXTwistedFakeOut: _not_in_mapping = object() + @_use_c_impl class LookupBase: @@ -693,7 +703,6 @@ def lookupAll(self, required, provided): return result - def subscriptions(self, required, provided): cache = self._scache.get(provided) if cache is None: @@ -710,33 +719,42 @@ def subscriptions(self, required, provided): @_use_c_impl -class VerifyingBase(LookupBaseFallback): +class VerifyingBase(LookupBaseFallback): # noqa F821 # Mixin for lookups against registries which "chain" upwards, and # whose lookups invalidate their own caches whenever a parent registry # bumps its own '_generation' counter. E.g., used by # zope.component.persistentregistry def changed(self, originally_changed): - LookupBaseFallback.changed(self, originally_changed) + LookupBaseFallback.changed(self, originally_changed) # noqa F821 self._verify_ro = self._registry.ro[1:] self._verify_generations = [r._generation for r in self._verify_ro] def _verify(self): - if ([r._generation for r in self._verify_ro] - != self._verify_generations): + if ( + [ + r._generation for r in self._verify_ro + ] != self._verify_generations + ): self.changed(None) def _getcache(self, provided, name): self._verify() - return LookupBaseFallback._getcache(self, provided, name) + return LookupBaseFallback._getcache( # noqa F821 + self, provided, name, + ) def lookupAll(self, required, provided): self._verify() - return LookupBaseFallback.lookupAll(self, required, provided) + return LookupBaseFallback.lookupAll( # noqa F821 + self, required, provided, + ) def subscriptions(self, required, provided): self._verify() - return LookupBaseFallback.subscriptions(self, required, provided) + return LookupBaseFallback.subscriptions( # noqa F821 + self, required, provided, + ) class AdapterLookupBase: @@ -755,7 +773,6 @@ def changed(self, ignored=None): r.unsubscribe(self) self._required.clear() - # Extendors # --------- @@ -778,7 +795,7 @@ def changed(self, ignored=None): # the interface's __iro__ has changed. This is unlikely enough that # we'll take our chances for now. - def init_extendors(self): + def init_extendors(self): # noqa E301 self._extendors = {} for p in self._registry._provided: self.add_extendor(p) @@ -788,12 +805,14 @@ def add_extendor(self, provided): for i in provided.__iro__: extendors = _extendors.get(i, ()) _extendors[i] = ( - [e for e in extendors if provided.isOrExtends(e)] - + - [provided] - + - [e for e in extendors if not provided.isOrExtends(e)] - ) + [ + e for e in extendors if provided.isOrExtends(e) + ] + [ + provided + ] + [ + e for e in extendors if not provided.isOrExtends(e) + ] + ) def remove_extendor(self, provided): _extendors = self._extendors @@ -801,7 +820,6 @@ def remove_extendor(self, provided): _extendors[i] = [e for e in _extendors.get(i, ()) if e != provided] - def _subscribe(self, *required): _refs = self._required for r in required: @@ -838,7 +856,9 @@ def queryMultiAdapter(self, objects, provided, name='', default=None): if factory is None: return default - result = factory(*[o.__self__ if isinstance(o, super) else o for o in objects]) + result = factory(*[ + o.__self__ if isinstance(o, super) else o for o in objects + ]) if result is None: return default @@ -889,7 +909,9 @@ def _uncached_subscriptions(self, required, provided): return result def subscribers(self, objects, provided): - subscriptions = self.subscriptions([providedBy(o) for o in objects], provided) + subscriptions = self.subscriptions( + [providedBy(o) for o in objects], provided + ) if provided is None: result = () for subscription in subscriptions: @@ -902,9 +924,11 @@ def subscribers(self, objects, provided): result.append(subscriber) return result + class AdapterLookup(AdapterLookupBase, LookupBase): pass + @implementer(IAdapterRegistry) class AdapterRegistry(BaseAdapterRegistry): """ @@ -949,6 +973,7 @@ def changed(self, originally_changed): class VerifyingAdapterLookup(AdapterLookupBase, VerifyingBase): pass + @implementer(IAdapterRegistry) class VerifyingAdapterRegistry(BaseAdapterRegistry): """ @@ -957,13 +982,15 @@ class VerifyingAdapterRegistry(BaseAdapterRegistry): LookupClass = VerifyingAdapterLookup + def _convert_None_to_Interface(x): if x is None: return Interface else: return x -def _lookup(components, specs, provided, name, i, l): + +def _lookup(components, specs, provided, name, i, l): # noqa: E741 # this function is called very often. # The components.get in loops is executed 100 of 1000s times. # by loading get into a local variable the bytecode @@ -973,7 +1000,7 @@ def _lookup(components, specs, provided, name, i, l): for spec in specs[i].__sro__: comps = components_get(spec) if comps: - r = _lookup(comps, specs, provided, name, i+1, l) + r = _lookup(comps, specs, provided, name, i + 1, l) if r is not None: return r else: @@ -986,26 +1013,32 @@ def _lookup(components, specs, provided, name, i, l): return None -def _lookupAll(components, specs, provided, result, i, l): + +def _lookupAll(components, specs, provided, result, i, l): # noqa: E741 components_get = components.get # see _lookup above if i < l: for spec in reversed(specs[i].__sro__): comps = components_get(spec) if comps: - _lookupAll(comps, specs, provided, result, i+1, l) + _lookupAll(comps, specs, provided, result, i + 1, l) else: for iface in reversed(provided): comps = components_get(iface) if comps: result.update(comps) -def _subscriptions(components, specs, provided, name, result, i, l): + +def _subscriptions( + components, specs, provided, name, result, i, l # noqa: E741 +): components_get = components.get # see _lookup above if i < l: for spec in reversed(specs[i].__sro__): comps = components_get(spec) if comps: - _subscriptions(comps, specs, provided, name, result, i+1, l) + _subscriptions( + comps, specs, provided, name, result, i + 1, l + ) else: for iface in reversed(provided): comps = components_get(iface) diff --git a/src/zope/interface/advice.py b/src/zope/interface/advice.py index 5a8e3777..f577d42a 100644 --- a/src/zope/interface/advice.py +++ b/src/zope/interface/advice.py @@ -52,7 +52,7 @@ def getFrameInfo(frame): hasName = '__name__' in f_globals sameName = hasModule and hasName - sameName = sameName and f_globals['__name__']==f_locals['__module__'] + sameName = sameName and f_globals['__name__'] == f_locals['__module__'] module = hasName and sys.modules.get(f_globals['__name__']) or None @@ -67,35 +67,36 @@ def getFrameInfo(frame): 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. + 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') + 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] + 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: + if len(meta) == 1: # easy case return meta[0] - candidates = minimalBases(meta) # minimal set of metaclasses + candidates = minimalBases(meta) # minimal set of metaclasses - if len(candidates)>1: + if len(candidates) > 1: # We could auto-combine, but for now we won't... raise TypeError("Incompatible metatypes", bases) @@ -109,7 +110,7 @@ def minimalBases(classes): for m in classes: for n in classes: - if issubclass(n,m) and m is not n: + if issubclass(n, m) and m is not n: break else: # m has no subclasses in 'classes' diff --git a/src/zope/interface/common/__init__.py b/src/zope/interface/common/__init__.py index f308f9ed..4fee7e19 100644 --- a/src/zope/interface/common/__init__.py +++ b/src/zope/interface/common/__init__.py @@ -24,11 +24,11 @@ # 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 @@ -115,8 +115,9 @@ class ABCInterfaceClass(InterfaceClass): """ # 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? + # 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. @@ -128,7 +129,9 @@ def __init__(self, name, bases, 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) + ABCInterfaceClass.__register_classes( + self, extra_classes, ignored_classes, + ) self.__class__ = InterfaceClass return @@ -143,8 +146,9 @@ def __init__(self, name, bases, attrs): # 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) + 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) @@ -169,6 +173,7 @@ def __optional_methods_to_docs(attrs): def __create_class_doc(self, attrs): based_on = self.__abc + def ref(c): mod = c.__module__ name = c.__name__ @@ -177,12 +182,15 @@ def ref(c): 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 + implementations_doc = ( + "\n\nKnown implementations are:\n\n - " + implementations_doc + ) based_on_doc = (based_on.__doc__ or '') based_on_doc = based_on_doc.splitlines() @@ -196,7 +204,6 @@ def ref(c): ) return doc - @staticmethod def __is_private_name(name): if name.startswith('__') and name.endswith('__'): @@ -221,8 +228,14 @@ def __method_from_function(self, function, name): 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 + 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 @@ -246,7 +259,9 @@ def getRegisteredConformers(self): # 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) + 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. @@ -261,13 +276,16 @@ def getRegisteredConformers(self): 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 + # 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) + instance = ABCInterfaceClass.__new__( + ABCInterfaceClass, *abc_name_bases_attrs, + ) InterfaceClass.__init__(instance, *abc_name_bases_attrs) return instance + ABCInterface = _create_ABCInterface() diff --git a/src/zope/interface/common/builtins.py b/src/zope/interface/common/builtins.py index 6e13e064..09de5b3b 100644 --- a/src/zope/interface/common/builtins.py +++ b/src/zope/interface/common/builtins.py @@ -35,6 +35,7 @@ 'IFile', ] + # pylint:disable=no-self-argument class IList(collections.IMutableSequence): """ @@ -86,6 +87,8 @@ class INativeString(ITextString): 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) @@ -108,8 +111,8 @@ 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. + 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 diff --git a/src/zope/interface/common/collections.py b/src/zope/interface/common/collections.py index 3c751c05..543266d9 100644 --- a/src/zope/interface/common/collections.py +++ b/src/zope/interface/common/collections.py @@ -13,10 +13,10 @@ 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: +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 @@ -67,6 +67,7 @@ def _new_in_ver(name, ver, return missing + __all__ = [ 'IAsyncGenerator', 'IAsyncIterable', @@ -93,6 +94,7 @@ def _new_in_ver(name, ver, 'IValuesView', ] + class IContainer(ABCInterface): abc = abc.Container @@ -104,9 +106,11 @@ def __contains__(other): to implement ``in``. """ + class IHashable(ABCInterface): abc = abc.Hashable + class IIterable(ABCInterface): abc = abc.Iterable @@ -117,9 +121,11 @@ def __iter__(): implement `iter` using the old ``__getitem__`` protocol. """ + class IIterator(IIterable): abc = abc.Iterator + class IReversible(IIterable): abc = _new_in_ver('Reversible', True, (IIterable.getABC(),)) @@ -131,6 +137,7 @@ def __reversed__(): `reversed` builtin. """ + class IGenerator(IIterator): # New in Python 3.5 abc = _new_in_ver('Generator', True, (IIterator.getABC(),)) @@ -142,21 +149,25 @@ class ISized(ABCInterface): # 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())) + 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 + # On Python 2, basestring was 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 + ignored_classes = () @optional def __reversed__(): @@ -173,6 +184,7 @@ def __iter__(): implement `iter` using the old ``__getitem__`` protocol. """ + class IMutableSequence(ISequence): abc = abc.MutableSequence extra_classes = (UserList,) @@ -182,9 +194,9 @@ class IByteString(ISequence): """ This unifies `bytes` and `bytearray`. """ - abc = _new_in_ver('ByteString', True, - (ISequence.getABC(),), - (bytes, bytearray)) + abc = _new_in_ver( + 'ByteString', True, (ISequence.getABC(),), (bytes, bytearray), + ) class ISet(ICollection): @@ -210,6 +222,7 @@ class IMutableMapping(IMapping): extra_classes = (dict, UserDict,) ignored_classes = (OrderedDict,) + class IMappingView(ISized): abc = abc.MappingView @@ -233,6 +246,7 @@ def __contains__(other): to implement ``in``. """ + class IAwaitable(ABCInterface): abc = _new_in_ver('Awaitable', True) diff --git a/src/zope/interface/common/idatetime.py b/src/zope/interface/common/idatetime.py index aeda07aa..24b2606e 100644 --- a/src/zope/interface/common/idatetime.py +++ b/src/zope/interface/common/idatetime.py @@ -89,10 +89,10 @@ 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`. + 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): @@ -122,13 +122,17 @@ class IDate(IDateClass): month = Attribute("Between 1 and 12 inclusive") day = Attribute( - "Between 1 and the number of days in the given month of the given year.") + "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 + arguments are specified. + + For example, if ``d == date(2002, 12, 31)``, then ``d.replace(day=26) == date(2000, 12, 26)``. """ @@ -238,10 +242,10 @@ def today(): 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). + 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 @@ -269,7 +273,7 @@ def fromtimestamp(timestamp, tz=None): 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))``. + ``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() @@ -286,8 +290,8 @@ 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. + values supported by the platform C ``gmtime()`` function. It's common + for this to be restricted to years in 1970 through 2038. .. seealso:: `fromtimestamp`. """ @@ -312,7 +316,7 @@ def combine(date, time): class IDateTime(IDate, IDateTimeClass): - """Object contains all the information from a date object and a time object. + """Contains all the information from a date object and a time object. Implemented by `datetime.datetime`. """ @@ -337,7 +341,7 @@ class IDateTime(IDate, IDateTimeClass): or None if none was passed""") def date(): - """Return date object with same year, month and day.""" + """Return date object with same year, month and day.""" def time(): """Return time object with same hour, minute, second, microsecond. @@ -358,8 +362,8 @@ 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. + 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): @@ -377,13 +381,16 @@ def astimezone(tz): 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). + 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 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)``. @@ -405,7 +412,7 @@ def tzname(): """Return the timezone name.""" def timetuple(): - """Return a 9-element tuple of the form returned by `time.localtime`.""" + """Return a 9-tuple of the form returned by `time.localtime`.""" def utctimetuple(): """Return UTC time tuple compatilble with `time.gmtime`.""" @@ -453,17 +460,21 @@ def isoformat(sep='T'): """ def __str__(): - """For a datetime instance *d*, ``str(d)`` is equivalent to ``d.isoformat(' ')``. + """Convert to a stirng + + 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. + ``datetime(2002, 12, 4, 20, 30, 40).ctime()`` yields + ``'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): @@ -605,7 +616,7 @@ def fromutc(dt): classImplements(time, ITime) classImplements(tzinfo, ITZInfo) -## directlyProvides(timedelta, ITimeDeltaClass) -## directlyProvides(date, IDateClass) -## directlyProvides(datetime, IDateTimeClass) -## directlyProvides(time, ITimeClass) +# directlyProvides(timedelta, ITimeDeltaClass) +# directlyProvides(date, IDateClass) +# directlyProvides(datetime, IDateTimeClass) +# directlyProvides(time, ITimeClass) diff --git a/src/zope/interface/common/interfaces.py b/src/zope/interface/common/interfaces.py index 688e323a..74386de0 100644 --- a/src/zope/interface/common/interfaces.py +++ b/src/zope/interface/common/interfaces.py @@ -19,7 +19,7 @@ class IException(Interface): "Interface for `Exception`" -classImplements(Exception, IException) +classImplements(Exception, IException) # noqa E305 class IStandardError(IException): @@ -28,117 +28,117 @@ class IStandardError(IException): class IWarning(IException): "Interface for `Warning`" -classImplements(Warning, IWarning) +classImplements(Warning, IWarning) # noqa E305 class ISyntaxError(IStandardError): "Interface for `SyntaxError`" -classImplements(SyntaxError, ISyntaxError) +classImplements(SyntaxError, ISyntaxError) # noqa E305 class ILookupError(IStandardError): "Interface for `LookupError`" -classImplements(LookupError, ILookupError) +classImplements(LookupError, ILookupError) # noqa E305 class IValueError(IStandardError): "Interface for `ValueError`" -classImplements(ValueError, IValueError) +classImplements(ValueError, IValueError) # noqa E305 class IRuntimeError(IStandardError): "Interface for `RuntimeError`" -classImplements(RuntimeError, IRuntimeError) +classImplements(RuntimeError, IRuntimeError) # noqa E305 class IArithmeticError(IStandardError): "Interface for `ArithmeticError`" -classImplements(ArithmeticError, IArithmeticError) +classImplements(ArithmeticError, IArithmeticError) # noqa E305 class IAssertionError(IStandardError): "Interface for `AssertionError`" -classImplements(AssertionError, IAssertionError) +classImplements(AssertionError, IAssertionError) # noqa E305 class IAttributeError(IStandardError): "Interface for `AttributeError`" -classImplements(AttributeError, IAttributeError) +classImplements(AttributeError, IAttributeError) # noqa E305 class IDeprecationWarning(IWarning): "Interface for `DeprecationWarning`" -classImplements(DeprecationWarning, IDeprecationWarning) +classImplements(DeprecationWarning, IDeprecationWarning) # noqa E305 class IEOFError(IStandardError): "Interface for `EOFError`" -classImplements(EOFError, IEOFError) +classImplements(EOFError, IEOFError) # noqa E305 class IEnvironmentError(IStandardError): "Interface for `EnvironmentError`" -classImplements(EnvironmentError, IEnvironmentError) +classImplements(EnvironmentError, IEnvironmentError) # noqa E305 class IFloatingPointError(IArithmeticError): "Interface for `FloatingPointError`" -classImplements(FloatingPointError, IFloatingPointError) +classImplements(FloatingPointError, IFloatingPointError) # noqa E305 class IIOError(IEnvironmentError): "Interface for `IOError`" -classImplements(IOError, IIOError) +classImplements(IOError, IIOError) # noqa E305 class IImportError(IStandardError): "Interface for `ImportError`" -classImplements(ImportError, IImportError) +classImplements(ImportError, IImportError) # noqa E305 class IIndentationError(ISyntaxError): "Interface for `IndentationError`" -classImplements(IndentationError, IIndentationError) +classImplements(IndentationError, IIndentationError) # noqa E305 class IIndexError(ILookupError): "Interface for `IndexError`" -classImplements(IndexError, IIndexError) +classImplements(IndexError, IIndexError) # noqa E305 class IKeyError(ILookupError): "Interface for `KeyError`" -classImplements(KeyError, IKeyError) +classImplements(KeyError, IKeyError) # noqa E305 class IKeyboardInterrupt(IStandardError): "Interface for `KeyboardInterrupt`" -classImplements(KeyboardInterrupt, IKeyboardInterrupt) +classImplements(KeyboardInterrupt, IKeyboardInterrupt) # noqa E305 class IMemoryError(IStandardError): "Interface for `MemoryError`" -classImplements(MemoryError, IMemoryError) +classImplements(MemoryError, IMemoryError) # noqa E305 class INameError(IStandardError): "Interface for `NameError`" -classImplements(NameError, INameError) +classImplements(NameError, INameError) # noqa E305 class INotImplementedError(IRuntimeError): "Interface for `NotImplementedError`" -classImplements(NotImplementedError, INotImplementedError) +classImplements(NotImplementedError, INotImplementedError) # noqa E305 class IOSError(IEnvironmentError): "Interface for `OSError`" -classImplements(OSError, IOSError) +classImplements(OSError, IOSError) # noqa E305 class IOverflowError(IArithmeticError): "Interface for `ArithmeticError`" -classImplements(OverflowError, IOverflowError) +classImplements(OverflowError, IOverflowError) # noqa E305 class IOverflowWarning(IWarning): @@ -151,59 +151,59 @@ class IOverflowWarning(IWarning): class IReferenceError(IStandardError): "Interface for `ReferenceError`" -classImplements(ReferenceError, IReferenceError) +classImplements(ReferenceError, IReferenceError) # noqa E305 class IRuntimeWarning(IWarning): "Interface for `RuntimeWarning`" -classImplements(RuntimeWarning, IRuntimeWarning) +classImplements(RuntimeWarning, IRuntimeWarning) # noqa E305 class IStopIteration(IException): "Interface for `StopIteration`" -classImplements(StopIteration, IStopIteration) +classImplements(StopIteration, IStopIteration) # noqa E305 class ISyntaxWarning(IWarning): "Interface for `SyntaxWarning`" -classImplements(SyntaxWarning, ISyntaxWarning) +classImplements(SyntaxWarning, ISyntaxWarning) # noqa E305 class ISystemError(IStandardError): "Interface for `SystemError`" -classImplements(SystemError, ISystemError) +classImplements(SystemError, ISystemError) # noqa E305 class ISystemExit(IException): "Interface for `SystemExit`" -classImplements(SystemExit, ISystemExit) +classImplements(SystemExit, ISystemExit) # noqa E305 class ITabError(IIndentationError): "Interface for `TabError`" -classImplements(TabError, ITabError) +classImplements(TabError, ITabError) # noqa E305 class ITypeError(IStandardError): "Interface for `TypeError`" -classImplements(TypeError, ITypeError) +classImplements(TypeError, ITypeError) # noqa E305 class IUnboundLocalError(INameError): "Interface for `UnboundLocalError`" -classImplements(UnboundLocalError, IUnboundLocalError) +classImplements(UnboundLocalError, IUnboundLocalError) # noqa E305 class IUnicodeError(IValueError): "Interface for `UnicodeError`" -classImplements(UnicodeError, IUnicodeError) +classImplements(UnicodeError, IUnicodeError) # noqa E305 class IUserWarning(IWarning): "Interface for `UserWarning`" -classImplements(UserWarning, IUserWarning) +classImplements(UserWarning, IUserWarning) # noqa E305 class IZeroDivisionError(IArithmeticError): "Interface for `ZeroDivisionError`" -classImplements(ZeroDivisionError, IZeroDivisionError) +classImplements(ZeroDivisionError, IZeroDivisionError) # noqa E305 diff --git a/src/zope/interface/common/mapping.py b/src/zope/interface/common/mapping.py index eb9a2900..d8ea0748 100644 --- a/src/zope/interface/common/mapping.py +++ b/src/zope/interface/common/mapping.py @@ -96,9 +96,11 @@ 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. @@ -115,6 +117,7 @@ class IClonableMapping(Interface): def copy(): "return copy of dict" + class IExtendedReadMapping(IIterableMapping): """ Something with a particular method equivalent to ``__contains__``. @@ -154,9 +157,14 @@ 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,): + collections.IMutableMapping, + IExtendedReadMapping, + IExtendedWriteMapping, + IClonableMapping, + IMapping, +): """ Full mapping interface. diff --git a/src/zope/interface/common/sequence.py b/src/zope/interface/common/sequence.py index 738f76d4..c63f5a47 100644 --- a/src/zope/interface/common/sequence.py +++ b/src/zope/interface/common/sequence.py @@ -55,6 +55,7 @@ def __getitem__(index): Declaring this interface does not specify whether `__getitem__` supports slice objects.""" + class IFiniteSequence(collections.ISized, IMinimalSequence): """ A sequence of bound size. @@ -63,6 +64,7 @@ class IFiniteSequence(collections.ISized, IMinimalSequence): Extend ``ISized`` """ + class IReadSequence(collections.IContainer, IFiniteSequence): """ read interface shared by tuple and list @@ -120,6 +122,7 @@ def index(item, *args): Return first index of *value* """ + class IUniqueMemberWriteSequence(Interface): """The write contract for a sequence that may enforce unique members""" @@ -161,12 +164,14 @@ def sort(cmpfunc=None): 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. diff --git a/src/zope/interface/common/tests/__init__.py b/src/zope/interface/common/tests/__init__.py index ad999459..f70a5309 100644 --- a/src/zope/interface/common/tests/__init__.py +++ b/src/zope/interface/common/tests/__init__.py @@ -23,11 +23,14 @@ def iter_abc_interfaces(predicate=lambda iface: True): # 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. + # 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 + stack = list( + ABCInterface.dependents + ) # subclasses, but also implementedBy objects + while stack: iface = stack.pop(0) if iface in seen or not isinstance(iface, ABCInterfaceClass): @@ -54,7 +57,10 @@ def add_verify_tests(cls, iface_classes_iter): 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: + 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)) @@ -98,6 +104,7 @@ def test_ro(self, stdlib_class=stdlib_class, iface=iface): assert not hasattr(cls, name) setattr(cls, name, test_ro) + class VerifyClassMixin(unittest.TestCase): verifier = staticmethod(verifyClass) UNVERIFIABLE = () diff --git a/src/zope/interface/common/tests/basemapping.py b/src/zope/interface/common/tests/basemapping.py index f509e855..f60ec7cc 100644 --- a/src/zope/interface/common/tests/basemapping.py +++ b/src/zope/interface/common/tests/basemapping.py @@ -31,32 +31,37 @@ def testIReadMapping(self, inst, state, absent): 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() + inst_keys = sorted(inst.keys()) + state_keys = sorted(state.keys()) 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() + inst_keys = sorted(inst) + state_keys = sorted(state.keys()) 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() + inst_values = sorted(inst.values()) + state_values = sorted(state.values()) 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() + inst_items = sorted(inst.items()) + state_items = sorted(state.items()) 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) @@ -65,6 +70,7 @@ def testIEnumerableMapping(self, inst, state): class BaseTestIReadMapping: + def testIReadMapping(self): inst = self._IReadMapping__sample() state = self._IReadMapping__stateDict() @@ -74,6 +80,7 @@ def testIReadMapping(self): 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() diff --git a/src/zope/interface/common/tests/test_collections.py b/src/zope/interface/common/tests/test_collections.py index 44ff2dad..6d23f6f9 100644 --- a/src/zope/interface/common/tests/test_collections.py +++ b/src/zope/interface/common/tests/test_collections.py @@ -53,24 +53,24 @@ 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. + # 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. + # 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? + # 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 @@ -81,9 +81,9 @@ def test_UserString(self): 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. + # 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, @@ -96,6 +96,7 @@ def test_UserString(self): array.array, } + add_abc_interface_tests(TestVerifyClass, collections.ISet.__module__) diff --git a/src/zope/interface/common/tests/test_io.py b/src/zope/interface/common/tests/test_io.py index 3e3b72f5..72684bff 100644 --- a/src/zope/interface/common/tests/test_io.py +++ b/src/zope/interface/common/tests/test_io.py @@ -26,6 +26,7 @@ class TestVerifyClass(VerifyClassMixin, unittest.TestCase): pass + add_abc_interface_tests(TestVerifyClass, io.IIOBase.__module__) @@ -36,7 +37,9 @@ class TestVerifyObject(VerifyObjectMixin, 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.BufferedRWPair: lambda: abc.BufferedRWPair( + abc.BytesIO(), abc.BytesIO() + ), abc.FileIO: lambda: abc.FileIO(__file__), '_WindowsConsoleIO': unittest.SkipTest, 'WinConsoleIO': unittest.SkipTest, # breaks on PyPy-3.10 diff --git a/src/zope/interface/common/tests/test_numbers.py b/src/zope/interface/common/tests/test_numbers.py index c6282a3a..4e86514a 100644 --- a/src/zope/interface/common/tests/test_numbers.py +++ b/src/zope/interface/common/tests/test_numbers.py @@ -33,6 +33,7 @@ def test_float(self): self.assertIsInstance(float(), abc.Real) self.assertTrue(self.verify(numbers.IReal, float)) + add_abc_interface_tests(TestVerifyClass, numbers.INumber.__module__) diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py index 87e62520..7f2384af 100644 --- a/src/zope/interface/declarations.py +++ b/src/zope/interface/declarations.py @@ -61,6 +61,7 @@ def _next_super_class(ob): next_class = complete_mro[complete_mro.index(class_that_invoked_super) + 1] return next_class + class named: def __init__(self, name): @@ -103,7 +104,7 @@ def __sub__(self, other): if not [ j for j in other.interfaces() - if i.extends(j, 0) # non-strict extends + if i.extends(j, 0) # non-strict extends ] ]) @@ -114,10 +115,10 @@ def __add__(self, other): .. versionchanged:: 5.4.0 Now tries to preserve a consistent resolution order. Interfaces - being added to this object are added to the front of the resulting resolution - order if they already extend an interface in this object. Previously, - they were always added to the end of the order, which easily resulted in - invalid orders. + being added to this object are added to the front of the resulting + resolution order if they already extend an interface in this + object. Previously, they were always added to the end of the order, + which easily resulted in invalid orders. """ before = [] result = list(self.interfaces()) @@ -171,9 +172,11 @@ def _argument_names_for_repr(interfaces): # classes.) this_name = iface.__name__ duplicate_transform = _implements_name - elif (isinstance(iface, Implements) - and not iface.declared - and iface.inherit in interfaces): + elif ( + isinstance(iface, Implements) and + not iface.declared and + iface.inherit in interfaces + ): # If nothing is declared, there's no need to even print this; # it would just show as ``classImplements(Class)``, and the # ``Class`` has typically already. @@ -216,13 +219,15 @@ def __bases__(self): @__bases__.setter def __bases__(self, new_bases): # We expect the superclass constructor to set ``self.__bases__ = ()``. - # Rather than attempt to special case that in the constructor and allow - # setting __bases__ only at that time, it's easier to just allow setting - # the empty tuple at any time. That makes ``x.__bases__ = x.__bases__`` a nice - # no-op too. (Skipping the superclass constructor altogether is a recipe - # for maintenance headaches.) + # Rather than attempt to special case that in the constructor and + # allow setting __bases__ only at that time, it's easier to just allow + # setting the empty tuple at any time. That makes ``x.__bases__ = + # x.__bases__`` a nice no-op too. (Skipping the superclass constructor + # altogether is a recipe for maintenance headaches.) if new_bases != (): - raise TypeError("Cannot set non-empty bases on shared empty Declaration.") + raise TypeError( + "Cannot set non-empty bases on shared empty Declaration." + ) # As the immutable empty declaration, we cannot be changed. # This means there's no logical reason for us to have dependents @@ -246,20 +251,20 @@ def get(self, name, default=None): def weakref(self, callback=None): # We're a singleton, we never go away. So there's no need to return - # distinct weakref objects here; their callbacks will never - # be called. Instead, we only need to return a callable that - # returns ourself. The easiest one is to return _ImmutableDeclaration - # itself; testing on Python 3.8 shows that's faster than a function that - # returns _empty. (Remember, one goal is to avoid allocating any - # object, and that includes a method.) + # distinct weakref objects here; their callbacks will never be called. + # Instead, we only need to return a callable that returns ourself. The + # easiest one is to return _ImmutableDeclaration itself; testing on + # Python 3.8 shows that's faster than a function that returns _empty. + # (Remember, one goal is to avoid allocating any object, and that + # includes a method.) return _ImmutableDeclaration @property def _v_attrs(self): # _v_attrs is not a public, documented property, but some client code # uses it anyway as a convenient place to cache things. To keep the - # empty declaration truly immutable, we must ignore that. That includes - # ignoring assignments as well. + # empty declaration truly immutable, we must ignore that. That + # includes ignoring assignments as well. return {} @_v_attrs.setter @@ -275,26 +280,28 @@ def _v_attrs(self, new_attrs): class Implements(NameAndModuleComparisonMixin, Declaration): - # Inherit from NameAndModuleComparisonMixin to be - # mutually comparable with InterfaceClass objects. - # (The two must be mutually comparable to be able to work in e.g., BTrees.) - # Instances of this class generally don't have a __module__ other than - # `zope.interface.declarations`, whereas they *do* have a __name__ that is the - # fully qualified name of the object they are representing. + # Inherit from NameAndModuleComparisonMixin to be mutually comparable with + # InterfaceClass objects. (The two must be mutually comparable to be able + # to work in e.g., BTrees.) Instances of this class generally don't have a + # __module__ other than `zope.interface.declarations`, whereas they *do* + # have a __name__ that is the fully qualified name of the object they are + # representing. # Note, though, that equality and hashing are still identity based. This - # accounts for things like nested objects that have the same name (typically - # only in tests) and is consistent with pickling. As far as comparisons to InterfaceClass - # goes, we'll never have equal name and module to those, so we're still consistent there. - # Instances of this class are essentially intended to be unique and are - # heavily cached (note how our __reduce__ handles this) so having identity - # based hash and eq should also work. - - # We want equality and hashing to be based on identity. However, we can't actually - # implement __eq__/__ne__ to do this because sometimes we get wrapped in a proxy. - # We need to let the proxy types implement these methods so they can handle unwrapping - # and then rely on: (1) the interpreter automatically changing `implements == proxy` into - # `proxy == implements` (which will call proxy.__eq__ to do the unwrapping) and then + # accounts for things like nested objects that have the same name + # (typically only in tests) and is consistent with pickling. As far as + # comparisons to InterfaceClass goes, we'll never have equal name and + # module to those, so we're still consistent there. Instances of this + # class are essentially intended to be unique and are heavily cached (note + # how our __reduce__ handles this) so having identity based hash and eq + # should also work. + + # We want equality and hashing to be based on identity. However, we can't + # actually implement __eq__/__ne__ to do this because sometimes we get + # wrapped in a proxy. We need to let the proxy types implement these + # methods so they can handle unwrapping and then rely on: (1) the + # interpreter automatically changing `implements == proxy` into `proxy == + # implements` (which will call proxy.__eq__ to do the unwrapping) and then # (2) the default equality and hashing semantics being identity based. # class whose specification should be used as additional base @@ -313,11 +320,11 @@ class Implements(NameAndModuleComparisonMixin, @classmethod def named(cls, name, *bases): - # Implementation method: Produce an Implements interface with - # a fully fleshed out __name__ before calling the constructor, which - # sets bases to the given interfaces and which may pass this object to - # other objects (e.g., to adjust dependents). If they're sorting or comparing - # by name, this needs to be set. + # Implementation method: Produce an Implements interface with a fully + # fleshed out __name__ before calling the constructor, which sets + # bases to the given interfaces and which may pass this object to + # other objects (e.g., to adjust dependents). If they're sorting or + # comparing by name, this needs to be set. inst = cls.__new__(cls) inst.__name__ = name inst.__init__(*bases) @@ -332,7 +339,10 @@ def changed(self, originally_changed): def __repr__(self): if self.inherit: - name = getattr(self.inherit, '__name__', None) or _implements_name(self.inherit) + name = ( + getattr(self.inherit, '__name__', None) or + _implements_name(self.inherit) + ) else: name = self.__name__ declared_names = self._argument_names_for_repr(self.declared) @@ -370,7 +380,7 @@ def _implementedBy_super(sup): # that excludes the classes being skipped over but # includes everything else. implemented_by_self = implementedBy(sup.__self_class__) - cache = implemented_by_self._super_cache # pylint:disable=protected-access + cache = implemented_by_self._super_cache # pylint:disable=protected-access if cache is None: cache = implemented_by_self._super_cache = weakref.WeakKeyDictionary() @@ -405,7 +415,9 @@ def _implementedBy_super(sup): @_use_c_impl -def implementedBy(cls): # pylint:disable=too-many-return-statements,too-many-branches +def implementedBy( + cls +): # pylint:disable=too-many-return-statements,too-many-branches """Return the interfaces implemented for a class' instances The value returned is an `~zope.interface.interfaces.IDeclaration`. @@ -459,10 +471,10 @@ def implementedBy(cls): # pylint:disable=too-many-return-statements,too-many-bra spec_name = _implements_name(cls) if spec is not None: # old-style __implemented__ = foo declaration - spec = (spec, ) # tuplefy, as it might be just an int + spec = (spec, ) # tuplefy, as it might be just an int spec = Implements.named(spec_name, *_normalizeargs(spec)) - spec.inherit = None # old-style implies no inherit - del cls.__implemented__ # get rid of the old-style declaration + spec.inherit = None # old-style implies no inherit + del cls.__implemented__ # get rid of the old-style declaration else: try: bases = cls.__bases__ @@ -482,9 +494,8 @@ def implementedBy(cls): # pylint:disable=too-many-return-statements,too-many-bra if isinstance(cls, type) and '__provides__' not in cls.__dict__: # Make sure we get a __provides__ descriptor cls.__provides__ = ClassProvides( - cls, - getattr(cls, '__class__', type(cls)), - ) + cls, getattr(cls, '__class__', type(cls)), + ) except TypeError: if not isinstance(cls, type): @@ -502,9 +513,10 @@ def classImplementsOnly(cls, *interfaces): specifications (`~zope.interface.interfaces.IDeclaration` objects). The interfaces given (including the interfaces in the specifications) - replace any previous declarations, *including* inherited definitions. If you - wish to preserve inherited declarations, you can pass ``implementedBy(cls)`` - in *interfaces*. This can be used to alter the interface resolution order. + replace any previous declarations, *including* inherited definitions. If + you wish to preserve inherited declarations, you can pass + ``implementedBy(cls)`` in *interfaces*. This can be used to alter the + interface resolution order. """ spec = implementedBy(cls) # Clear out everything inherited. It's important to @@ -521,8 +533,8 @@ def classImplements(cls, *interfaces): """ Declare additional interfaces implemented for instances of a class - The arguments after the class are one or more interfaces or - interface specifications (`~zope.interface.interfaces.IDeclaration` objects). + The arguments after the class are one or more interfaces or interface + specifications (`~zope.interface.interfaces.IDeclaration` objects). The interfaces given (including the interfaces in the specifications) are added to any interfaces previously declared. An effort is made to @@ -534,13 +546,14 @@ def classImplements(cls, *interfaces): based on inheritance, in order to try to maintain a consistent resolution order. Previously, all interfaces were added to the end. .. versionchanged:: 5.1.0 - If *cls* is already declared to implement an interface (or derived interface) - in *interfaces* through inheritance, the interface is ignored. Previously, it - would redundantly be made direct base of *cls*, which often produced inconsistent - interface resolution orders. Now, the order will be consistent, but may change. - Also, if the ``__bases__`` of the *cls* are later changed, the *cls* will no - longer be considered to implement such an interface (changing the ``__bases__`` of *cls* - has never been supported). + If *cls* is already declared to implement an interface (or derived + interface) in *interfaces* through inheritance, the interface is + ignored. Previously, it would redundantly be made direct base of *cls*, + which often produced inconsistent interface resolution orders. Now, the + order will be consistent, but may change. Also, if the ``__bases__`` + of the *cls* are later changed, the *cls* will no longer be considered + to implement such an interface (changing the ``__bases__`` of *cls* has + never been supported). """ spec = implementedBy(cls) interfaces = tuple(_normalizeargs(interfaces)) @@ -578,9 +591,9 @@ def classImplementsFirst(cls, iface): def _classImplements_ordered(spec, before=(), after=()): # Elide everything already inherited. # Except, if it is the root, and we don't already declare anything else - # that would imply it, allow the root through. (TODO: When we disallow non-strict - # IRO, this part of the check can be removed because it's not possible to re-declare - # like that.) + # that would imply it, allow the root through. (TODO: When we disallow + # non-strict IRO, this part of the check can be removed because it's not + # possible to re-declare like that.) before = [ x for x in before @@ -595,8 +608,8 @@ def _classImplements_ordered(spec, before=(), after=()): # eliminate duplicates new_declared = [] seen = set() - for l in before, spec.declared, after: - for b in l: + for lst in before, spec.declared, after: + for b in lst: if b not in seen: new_declared.append(b) seen.add(b) @@ -604,7 +617,7 @@ def _classImplements_ordered(spec, before=(), after=()): spec.declared = tuple(new_declared) # compute the bases - bases = new_declared # guaranteed no dupes + bases = new_declared # guaranteed no dupes if spec.inherit is not None: for c in spec.inherit.__bases__: @@ -629,19 +642,18 @@ class implementer: This function is called as a class decorator. - The arguments are one or more interfaces or interface - specifications (`~zope.interface.interfaces.IDeclaration` - objects). + The arguments are one or more interfaces or interface specifications + (`~zope.interface.interfaces.IDeclaration` objects). - The interfaces given (including the interfaces in the - specifications) are added to any interfaces previously declared, - unless the interface is already implemented. + The interfaces given (including the interfaces in the specifications) are + added to any interfaces previously declared, unless the interface is + already implemented. Previous declarations include declarations for base classes unless implementsOnly was used. - This function is provided for convenience. It provides a more - convenient way to call `classImplements`. For example:: + This function is provided for convenience. It provides a more convenient + way to call `classImplements`. For example:: @implementer(I1) class C(object): @@ -675,6 +687,7 @@ def __call__(self, ob): raise TypeError("Can't declare implements", ob) return ob + class implementer_only: """Declare the only interfaces implemented by instances of a class @@ -728,22 +741,23 @@ class Provides(Declaration): # Really named ProvidesClass def __init__(self, cls, *interfaces): self.__args = (cls, ) + interfaces self._cls = cls - Declaration.__init__(self, *self._add_interfaces_to_cls(interfaces, cls)) + Declaration.__init__( + self, *self._add_interfaces_to_cls(interfaces, cls) + ) # Added to by ``moduleProvides``, et al _v_module_names = () def __repr__(self): - # The typical way to create instances of this - # object is via calling ``directlyProvides(...)`` or ``alsoProvides()``, - # but that's not the only way. Proxies, for example, - # directly use the ``Provides(...)`` function (which is the - # more generic method, and what we pickle as). We're after the most - # readable, useful repr in the common case, so we use the most - # common name. + # The typical way to create instances of this object is via calling + # ``directlyProvides(...)`` or ``alsoProvides()``, but that's not the + # only way. Proxies, for example, directly use the ``Provides(...)`` + # function (which is the more generic method, and what we pickle as). + # We're after the most readable, useful repr in the common case, so we + # use the most common name. # - # We also cooperate with ``moduleProvides`` to attempt to do the - # right thing for that API. See it for details. + # We also cooperate with ``moduleProvides`` to attempt to do the right + # thing for that API. See it for details. function_name = 'directlyProvides' if self._cls is ModuleType and self._v_module_names: # See notes in ``moduleProvides``/``directlyProvides`` @@ -783,13 +797,16 @@ def __get__(self, inst, cls): raise AttributeError('__provides__') + ProvidesClass = Provides + # Registry of instance declarations # This is a memory optimization to allow objects to share specifications. InstanceDeclarations = weakref.WeakValueDictionary() -def Provides(*interfaces): # pylint:disable=function-redefined + +def Provides(*interfaces): # pylint:disable=function-redefined """Declaration for an instance of *cls*. The correct signature is ``cls, *interfaces``. @@ -806,10 +823,11 @@ def Provides(*interfaces): # pylint:disable=function-redefined return spec + Provides.__safe_for_unpickling__ = True -def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin +def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin """Declare interfaces declared directly for an object The arguments after the object are one or more interfaces or interface @@ -842,8 +860,7 @@ def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin provides._v_module_names += (object.__name__,) - -def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin +def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin """Declare interfaces declared directly for an object The arguments after the object are one or more interfaces or interface @@ -855,7 +872,7 @@ def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin directlyProvides(object, directlyProvidedBy(object), *interfaces) -def noLongerProvides(object, interface): # pylint:disable=redefined-builtin +def noLongerProvides(object, interface): # pylint:disable=redefined-builtin """ Removes a directly provided interface from an object. """ directlyProvides(object, directlyProvidedBy(object) - interface) @@ -903,17 +920,19 @@ def __init__(self, cls, metacls, *interfaces): self._cls = cls self._implements = implementedBy(cls) self.__args = (cls, metacls, ) + interfaces - Declaration.__init__(self, *self._add_interfaces_to_cls(interfaces, metacls)) + Declaration.__init__( + self, *self._add_interfaces_to_cls(interfaces, metacls) + ) def __repr__(self): - # There are two common ways to get instances of this object: - # The most interesting way is calling ``@provider(..)`` as a decorator - # of a class; this is the same as calling ``directlyProvides(cls, ...)``. + # There are two common ways to get instances of this object: The most + # interesting way is calling ``@provider(..)`` as a decorator of a + # class; this is the same as calling ``directlyProvides(cls, ...)``. # - # The other way is by default: anything that invokes ``implementedBy(x)`` - # will wind up putting an instance in ``type(x).__provides__``; this includes - # the ``@implementer(...)`` decorator. Those instances won't have any - # interfaces. + # The other way is by default: anything that invokes + # ``implementedBy(x)`` will wind up putting an instance in + # ``type(x).__provides__``; this includes the ``@implementer(...)`` + # decorator. Those instances won't have any interfaces. # # Thus, as our repr, we go with the ``directlyProvides()`` syntax. interfaces = (self._cls, ) + self.__args[2:] @@ -927,18 +946,18 @@ def __reduce__(self): __get__ = ClassProvidesBase.__get__ -def directlyProvidedBy(object): # pylint:disable=redefined-builtin +def directlyProvidedBy(object): # pylint:disable=redefined-builtin """Return the interfaces directly provided by the given object The value returned is an `~zope.interface.interfaces.IDeclaration`. """ provides = getattr(object, "__provides__", None) if ( - provides is None # no spec + provides is None # no spec # We might have gotten the implements spec, as an # optimization. If so, it's like having only one base, that we # lop off to exclude class-supplied declarations: - or isinstance(provides, Implements) + or isinstance(provides, Implements) # noqa W503 ): return _empty @@ -1008,8 +1027,8 @@ def moduleProvides(*interfaces): directlyProvides(sys.modules[__name__], I1) """ - frame = sys._getframe(1) # pylint:disable=protected-access - locals = frame.f_locals # pylint:disable=redefined-builtin + frame = sys._getframe(1) # pylint:disable=protected-access + locals = frame.f_locals # pylint:disable=redefined-builtin # Try to make sure we were called from a module body if (locals is not frame.f_globals) or ('__name__' not in locals): @@ -1020,18 +1039,18 @@ def moduleProvides(*interfaces): raise TypeError( "moduleProvides can only be used once in a module definition.") - # Note: This is cached based on the key ``(ModuleType, *interfaces)``; - # One consequence is that any module that provides the same interfaces - # gets the same ``__repr__``, meaning that you can't tell what module - # such a declaration came from. Adding the module name to ``_v_module_names`` - # attempts to correct for this; it works in some common situations, but fails - # (1) after pickling (the data is lost) and (2) if declarations are - # actually shared and (3) if the alternate spelling of ``directlyProvides()`` - # is used. Problem (3) is fixed by cooperating with ``directlyProvides`` - # to maintain this information, and problem (2) is worked around by - # printing all the names, but (1) is unsolvable without introducing - # new classes or changing the stored data...but it doesn't actually matter, - # because ``ModuleType`` can't be pickled! + # Note: This is cached based on the key ``(ModuleType, *interfaces)``; One + # consequence is that any module that provides the same interfaces gets + # the same ``__repr__``, meaning that you can't tell what module such a + # declaration came from. Adding the module name to ``_v_module_names`` + # attempts to correct for this; it works in some common situations, but + # fails (1) after pickling (the data is lost) and (2) if declarations are + # actually shared and (3) if the alternate spelling of + # ``directlyProvides()`` is used. Problem (3) is fixed by cooperating + # with ``directlyProvides`` to maintain this information, and problem (2) + # is worked around by printing all the names, but (1) is unsolvable + # without introducing new classes or changing the stored data...but it + # doesn't actually matter, because ``ModuleType`` can't be pickled! p = locals["__provides__"] = Provides(ModuleType, *_normalizeargs(interfaces)) p._v_module_names += (locals['__name__'],) @@ -1050,7 +1069,8 @@ def ObjectSpecification(direct, cls): These combine information for the object and for it's classes. """ - return Provides(cls, direct) # pragma: no cover fossil + return Provides(cls, direct) # pragma: no cover fossil + @_use_c_impl def getObjectSpecification(ob): @@ -1086,7 +1106,7 @@ def providedBy(ob): # Try to get __providedBy__ try: - if isinstance(ob, super): # Some objects raise errors on isinstance() + if isinstance(ob, super): # Some objects raise errors on isinstance() return implementedBy(ob) r = ob.__providedBy__ @@ -1136,8 +1156,8 @@ def providedBy(ob): class ObjectSpecificationDescriptor: """Implement the ``__providedBy__`` attribute - The ``__providedBy__`` attribute computes the interfaces provided by - an object. If an object has an ``__provides__`` attribute, that is returned. + The ``__providedBy__`` attribute computes the interfaces provided by an + object. If an object has an ``__provides__`` attribute, that is returned. Otherwise, `implementedBy` the *cls* is returned. .. versionchanged:: 5.4.0 @@ -1184,6 +1204,7 @@ def _normalizeargs(sequence, output=None): return output + _empty = _ImmutableDeclaration() objectSpecificationDescriptor = ObjectSpecificationDescriptor() diff --git a/src/zope/interface/document.py b/src/zope/interface/document.py index 2595c569..ce3546c5 100644 --- a/src/zope/interface/document.py +++ b/src/zope/interface/document.py @@ -24,7 +24,8 @@ 'asStructuredText', ] -def asStructuredText(I, munge=0, rst=False): + +def asStructuredText(iface, munge=0, rst=False): """ Output structured text format. Note, this will whack any existing 'structured' format of the text. @@ -33,19 +34,21 @@ def asStructuredText(I, munge=0, rst=False): """ if rst: - inline_literal = lambda s: "``{}``".format(s) + def inline_literal(s): + return "``{}``".format(s) else: - inline_literal = lambda s: s + def inline_literal(s): + return s - r = [inline_literal(I.getName())] + r = [inline_literal(iface.getName())] outp = r.append level = 1 - if I.getDoc(): - outp(_justify_and_indent(_trim_doc_string(I.getDoc()), level)) + if iface.getDoc(): + outp(_justify_and_indent(_trim_doc_string(iface.getDoc()), level)) bases = [base - for base in I.__bases__ + for base in iface.__bases__ if base is not zope.interface.Interface ] if bases: @@ -56,14 +59,16 @@ def asStructuredText(I, munge=0, rst=False): outp(_justify_and_indent(_trim_doc_string(item), level, munge)) level -= 1 - namesAndDescriptions = sorted(I.namesAndDescriptions()) + namesAndDescriptions = sorted(iface.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') + item = "{} -- {}".format( + inline_literal(desc.getName()), + desc.getDoc() or 'no documentation' + ) outp(_justify_and_indent(_trim_doc_string(item), level, munge)) level -= 1 @@ -72,17 +77,20 @@ def asStructuredText(I, munge=0, rst=False): 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') + 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 asReStructuredText(iface, munge=0): + """ Output reStructuredText format. + + Note, this will whack any existing 'structured' format of the text.""" + return asStructuredText(iface, munge=munge, rst=True) def _trim_doc_string(text): diff --git a/src/zope/interface/exceptions.py b/src/zope/interface/exceptions.py index 0612eb23..1b7fe7d3 100644 --- a/src/zope/interface/exceptions.py +++ b/src/zope/interface/exceptions.py @@ -26,6 +26,7 @@ 'InvalidInterface', ] + class Invalid(Exception): """A specification is violated """ @@ -55,7 +56,7 @@ class _TargetInvalid(Invalid): def _get_arg_or_default(self, ix, default=None): try: - return self.args[ix] # pylint:disable=unsubscriptable-object + return self.args[ix] # pylint:disable=unsubscriptable-object except self._NOT_GIVEN_CATCH: return default @@ -146,7 +147,7 @@ class BrokenImplementation(_TargetInvalid): @property def name(self): - return self.args[1] # pylint:disable=unsubscriptable-object + return self.args[1] # pylint:disable=unsubscriptable-object @property def _str_details(self): @@ -157,7 +158,9 @@ def _str_details(self): class BrokenMethodImplementation(_TargetInvalid): """ - BrokenMethodImplementation(method, message[, implementation, interface, target]) + BrokenMethodImplementation( + method, message[, implementation, interface, target] + ) The *target* (optional) has a *method* in *implementation* that violates its contract in a way described by *mess*. @@ -181,11 +184,11 @@ class BrokenMethodImplementation(_TargetInvalid): @property def method(self): - return self.args[0] # pylint:disable=unsubscriptable-object + return self.args[0] # pylint:disable=unsubscriptable-object @property def mess(self): - return self.args[1] # pylint:disable=unsubscriptable-object + return self.args[1] # pylint:disable=unsubscriptable-object @staticmethod def __implementation_str(impl): @@ -197,8 +200,7 @@ def __implementation_str(impl): formatsig = str except AttributeError: sig = inspect.getargspec - f = inspect.formatargspec - formatsig = lambda sig: f(*sig) # pylint:disable=deprecated-method + formatsig = inspect.formatargspec try: sig = sig(impl) @@ -248,7 +250,7 @@ def __init__(self, interface, target, exceptions): @property def exceptions(self): - return self.args[2] # pylint:disable=unsubscriptable-object + return self.args[2] # pylint:disable=unsubscriptable-object @property def _str_details(self): @@ -259,7 +261,7 @@ def _str_details(self): for x in self.exceptions ) - _str_conjunction = ':' # We don't want a trailing space, messes up doctests + _str_conjunction = ':' # no trailing space, messes up doctests _str_trailer = '' @@ -267,6 +269,7 @@ class InvalidInterface(Exception): """The interface has invalid contents """ + class BadImplements(TypeError): """An implementation assertion is invalid diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py index e55ee7f0..81fe5317 100644 --- a/src/zope/interface/interface.py +++ b/src/zope/interface/interface.py @@ -47,7 +47,6 @@ _marker = object() - def invariant(call): f_locals = sys._getframe(1).f_locals tags = f_locals.setdefault(TAGGED_DATA, {}) @@ -72,9 +71,11 @@ class Element: # We can't say this yet because we don't have enough # infrastructure in place. # - #implements(IElement) + # implements(IElement) - def __init__(self, __name__, __doc__=''): # pylint:disable=redefined-builtin + def __init__( + self, __name__, __doc__='', + ): # pylint:disable=redefined-builtin if not __doc__ and __name__.find(' ') >= 0: __doc__ = __name__ __name__ = None @@ -108,7 +109,9 @@ def getTaggedValue(self, tag): def queryTaggedValue(self, tag, default=None): """ Returns the value associated with 'tag'. """ - return self.__tagged_values.get(tag, default) if self.__tagged_values else default + return self.__tagged_values.get( + tag, default, + ) if self.__tagged_values else default def getTaggedValueTags(self): """ Returns a collection of all tags. """ @@ -125,7 +128,7 @@ def setTaggedValue(self, tag, value): getDirectTaggedValueTags = getTaggedValueTags -SpecificationBasePy = object # filled by _use_c_impl. +SpecificationBasePy = object # filled by _use_c_impl. @_use_c_impl @@ -170,7 +173,7 @@ def implementedBy(self, cls): def isOrExtends(self, interface): """Is the interface the same as or extend the given interface """ - return interface in self._implied # pylint:disable=no-member + return interface in self._implied # pylint:disable=no-member __call__ = isOrExtends @@ -181,10 +184,11 @@ class NameAndModuleComparisonMixin: # attributes. Subclasses will be mutually comparable; but because equality # and hashing semantics are missing from this class, take care in how # you define those two attributes: If you stick with the default equality - # and hashing (identity based) you should make sure that all possible ``__name__`` - # and ``__module__`` pairs are unique ACROSS ALL SUBCLASSES. (Actually, pretty - # much the same thing goes if you define equality and hashing to be based on - # those two attributes: they must still be consistent ACROSS ALL SUBCLASSES.) + # and hashing (identity based) you should make sure that all possible + # ``__name__`` and ``__module__`` pairs are unique ACROSS ALL SUBCLASSES. + # (Actually, pretty much the same thing goes if you define equality and + # hashing to be based on those two attributes: they must still be + # consistent ACROSS ALL SUBCLASSES.) # pylint:disable=assigning-non-slot __slots__ = () @@ -206,8 +210,8 @@ def _compare(self, other): For example, ``class Foo(object)`` and ``class Foo(Interface)`` in the same file would compare equal, depending on the order of - operands. Writing code like this by hand would be unusual, but it could - happen with dynamic creation of types and interfaces. + operands. Writing code like this by hand would be unusual, but it + could happen with dynamic creation of types and interfaces. None is treated as a pseudo interface that implies the loosest contact possible, no contract. For that reason, all interfaces @@ -333,6 +337,7 @@ def __ne__(self, other): return c return c != 0 + adapter_hooks = _use_c_impl([], 'adapter_hooks') @@ -367,7 +372,7 @@ def __init__(self, bases=()): # 4700 had 0 dependents, 1400 had 1, 382 had 2 and so on. Only one # for had 1664. So there's savings to be had deferring # the creation of dependents. - self._dependents = None # type: weakref.WeakKeyDictionary + self._dependents = None # type: weakref.WeakKeyDictionary self._bases = () self._implied = {} self._v_attrs = None @@ -410,9 +415,8 @@ def __setBases(self, bases): self.changed(self) __bases__ = property( - lambda self: self._bases, - __setBases, - ) + lambda self: self._bases, __setBases, + ) # This method exists for tests to override the way we call # ro.calculate_ro(), usually by adding extra kwargs. We don't @@ -422,26 +426,25 @@ def __setBases(self, bases): _do_calculate_ro = calculate_ro def _calculate_sro(self): - """ - Calculate and return the resolution order for this object, using its ``__bases__``. + """Compute resolution order for this object using its ``__bases__``. - Ensures that ``Interface`` is always the last (lowest priority) element. + Ensures that ``Interface`` is always the last (lowest priority) + element. """ - # We'd like to make Interface the lowest priority as a - # property of the resolution order algorithm. That almost - # works out naturally, but it fails when class inheritance has - # some bases that DO implement an interface, and some that DO - # NOT. In such a mixed scenario, you wind up with a set of - # bases to consider that look like this: [[..., Interface], - # [..., object], ...]. Depending on the order of inheritance, - # Interface can wind up before or after object, and that can - # happen at any point in the tree, meaning Interface can wind - # up somewhere in the middle of the order. Since Interface is - # treated as something that everything winds up implementing - # anyway (a catch-all for things like adapters), having it high up - # the order is bad. It's also bad to have it at the end, just before - # some concrete class: concrete classes should be HIGHER priority than - # interfaces (because there's only one class, but many implementations). + # We'd like to make Interface the lowest priority as a property of the + # resolution order algorithm. That almost works out naturally, but it + # fails when class inheritance has some bases that DO implement an + # interface, and some that DO NOT. In such a mixed scenario, you wind + # up with a set of bases to consider that look like this: [[..., + # Interface], [..., object], ...]. Depending on the order of + # inheritance, Interface can wind up before or after object, and that + # can happen at any point in the tree, meaning Interface can wind up + # somewhere in the middle of the order. Since Interface is treated as + # something that everything winds up implementing anyway (a catch-all + # for things like adapters), having it high up the order is bad. It's + # also bad to have it at the end, just before some concrete class: + # concrete classes should be HIGHER priority than interfaces (because + # there's only one class, but many implementations). # # One technically nice way to fix this would be to have # ``implementedBy(object).__bases__ = (Interface,)`` @@ -462,9 +465,9 @@ def _calculate_sro(self): }) root = self._ROOT if root is not None and sro and sro[-1] is not root: - # In one dataset of 1823 Interface objects, 1117 ClassProvides objects, - # sro[-1] was root 4496 times, and only not root 118 times. So it's - # probably worth checking. + # In one dataset of 1823 Interface objects, 1117 ClassProvides + # objects, sro[-1] was root 4496 times, and only not root 118 + # times. So it's probably worth checking. # Once we don't have to deal with old-style classes, # we can add a check and only do this if base_count > 1, @@ -502,7 +505,9 @@ def changed(self, originally_changed): # Now, advise our dependents of change # (being careful not to create the WeakKeyDictionary if not needed): - for dependent in tuple(self._dependents.keys() if self._dependents else ()): + for dependent in tuple( + self._dependents.keys() if self._dependents else () + ): dependent.changed(originally_changed) # Just in case something called get() at some point @@ -526,10 +531,11 @@ def extends(self, interface, strict=True): Test whether an interface in the specification extends the given interface """ - return ((interface in self._implied) - and - ((not strict) or (self != interface)) - ) + return ( + (interface in self._implied) and ( + (not strict) or (self != interface) + ) + ) def weakref(self, callback=None): return weakref.ref(self, callback) @@ -552,14 +558,13 @@ def get(self, name, default=None): class _InterfaceMetaClass(type): - # Handling ``__module__`` on ``InterfaceClass`` is tricky. We need - # to be able to read it on a type and get the expected string. We - # also need to be able to set it on an instance and get the value - # we set. So far so good. But what gets tricky is that we'd like - # to store the value in the C structure (``InterfaceBase.__ibmodule__``) for - # direct access during equality, sorting, and hashing. "No - # problem, you think, I'll just use a property" (well, the C - # equivalents, ``PyMemberDef`` or ``PyGetSetDef``). + # Handling ``__module__`` on ``InterfaceClass`` is tricky. We need to be + # able to read it on a type and get the expected string. We also need to + # be able to set it on an instance and get the value we set. So far so + # good. But what gets tricky is that we'd like to store the value in the C + # structure (``InterfaceBase.__ibmodule__``) for direct access during + # equality, sorting, and hashing. "No problem, you think, I'll just use a + # property" (well, the C equivalents, ``PyMemberDef`` or ``PyGetSetDef``). # # Except there is a problem. When a subclass is created, the # metaclass (``type``) always automatically puts the expected @@ -578,13 +583,14 @@ class _InterfaceMetaClass(type): # (when implemented in C). Since that includes methods like # ``providedBy``, that's probably not acceptable. # - # All the other methods involve modifying subclasses. This can be - # done either on the fly in some cases, as instances are - # constructed, or by using a metaclass. These next few can be done on the fly. + # All the other methods involve modifying subclasses. This can be done + # either on the fly in some cases, as instances are constructed, or by + # using a metaclass. These next few can be done on the fly. # - # (2) Make ``__module__`` a descriptor in each subclass dictionary. - # It can't be a straight up ``@property`` descriptor, though, because accessing - # it on the class returns a ``property`` object, not the desired string. + # (2) Make ``__module__`` a descriptor in each subclass dictionary. It + # can't be a straight up ``@property`` descriptor, though, because + # accessing it on the class returns a ``property`` object, not the desired + # string. # # (3) Implement a data descriptor (``__get__`` and ``__set__``) # that is both a subclass of string, and also does the redirect of @@ -599,11 +605,12 @@ class _InterfaceMetaClass(type): # This works, preserves the ability to read and write # ``__module__``, and eliminates any penalty accessing other # attributes. But it slows down accessing ``__module__`` of - # instances by 200% (40ns to 124ns), requires editing class dicts on the fly - # (in InterfaceClass.__init__), thus slightly slowing down all interface creation, - # and is ugly. + # instances by 200% (40ns to 124ns), requires editing class dicts on the + # fly (in InterfaceClass.__init__), thus slightly slowing down all + # interface creation, and is ugly. # - # (4) As in the last step, but make it a non-data descriptor (no ``__set__``). + # (4) As in the last step, but make it a non-data descriptor (no + # ``__set__``). # # If you then *also* store a copy of ``__ibmodule__`` in # ``__module__`` in the instance's dict, reading works for both @@ -673,7 +680,8 @@ def interfacemethod(func): define the ``__adapt__`` method, but other interface methods can be overridden this way too. - .. seealso:: `zope.interface.interfaces.IInterfaceDeclaration.interfacemethod` + .. seealso:: + `zope.interface.interfaces.IInterfaceDeclaration.interfacemethod` """ f_locals = sys._getframe(1).f_locals methods = f_locals.setdefault(INTERFACE_METHODS, {}) @@ -692,10 +700,16 @@ class InterfaceClass(_InterfaceClassBase): # We can't say this yet because we don't have enough # infrastructure in place. # - #implements(IInterface) - - def __new__(cls, name=None, bases=(), attrs=None, __doc__=None, # pylint:disable=redefined-builtin - __module__=None): + # implements(IInterface) + + def __new__( + cls, + name=None, + bases=(), + attrs=None, + __doc__=None, # pylint:disable=redefined-builtin + __module__=None, + ): assert isinstance(bases, tuple) attrs = attrs or {} needs_custom_class = attrs.pop(INTERFACE_METHODS, None) @@ -716,7 +730,7 @@ def __new__(cls, name=None, bases=(), attrs=None, __doc__=None, # pylint:disable else: cls_bases = (cls, _InterfaceClassWithCustomMethods) - cls = type(cls)( # pylint:disable=self-cls-assignment + cls = type(cls)( # pylint:disable=self-cls-assignment name + "", cls_bases, needs_custom_class @@ -724,8 +738,14 @@ def __new__(cls, name=None, bases=(), attrs=None, __doc__=None, # pylint:disable return _InterfaceClassBase.__new__(cls) - def __init__(self, name, bases=(), attrs=None, __doc__=None, # pylint:disable=redefined-builtin - __module__=None): + def __init__( + self, + name, + bases=(), + attrs=None, + __doc__=None, # pylint:disable=redefined-builtin + __module__=None, + ): # We don't call our metaclass parent directly # pylint:disable=non-parent-init-called # pylint:disable=super-init-not-called @@ -745,7 +765,7 @@ def __init__(self, name, bases=(), attrs=None, __doc__=None, # pylint:disable=r # This is how cPython figures out the module of # a class, but of course it does it in C. :-/ __module__ = sys._getframe(1).f_globals['__name__'] - except (AttributeError, KeyError): # pragma: no cover + except (AttributeError, KeyError): # pragma: no cover pass InterfaceBase.__init__(self, name, __module__) @@ -806,7 +826,7 @@ def update_value(aname, aval): # https://github.com/python/cpython/pull/118475 '__firstlineno__', ) - and aval is not _decorator_non_return + and aval is not _decorator_non_return # noqa W503 } def interfaces(self): @@ -821,7 +841,7 @@ def isEqualOrExtendedBy(self, other): """Same interface or extends?""" return self == other or other.extends(self) - def names(self, all=False): # pylint:disable=redefined-builtin + def names(self, all=False): # pylint:disable=redefined-builtin """Return the attribute names defined by the interface.""" if not all: return self.__attrs.keys() @@ -836,7 +856,9 @@ def names(self, all=False): # pylint:disable=redefined-builtin def __iter__(self): return iter(self.names(all=True)) - def namesAndDescriptions(self, all=False): # pylint:disable=redefined-builtin + def namesAndDescriptions( + self, all=False # pylint:disable=redefined-builtin + ): """Return attribute names and descriptions defined by interface.""" if not all: return self.__attrs.items() @@ -886,8 +908,8 @@ def validateInvariants(self, obj, errors=None): def queryTaggedValue(self, tag, default=None): """ - Queries for the value associated with *tag*, returning it from the nearest - interface in the ``__iro__``. + Queries for the value associated with *tag*, returning it from the + nearest interface in the ``__iro__``. If not found, returns *default*. """ @@ -917,7 +939,7 @@ def __repr__(self): except AttributeError: name = str(self) r = "<{} {}>".format(self.__class__.__name__, name) - self._v_repr = r # pylint:disable=attribute-defined-outside-init + self._v_repr = r # pylint:disable=attribute-defined-outside-init return r def __str__(self): @@ -930,7 +952,7 @@ def __str__(self): def _call_conform(self, conform): try: return conform(self) - except TypeError: # pragma: no cover + except TypeError: # pragma: no cover # We got a TypeError. It might be an error raised by # the __conform__ implementation, or *we* may have # made the TypeError by calling an unbound method @@ -944,7 +966,7 @@ def _call_conform(self, conform): raise # This clever trick is from Phillip Eby - return None # pragma: no cover + return None # pragma: no cover def __reduce__(self): return self.__name__ @@ -957,6 +979,7 @@ def __ror__(self, other): """Allow type hinting syntax: None | Interface.""" return Union[other, self] + Interface = InterfaceClass("Interface", __module__='zope.interface') # Interface is the only member of its own SRO. Interface._calculate_sro = lambda: (Interface,) @@ -965,9 +988,11 @@ def __ror__(self, other): Specification._ROOT = Interface ro._ROOT = Interface + class _InterfaceClassWithCustomMethods(InterfaceClass): """ - Marker class for interfaces with custom methods that override InterfaceClass methods. + Marker class for interfaces with custom methods that override + InterfaceClass methods. """ @@ -989,7 +1014,12 @@ def _get_str_info(self): def __str__(self): of = '' if self.interface is not None: - of = self.interface.__module__ + '.' + self.interface.__name__ + '.' + of = ( + self.interface.__module__ + + '.' + + self.interface.__name__ + + '.' + ) # self.__name__ may be None during construction (e.g., debugging) return of + (self.__name__ or '') + self._get_str_info() @@ -1016,14 +1046,18 @@ class Method(Attribute): positional = required = () _optional = varargs = kwargs = None + def _get_optional(self): if self._optional is None: return {} return self._optional + def _set_optional(self, opt): self._optional = opt + def _del_optional(self): self._optional = None + optional = property(_get_optional, _set_optional, _del_optional) def __call__(self, *args, **kw): @@ -1145,5 +1179,5 @@ def _wire(): # list of the immutable declaration. It correctly overrides changed() # as a no-op, so we bypass that. # pylint:disable=wrong-import-position -from zope.interface.declarations import _empty # isort: skip +from zope.interface.declarations import _empty # isort: skip Specification.changed(_empty, _empty) diff --git a/src/zope/interface/interfaces.py b/src/zope/interface/interfaces.py index 0d315cb6..30eb3bdb 100644 --- a/src/zope/interface/interfaces.py +++ b/src/zope/interface/interfaces.py @@ -52,6 +52,7 @@ # pylint:disable=unexpected-special-method-signature # pylint:disable=too-many-lines + class IElement(Interface): """ Objects that have basic documentation and tagged values. @@ -82,7 +83,8 @@ class IElement(Interface): # make ``IInterface`` define new methods # ``getIndirectTaggedValue``, etc, to include inheritance instead # of overriding ``getTaggedValue`` to do that, but that ship has sailed. - # So to keep things nice and symmetric, we define the ``Direct`` methods here. + # So to keep things nice and symmetric, we define the ``Direct`` methods + # here. ### def getTaggedValue(tag): @@ -100,7 +102,8 @@ def getTaggedValue(tag): def queryTaggedValue(tag, default=None): """ - As for `getTaggedValue`, but instead of raising a `KeyError`, returns *default*. + As for `getTaggedValue`, but instead of raising a `KeyError`, returns + *default*. .. versionchanged:: 4.7.0 @@ -179,14 +182,15 @@ def getSignatureString(): """Return a signature string suitable for inclusion in documentation. This method returns the function signature string. For example, if you - have ``def func(a, b, c=1, d='f')``, then the signature string is ``"(a, b, - c=1, d='f')"``. + have ``def func(a, b, c=1, d='f')``, then the signature string is + ``"(a, b, c=1, d='f')"``. """ + class ISpecification(Interface): """Object Behavioral specifications""" # pylint:disable=arguments-differ - def providedBy(object): # pylint:disable=redefined-builtin + def providedBy(object): # pylint:disable=redefined-builtin """Test whether the interface is implemented by the object Return true of the object asserts that it implements the @@ -346,7 +350,7 @@ class itself implements, but only what its instances """ # pylint:disable=arguments-differ - def names(all=False): # pylint:disable=redefined-builtin + def names(all=False): # pylint:disable=redefined-builtin """Get the interface attribute names Return a collection of the names of the attributes, including @@ -357,7 +361,7 @@ def names(all=False): # pylint:disable=redefined-builtin attributes defined by base classes will be included. """ - def namesAndDescriptions(all=False): # pylint:disable=redefined-builtin + def namesAndDescriptions(all=False): # pylint:disable=redefined-builtin """Get the interface attribute names and descriptions Return a collection of the names and descriptions of the @@ -461,6 +465,7 @@ def __nonzero__(): """Return a true value of the interface specification is non-empty """ + class IInterfaceDeclaration(Interface): """ Declare and check the interfaces of objects. @@ -534,10 +539,10 @@ def interfacemethod(method): A decorator that transforms a method specification into an implementation method. - This is used to override methods of ``Interface`` or provide new methods. - Definitions using this decorator will not appear in :meth:`IInterface.names()`. - It is possible to have an implementation method and a method specification - of the same name. + This is used to override methods of ``Interface`` or provide new + methods. Definitions using this decorator will not appear in + :meth:`IInterface.names()`. It is possible to have an implementation + method and a method specification of the same name. For example:: @@ -549,10 +554,10 @@ def __adapt__(self, obj): return obj return super(type(IRange), self).__adapt__(obj) - You can use ``super`` to call the parent class functionality. Note that - the zero-argument version (``super().__adapt__``) works on Python 3.6 and above, but - prior to that the two-argument version must be used, and the class must be explicitly - passed as the first argument. + You can use ``super`` to call the parent class functionality. Note + that the zero-argument version (``super().__adapt__``) works on Python + 3.6 and above, but prior to that the two-argument version must be + used, and the class must be explicitly passed as the first argument. .. versionadded:: 5.1.0 .. seealso:: `zope.interface.interfacemethod` @@ -667,7 +672,7 @@ def implementer_only(*interfaces): .. seealso:: `zope.interface.implementer_only` """ - def directlyProvidedBy(object): # pylint:disable=redefined-builtin + def directlyProvidedBy(object): # pylint:disable=redefined-builtin """ Return the interfaces directly provided by the given object. @@ -676,7 +681,9 @@ def directlyProvidedBy(object): # pylint:disable=redefined-builtin .. seealso:: `zope.interface.directlyProvidedBy` """ - def directlyProvides(object, *interfaces): # pylint:disable=redefined-builtin + def directlyProvides( + object, *interfaces, + ): # pylint:disable=redefined-builtin """ Declare interfaces declared directly for an object. @@ -720,7 +727,7 @@ class C(A, B): .. seealso:: `zope.interface.directlyProvides` """ - def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin + def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin """ Declare additional interfaces directly for an object. @@ -735,7 +742,9 @@ def alsoProvides(object, *interfaces): # pylint:disable=redefined-builtin .. seealso:: `zope.interface.alsoProvides` """ - def noLongerProvides(object, interface): # pylint:disable=redefined-builtin + def noLongerProvides( + object, interface, + ): # pylint:disable=redefined-builtin """ Remove an interface from the list of an object's directly provided interfaces. @@ -803,6 +812,7 @@ def Declaration(*interfaces): .. seealso:: `zope.interface.Declaration` """ + class IAdapterRegistry(Interface): """Provide an interface-based registry for adapters @@ -856,11 +866,15 @@ def lookup1(required, provided, name='', default=None): text. """ - def queryAdapter(object, provided, name='', default=None): # pylint:disable=redefined-builtin + def queryAdapter( + object, provided, name='', default=None, + ): # pylint:disable=redefined-builtin """Adapt an object using a registered adapter factory. """ - def adapter_hook(provided, object, name='', default=None): # pylint:disable=redefined-builtin + def adapter_hook( + provided, object, name='', default=None, + ): # pylint:disable=redefined-builtin """Adapt an object using a registered adapter factory. name must be text. @@ -872,11 +886,13 @@ def lookupAll(required, provided): An iterable object is returned that provides name-value two-tuples. """ - def names(required, provided): # pylint:disable=arguments-differ + def names(required, provided): # pylint:disable=arguments-differ """Return the names for which there are registered objects """ - def subscribe(required, provided, subscriber): # pylint:disable=arguments-differ + def subscribe( + required, provided, subscriber, + ): # pylint:disable=arguments-differ """Register a subscriber A subscriber is registered for a *sequence* of required @@ -954,12 +970,15 @@ def subscribers(objects, provided): # begin formerly in zope.component + class ComponentLookupError(LookupError): """A component could not be found.""" + class Invalid(Exception): """A component doesn't satisfy a promise.""" + class IObjectEvent(Interface): """An event related to an object. @@ -973,7 +992,7 @@ class IObjectEvent(Interface): @implementer(IObjectEvent) class ObjectEvent: - def __init__(self, object): # pylint:disable=redefined-builtin + def __init__(self, object): # pylint:disable=redefined-builtin self.object = object @@ -990,13 +1009,17 @@ class IComponentLookup(Interface): utilities = Attribute( "Adapter Registry to manage all registered utilities.") - def queryAdapter(object, interface, name='', default=None): # pylint:disable=redefined-builtin + def queryAdapter( + object, interface, name='', default=None + ): # pylint:disable=redefined-builtin """Look for a named adapter to an interface for an object If a matching adapter cannot be found, returns the default. """ - def getAdapter(object, interface, name=''): # pylint:disable=redefined-builtin + def getAdapter( + object, interface, name='' + ): # pylint:disable=redefined-builtin """Look for a named adapter to an interface for an object If a matching adapter cannot be found, a `ComponentLookupError` @@ -1058,6 +1081,7 @@ def getAllUtilitiesRegisteredFor(interface): returned. """ + class IRegistration(Interface): """A registration-information object """ @@ -1073,6 +1097,7 @@ class IRegistration(Interface): commentary or information about the source of the configuration. """) + class IUtilityRegistration(IRegistration): """Information about the registration of a utility """ @@ -1081,6 +1106,7 @@ class IUtilityRegistration(IRegistration): component = Attribute("The object registered") provided = Attribute("The interface provided by the component") + class _IBaseAdapterRegistration(IRegistration): """Information about the registration of an adapter """ @@ -1099,14 +1125,17 @@ class _IBaseAdapterRegistration(IRegistration): This interface is implemented by the factory """) + class IAdapterRegistration(_IBaseAdapterRegistration): """Information about the registration of an adapter """ + class ISubscriptionAdapterRegistration(_IBaseAdapterRegistration): """Information about the registration of a subscription adapter """ + class IHandlerRegistration(IRegistration): handler = Attribute("An object called used to handle an event") @@ -1118,6 +1147,7 @@ class IHandlerRegistration(IRegistration): positional arguments, that provide these interfaces. """) + class IRegistrationEvent(IObjectEvent): """An event that involves a registration""" @@ -1129,18 +1159,22 @@ class RegistrationEvent(ObjectEvent): def __repr__(self): return "{} event:\n{!r}".format(self.__class__.__name__, self.object) + class IRegistered(IRegistrationEvent): """A component or factory was registered """ + @implementer(IRegistered) class Registered(RegistrationEvent): pass + class IUnregistered(IRegistrationEvent): """A component or factory was unregistered """ + @implementer(IUnregistered) class Unregistered(RegistrationEvent): """A component or factory was unregistered diff --git a/src/zope/interface/registry.py b/src/zope/interface/registry.py index a6a24fdd..970ac2ab 100644 --- a/src/zope/interface/registry.py +++ b/src/zope/interface/registry.py @@ -18,8 +18,9 @@ try: from zope.event import notify -except ImportError: # pragma: no cover - def notify(*arg, **kw): pass +except ImportError: # pragma: no cover + def notify(*arg, **kw): + pass from zope.interface.adapter import AdapterRegistry from zope.interface.declarations import implementedBy @@ -45,6 +46,7 @@ def notify(*arg, **kw): pass 'Components', ] + class _UnhashableComponentCounter: # defaultdict(int)-like object for unhashable components @@ -70,11 +72,13 @@ def __delitem__(self, component): if data[0] == component: del self._data[i] return - raise KeyError(component) # pragma: no cover + raise KeyError(component) # pragma: no cover + def _defaultdict_int(): return defaultdict(int) + class _UtilityRegistrations: def __init__(self, utilities, utility_registrations): @@ -94,18 +98,20 @@ 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]) + # 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. + # 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: @@ -124,7 +130,9 @@ def _is_utility_subscribed(self, provided, component): def registerUtility(self, provided, name, component, info, factory): subscribed = self._is_utility_subscribed(provided, component) - self._utility_registrations[(provided, name)] = component, info, factory + self._utility_registrations[ + (provided, name) + ] = component, info, factory self._utilities.register((), provided, name, component) if not subscribed: @@ -192,12 +200,16 @@ 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) + 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): @@ -215,7 +227,7 @@ def _setBases(self, 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): @@ -242,9 +254,9 @@ def registerUtility(self, component=None, provided=None, name='', if event: notify(Registered( - UtilityRegistration(self, provided, name, component, info, - factory) - )) + UtilityRegistration( + self, provided, name, component, info, factory) + )) def unregisterUtility(self, component=None, provided=None, name='', factory=None): @@ -273,7 +285,7 @@ def unregisterUtility(self, component=None, provided=None, name='', notify(Unregistered( UtilityRegistration(self, provided, name, component, *old[1:]) - )) + )) return True @@ -310,10 +322,10 @@ def registerAdapter(self, factory, required=None, provided=None, if event: notify(Registered( - AdapterRegistration(self, required, provided, name, - factory, info) - )) - + AdapterRegistration( + self, required, provided, name, factory, info + ) + )) def unregisterAdapter(self, factory=None, required=None, provided=None, name='', @@ -336,9 +348,8 @@ def unregisterAdapter(self, factory=None, self.adapters.unregister(required, provided, name) notify(Unregistered( - AdapterRegistration(self, required, provided, name, - *old) - )) + AdapterRegistration(self, required, provided, name, *old) + )) return True @@ -370,8 +381,8 @@ def getMultiAdapter(self, objects, interface, name=''): def getAdapters(self, objects, provided): for name, factory in self.adapters.lookupAll( - list(map(providedBy, objects)), - provided): + list(map(providedBy, objects)), provided, + ): adapter = factory(*objects) if adapter is not None: yield name, adapter @@ -387,22 +398,23 @@ def registerSubscriptionAdapter(self, 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) - )) + 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='', - ): + def unregisterSubscriptionAdapter( + self, factory=None, required=None, provided=None, name='', + ): if name: raise TypeError("Named subscribers are not yet supported") if provided is None: @@ -431,14 +443,14 @@ def unregisterSubscriptionAdapter(self, factory=None, 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, '') - )) + SubscriptionRegistration( + self, required, provided, name, factory, '', + ) + )) return True @@ -454,13 +466,13 @@ def registerHandler(self, 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: @@ -496,7 +508,7 @@ def unregisterHandler(self, factory=None, required=None, name=''): notify(Unregistered( HandlerRegistration(self, required, name, factory, '') - )) + )) return True @@ -520,9 +532,10 @@ def rebuildUtilityRegistryFromLocalCache(self, rebuild=False): 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. + 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 """ @@ -533,7 +546,6 @@ def rebuildUtilityRegistryFromLocalCache(self, rebuild=False): 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__ @@ -570,19 +582,23 @@ def rebuildUtilityRegistryFromLocalCache(self, rebuild=False): '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.") + "and no provided interface was specified." + ) + def _getAdapterProvided(factory): provided = list(implementedBy(factory)) @@ -590,7 +606,9 @@ def _getAdapterProvided(factory): return provided[0] raise TypeError( "The adapter factory doesn't implement a single interface " - "and no provided interface was specified.") + "and no provided interface was specified." + ) + def _getAdapterRequired(factory, required): if required is None: @@ -600,10 +618,12 @@ def _getAdapterRequired(factory, required): 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") + raise TypeError( + "the required argument should be a list of " + "interfaces, not a single interface" + ) result = [] for r in required: @@ -613,9 +633,10 @@ def _getAdapterRequired(factory, required): if isinstance(r, type): r = implementedBy(r) else: - raise TypeError("Required specification must be a " - "specification or class, not %r" % type(r) - ) + raise TypeError( + "Required specification must be a " + "specification or class, not %r" % type(r) + ) result.append(r) return tuple(result) @@ -624,18 +645,21 @@ def _getAdapterRequired(factory, required): 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 + self.registry = registry + self.provided = provided + self.name = name + self.component = component + self.info = doc + self.factory = 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, - ) + 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) @@ -658,6 +682,7 @@ def __gt__(self, other): def __ge__(self, other): return repr(self) >= repr(other) + @implementer(IAdapterRegistration) class AdapterRegistration: @@ -673,7 +698,7 @@ def __repr__(self): '[' + ", ".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) @@ -696,6 +721,7 @@ def __gt__(self, other): def __ge__(self, other): return repr(self) >= repr(other) + @implementer_only(ISubscriptionAdapterRegistration) class SubscriptionRegistration(AdapterRegistration): pass @@ -721,4 +747,4 @@ def __repr__(self): '[' + ", ".join([r.__name__ for r in self.required]) + ']', self.name, getattr(self.factory, '__name__', repr(self.factory)), self.info, - ) + ) diff --git a/src/zope/interface/ro.py b/src/zope/interface/ro.py index 52986483..5d0b6680 100644 --- a/src/zope/interface/ro.py +++ b/src/zope/interface/ro.py @@ -28,37 +28,45 @@ .. 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. +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. + 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. + 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`. + 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. + ``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. + 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. + 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 @@ -82,6 +90,9 @@ """ __docformat__ = 'restructuredtext' +import warnings + + __all__ = [ 'ro', 'InconsistentResolutionOrderError', @@ -90,13 +101,15 @@ __logger = None + def _logger(): - global __logger # pylint:disable=global-statement + 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 @@ -106,7 +119,7 @@ def _legacy_mergeOrderings(orderings): For example: - >>> _mergeOrderings([ + >>> _legacy_mergeOrderings([ ... ['x', 'y', 'z'], ... ['q', 'z'], ... [1, 3, 5], @@ -126,6 +139,7 @@ def _legacy_mergeOrderings(orderings): return result + def _legacy_flatten(begin): result = [begin] i = 0 @@ -139,6 +153,7 @@ def _legacy_flatten(begin): result[i:i] = ob.__bases__ return result + def _legacy_ro(ob): return _legacy_mergeOrderings([_legacy_flatten(ob)]) @@ -156,6 +171,7 @@ 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. @@ -177,7 +193,9 @@ def __init__(self, c3, base_tree_remaining): def __str__(self): import pprint - return "{}: For object {!r}.\nBase ROs:\n{}\nConflict Location:\n{}".format( + return ( + "{}: For object {!r}.\nBase ROs:\n{}\nConflict Location:\n{}" + ).format( self.__class__.__name__, self.C, pprint.pformat(self.base_ros), @@ -185,7 +203,7 @@ def __str__(self): ) -class _NamedBool(int): # cannot actually inherit bool +class _NamedBool(int): # cannot actually inherit bool def __new__(cls, val, name): inst = super(cls, _NamedBool).__new__(cls, val) @@ -209,7 +227,7 @@ def __get__(self, inst, klass): break if my_name is not None: break - else: # pragma: no cover + else: # pragma: no cover raise RuntimeError("Unable to find self") env_name = 'ZOPE_INTERFACE_' + my_name @@ -224,7 +242,7 @@ class _StaticMRO: # A previously resolved MRO, supplied by the caller. # Used in place of calculating it. - had_inconsistency = None # We don't know... + had_inconsistency = None # We don't know... def __init__(self, C, mro): self.leaf = C @@ -234,6 +252,16 @@ def mro(self): return list(self.__mro) +_INCONSISTENT_RESOLUTION_ORDER = """\ +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.""" + + class C3: # Holds the shared state during computation of an MRO. @@ -278,7 +306,9 @@ def __init__(self, C, memo): list(C.__bases__) ] - self.bases_had_inconsistency = any(base.had_inconsistency for base in base_resolvers) + 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() @@ -306,15 +336,8 @@ def _warn_iro(self): # 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.", + _INCONSISTENT_RESOLUTION_ORDER, InconsistentResolutionOrderWarning, ) @@ -344,7 +367,8 @@ 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. + 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: @@ -352,8 +376,9 @@ def _choose_next_base(self, base_tree_remaining): 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. + """Return the next base that fits the constraints + + Return ``None`` if there isn't one. """ for bases in base_tree_remaining: base = bases[0] @@ -379,11 +404,12 @@ def _guess_next_base(self, base_tree_remaining): # 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, ]`` - # (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. + # ``[IEnvironmentError, IIOError, IOSError, ]`` (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: @@ -409,7 +435,9 @@ def _guess_next_base(self, base_tree_remaining): # # So now, we fall back to the old linearization (fast to compute). self._warn_iro() - self.direct_inconsistency = InconsistentResolutionOrderError(self, base_tree_remaining) + self.direct_inconsistency = InconsistentResolutionOrderError( + self, base_tree_remaining, + ) raise self._UseLegacyRO def _merge(self): @@ -422,7 +450,9 @@ def _merge(self): # 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) + base_tree_remaining = self._nonempty_bases_ignoring( + base_tree_remaining, base + ) if not base_tree_remaining: return result @@ -442,12 +472,14 @@ def mro(self): 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 @@ -474,8 +506,10 @@ class _ROComparison: # 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, @@ -490,9 +524,10 @@ class Inserted(Item): Empty = str - class ReplacedBy: # pragma: no cover + class ReplacedBy: # pragma: no cover prefix = '- ' suffix = '' + def __init__(self, chunk, total_count): self.chunk = chunk self.total_count = total_count @@ -511,7 +546,6 @@ class Replacing(ReplacedBy): prefix = "+ " suffix = '' - _c3_report = None _legacy_report = None @@ -547,16 +581,23 @@ def _generate_report(self): if opcode == 'delete': # Guaranteed same length assert not c3_chunk - self.__move(c3_report, legacy_report, legacy_chunk, self.Deleted) + 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?) + 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)) + legacy_report.extend( + self.ReplacedBy(legacy_chunk, chunk_size), + ) return self._c3_report, self._legacy_report @@ -591,7 +632,12 @@ def __str__(self): self._inconsistent_label, ) lines = [ - (padding + left_title.ljust(max_left) + padding + right_title.ljust(max_right)), + ( + padding + + left_title.ljust(max_left) + + padding + + right_title.ljust(max_right) + ), padding + '=' * (max_left + len(padding) + max_right) ] lines += [ @@ -606,7 +652,10 @@ def __str__(self): # 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): + +def ro( + C, strict=None, base_mros=None, log_changed_ro=None, use_legacy_ro=None, +): """ ro(C) -> list @@ -624,8 +673,14 @@ def ro(C, strict=None, base_mros=None, log_changed_ro=None, use_legacy_ro=None): 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 + 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 @@ -660,8 +715,8 @@ def ro(C, strict=None, base_mros=None, log_changed_ro=None, use_legacy_ro=None): def is_consistent(C): - """ - Check if the resolution order for *C*, as computed by :func:`ro`, is consistent - according to C3. + """Is the resolution order for *C*, consistent according to C3. + + Order as computed by :func:`ro`. """ return not C3.resolver(C, False, None).had_inconsistency diff --git a/src/zope/interface/tests/__init__.py b/src/zope/interface/tests/__init__.py index 04ff9399..11125132 100644 --- a/src/zope/interface/tests/__init__.py +++ b/src/zope/interface/tests/__init__.py @@ -65,14 +65,16 @@ def __getattribute__(self, name): @classmethod def test_raises(cls, unittest, test_func, expected_missing, **other_attrs): """ - Loop through various exceptions, calling *test_func* inside a ``assertRaises`` block. + 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*. + :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 @@ -83,13 +85,14 @@ def test_raises(cls, unittest, test_func, expected_missing, **other_attrs): unittest.assertEqual(ex.exception.args[0], expected_missing) - # Now test that the AttributeError for that expected_missing is *not* raised. + # 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 + except Exception: # pylint:disable=broad-except pass # Be sure cleanup functionality is available; classes that use the adapter hook @@ -99,13 +102,16 @@ def test_raises(cls, unittest, test_func, expected_missing, **other_attrs): # (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.) +# 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 diff --git a/src/zope/interface/tests/advisory_testing.py b/src/zope/interface/tests/advisory_testing.py index b8021454..93769552 100644 --- a/src/zope/interface/tests/advisory_testing.py +++ b/src/zope/interface/tests/advisory_testing.py @@ -20,8 +20,10 @@ ClassicClass = None + class NewStyleClass: __metaclass__ = type classLevelFrameInfo = getFrameInfo(sys._getframe()) + moduleLevelFrameInfo = getFrameInfo(sys._getframe()) diff --git a/src/zope/interface/tests/dummy.py b/src/zope/interface/tests/dummy.py index ffc27e53..8ec85f80 100644 --- a/src/zope/interface/tests/dummy.py +++ b/src/zope/interface/tests/dummy.py @@ -19,6 +19,7 @@ moduleProvides(IDummyModule) + def bar(baz): # Note: no 'self', because the module provides the interface directly. raise NotImplementedError() diff --git a/src/zope/interface/tests/m1.py b/src/zope/interface/tests/m1.py index c969c1a5..8998e46e 100644 --- a/src/zope/interface/tests/m1.py +++ b/src/zope/interface/tests/m1.py @@ -17,7 +17,12 @@ from zope.interface import moduleProvides -class I1(Interface): pass -class I2(Interface): pass +class I1(Interface): + pass + + +class I2(Interface): + pass + moduleProvides(I1, I2) diff --git a/src/zope/interface/tests/odd.py b/src/zope/interface/tests/odd.py index 27b42cad..bcead56c 100644 --- a/src/zope/interface/tests/odd.py +++ b/src/zope/interface/tests/odd.py @@ -62,6 +62,7 @@ # class OddClass is an odd meta class + class MetaMetaClass(type): def __getattribute__(cls, name): @@ -90,14 +91,19 @@ def __getattr__(self, name): return v raise AttributeError(name) - def __repr__(self): # pragma: no cover + def __repr__(self): # pragma: no cover return "".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__',)}) +MetaClass = MetaMetaClass( + 'MetaClass', + MetaClass.__bases__, + { + k: v for k, v in MetaClass.__dict__.items() + if k not in ('__dict__',) + } +) + class OddInstance: @@ -119,6 +125,6 @@ def __setattr__(self, name, v): def __delattr__(self, name): raise NotImplementedError() - def __repr__(self): # pragma: no cover + def __repr__(self): # pragma: no cover return "".format( self.__class__.__name__, hex(id(self))) diff --git a/src/zope/interface/tests/test_adapter.py b/src/zope/interface/tests/test_adapter.py index 45809cb1..ea90732c 100644 --- a/src/zope/interface/tests/test_adapter.py +++ b/src/zope/interface/tests/test_adapter.py @@ -26,22 +26,28 @@ def _makeInterfaces(): class IB0(Interface): pass + class IB1(IB0): pass + class IB2(IB0): pass + class IB3(IB2, IB1): pass + class IB4(IB1, IB2): pass class IF0(Interface): pass + class IF1(IF0): pass class IR0(Interface): pass + class IR1(IR0): pass @@ -53,6 +59,7 @@ class IR1(IR0): # types propagate through the data tree as expected. class CustomDataTypeBase: _data = None + def __getitem__(self, name): return self._data[name] @@ -72,13 +79,14 @@ def __eq__(self, other): if other is self: return True # pylint:disable=unidiomatic-typecheck - if type(other) != type(self): + if type(other) is not type(self): return False return other._data == self._data def __repr__(self): return repr(self._data) + class CustomMapping(CustomDataTypeBase): def __init__(self, other=None): self._data = {} @@ -95,9 +103,11 @@ def __init__(self, other=None): self._data.extend(other) self.append = self._data.append + class CustomLeafSequence(CustomSequence): pass + class CustomProvided(CustomMapping): pass @@ -112,18 +122,25 @@ def _getBaseAdapterRegistry(self): def _getTargetClass(self): BaseAdapterRegistry = self._getBaseAdapterRegistry() + class _CUT(BaseAdapterRegistry): + class LookupClass: _changed = _extendors = () + def __init__(self, reg): pass + def changed(self, orig): self._changed += (orig,) + def add_extendor(self, provided): self._extendors += (provided,) + def remove_extendor(self, provided): self._extendors = tuple([x for x in self._extendors if x != provided]) + for name in BaseAdapterRegistry._delegated: setattr(_CUT.LookupClass, name, object()) return _CUT @@ -147,7 +164,9 @@ def test_lookup_delegation(self): CUT = self._getTargetClass() registry = CUT() for name in CUT._delegated: - self.assertIs(getattr(registry, name), getattr(registry._v_lookup, name)) + self.assertIs( + getattr(registry, name), getattr(registry._v_lookup, name) + ) def test__generation_on_first_creation(self): registry = self._makeOne() @@ -170,7 +189,9 @@ class _Base: self.assertEqual(registry._generation, 2) def _check_basic_types_of_adapters(self, registry, expected_order=2): - self.assertEqual(len(registry._adapters), expected_order) # order 0 and order 1 + self.assertEqual( + len(registry._adapters), expected_order, + ) # order 0 and order 1 self.assertIsInstance(registry._adapters, self._getMutableListType()) MT = self._getMappingType() for mapping in registry._adapters: @@ -180,8 +201,12 @@ def _check_basic_types_of_adapters(self, registry, expected_order=2): self.assertEqual(len(registry._adapters[expected_order - 1]), 1) def _check_basic_types_of_subscribers(self, registry, expected_order=2): - self.assertEqual(len(registry._subscribers), expected_order) # order 0 and order 1 - self.assertIsInstance(registry._subscribers, self._getMutableListType()) + self.assertEqual( + len(registry._subscribers), expected_order, + ) # order 0 and order 1 + self.assertIsInstance( + registry._subscribers, self._getMutableListType(), + ) MT = self._getMappingType() for mapping in registry._subscribers: self.assertIsInstance(mapping, MT) @@ -191,7 +216,9 @@ def _check_basic_types_of_subscribers(self, registry, expected_order=2): self.assertEqual(len(registry._subscribers[expected_order - 1]), 1) def test_register(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.register([IB0], IR0, '', 'A1') self.assertEqual(registry.registered([IB0], IR0, ''), 'A1') @@ -210,14 +237,16 @@ def test_register(self): registered = list(registry.allRegistrations()) self.assertEqual(registered, [( - (IB0,), # required - IR0, # provided - '', # name - 'A1' # value + (IB0,), # required + IR0, # provided + '', # name + 'A1' # value )]) def test_register_multiple_allRegistrations(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() # Use several different depths and several different names registry.register([], IR0, '', 'A1') @@ -303,10 +332,14 @@ def build_adapters(L, MT): registry._leafSequenceType = CustomLeafSequence registry._sequenceType = CustomSequence registry._providedType = CustomProvided + def addValue(existing, new): - existing = existing if existing is not None else CustomLeafSequence() + existing = ( + existing if existing is not None else CustomLeafSequence() + ) existing.append(new) return existing + registry._addValueToLeaf = addValue registry.rebuild() @@ -318,13 +351,17 @@ def addValue(existing, new): )) def test_register_with_invalid_name(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() with self.assertRaises(ValueError): registry.register([IB0], IR0, object(), 'A1') def test_register_with_value_None_unregisters(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.register([None], IR0, '', 'A1') registry.register([None], IR0, '', None) @@ -335,13 +372,15 @@ def test_register_with_value_None_unregisters(self): def test_register_with_same_value(self): from zope.interface import Interface - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() _value = object() registry.register([None], IR0, '', _value) _before = registry._generation registry.register([None], IR0, '', _value) - self.assertEqual(registry._generation, _before) # skipped changed() + self.assertEqual(registry._generation, _before) # skipped changed() self._check_basic_types_of_adapters(registry) MT = self._getMappingType() self.assertEqual(registry._adapters[1], MT( @@ -355,13 +394,12 @@ def test_register_with_same_value(self): )) registered = list(registry.allRegistrations()) self.assertEqual(registered, [( - (Interface,), # required - IR0, # provided - '', # name - _value # value + (Interface,), # required + IR0, # provided + '', # name + _value # value )]) - def test_registered_empty(self): registry = self._makeOne() self.assertEqual(registry.registered([None], None, ''), None) @@ -369,7 +407,9 @@ def test_registered_empty(self): self.assertEqual(registered, []) def test_registered_non_empty_miss(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.register([IB1], None, '', 'A1') self.assertEqual(registry.registered([IB2], None, ''), None) @@ -381,15 +421,17 @@ def test_registered_non_empty_hit(self): def test_unregister_empty(self): registry = self._makeOne() - registry.unregister([None], None, '') # doesn't raise + registry.unregister([None], None, '') # doesn't raise self.assertEqual(registry.registered([None], None, ''), None) self.assertEqual(len(registry._provided), 0) def test_unregister_non_empty_miss_on_required(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.register([IB1], None, '', 'A1') - registry.unregister([IB2], None, '') # doesn't raise + registry.unregister([IB2], None, '') # doesn't raise self.assertEqual(registry.registered([IB1], None, ''), 'A1') self._check_basic_types_of_adapters(registry) MT = self._getMappingType() @@ -408,10 +450,12 @@ def test_unregister_non_empty_miss_on_required(self): })) def test_unregister_non_empty_miss_on_name(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.register([IB1], None, '', 'A1') - registry.unregister([IB1], None, 'nonesuch') # doesn't raise + registry.unregister([IB1], None, 'nonesuch') # doesn't raise self.assertEqual(registry.registered([IB1], None, ''), 'A1') self._check_basic_types_of_adapters(registry) MT = self._getMappingType() @@ -430,16 +474,20 @@ def test_unregister_non_empty_miss_on_name(self): })) def test_unregister_with_value_not_None_miss(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() orig = object() nomatch = object() registry.register([IB1], None, '', orig) - registry.unregister([IB1], None, '', nomatch) #doesn't raise + registry.unregister([IB1], None, '', nomatch) # doesn't raise self.assertIs(registry.registered([IB1], None, ''), orig) def test_unregister_hit_clears_empty_subcomponents(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() one = object() another = object() @@ -482,12 +530,14 @@ def test_unregister_hit_clears_empty_subcomponents(self): def test_unsubscribe_empty(self): registry = self._makeOne() - registry.unsubscribe([None], None, '') #doesn't raise + registry.unsubscribe([None], None, '') # doesn't raise self.assertEqual(registry.registered([None], None, ''), None) self._check_basic_types_of_subscribers(registry, expected_order=0) def test_unsubscribe_hit(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() orig = object() registry.subscribe([IB1], None, orig) @@ -503,7 +553,7 @@ def test_unsubscribe_hit(self): }) })) self.assertEqual(registry._provided, PT({})) - registry.unsubscribe([IB1], None, orig) #doesn't raise + registry.unsubscribe([IB1], None, orig) # doesn't raise self.assertEqual(len(registry._subscribers), 0) self.assertEqual(registry._provided, PT({})) @@ -513,14 +563,16 @@ def assertLeafIdentity(self, leaf1, leaf2): instead of mutating existing subscriber leaf objects, or vice versa. The default implementation uses immutable tuples, so they are never - the same. Other implementations may use persistent lists so they should be - the same and mutated in place. Subclasses testing this behaviour need to - override this method. + the same. Other implementations may use persistent lists so they + should be the same and mutated in place. Subclasses testing this + behaviour need to override this method. """ self.assertIsNot(leaf1, leaf2) def test_unsubscribe_after_multiple(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() first = object() second = object() @@ -543,8 +595,8 @@ def test_unsubscribe_after_multiple(self): self.assertEqual(registry._provided, PT({ IR0: 2 })) - # The leaf objects may or may not stay the same as they are unsubscribed, - # depending on the implementation + # The leaf objects may or may not stay the same as they are + # unsubscribed, depending on the implementation IR0_leaf_orig = registry._subscribers[1][IB1][IR0][''] Non_leaf_orig = registry._subscribers[1][IB1][None][''] @@ -573,7 +625,9 @@ def test_unsubscribe_after_multiple(self): def test_subscribe_unsubscribe_identical_objects_provided(self): # https://github.com/zopefoundation/zope.interface/issues/227 - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() first = object() registry.subscribe([IB1], IR0, first) @@ -598,7 +652,9 @@ def test_subscribe_unsubscribe_identical_objects_provided(self): def test_subscribe_unsubscribe_nonequal_objects_provided(self): # https://github.com/zopefoundation/zope.interface/issues/227 - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() first = object() second = object() @@ -629,7 +685,9 @@ def test_subscribed_empty(self): self.assertEqual(subscribed, []) def test_subscribed_non_empty_miss(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.subscribe([IB1], IF0, 'A1') # Mismatch required @@ -640,13 +698,17 @@ def test_subscribed_non_empty_miss(self): self.assertIsNone(registry.subscribed([IB1], IF0, '')) def test_subscribed_non_empty_hit(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.subscribe([IB0], IF0, 'A1') self.assertEqual(registry.subscribed([IB0], IF0, 'A1'), 'A1') def test_unsubscribe_w_None_after_multiple(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() first = object() second = object() @@ -658,11 +720,13 @@ def test_unsubscribe_w_None_after_multiple(self): self.assertEqual(len(registry._subscribers), 0) def test_unsubscribe_non_empty_miss_on_required(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.subscribe([IB1], None, 'A1') self._check_basic_types_of_subscribers(registry, expected_order=2) - registry.unsubscribe([IB2], None, '') # doesn't raise + registry.unsubscribe([IB2], None, '') # doesn't raise self.assertEqual(len(registry._subscribers), 2) MT = self._getMappingType() L = self._getLeafSequenceType() @@ -673,11 +737,13 @@ def test_unsubscribe_non_empty_miss_on_required(self): })) def test_unsubscribe_non_empty_miss_on_value(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() registry.subscribe([IB1], None, 'A1') self._check_basic_types_of_subscribers(registry, expected_order=2) - registry.unsubscribe([IB1], None, 'A2') # doesn't raise + registry.unsubscribe([IB1], None, 'A2') # doesn't raise self.assertEqual(len(registry._subscribers), 2) MT = self._getMappingType() L = self._getLeafSequenceType() @@ -688,12 +754,14 @@ def test_unsubscribe_non_empty_miss_on_value(self): })) def test_unsubscribe_with_value_not_None_miss(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() orig = object() nomatch = object() registry.subscribe([IB1], None, orig) - registry.unsubscribe([IB1], None, nomatch) #doesn't raise + registry.unsubscribe([IB1], None, nomatch) # doesn't raise self.assertEqual(len(registry._subscribers), 2) def _instance_method_notify_target(self): @@ -701,7 +769,9 @@ def _instance_method_notify_target(self): def test_unsubscribe_instance_method(self): # Checking that the values are compared by equality, not identity - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() self.assertEqual(len(registry._subscribers), 0) registry.subscribe([IB1], None, self._instance_method_notify_target) @@ -709,7 +779,9 @@ def test_unsubscribe_instance_method(self): self.assertEqual(len(registry._subscribers), 0) def test_subscribe_multiple_allRegistrations(self): - IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1 = _makeInterfaces() # pylint:disable=unused-variable + ( + IB0, IB1, IB2, IB3, IB4, IF0, IF1, IR0, IR1, + ) = _makeInterfaces() # pylint:disable=unused-variable registry = self._makeOne() # Use several different depths and several different values registry.subscribe([], IR0, 'A1') @@ -725,7 +797,6 @@ def test_subscribe_multiple_allRegistrations(self): registry.subscribe([IB0, IB2], IR1, 'A4') registry.subscribe([IB0, IB3], IR1, 'A3') - def build_subscribers(L, F, MT): return L([ # 0 @@ -775,7 +846,6 @@ def build_provided(P): IR1: 4, }) - self.assertEqual(registry._provided, build_provided(P=self._getProvidedType())) @@ -806,10 +876,14 @@ def build_provided(P): registry._leafSequenceType = CustomLeafSequence registry._sequenceType = CustomSequence registry._providedType = CustomProvided + def addValue(existing, new): - existing = existing if existing is not None else CustomLeafSequence() + existing = ( + existing if existing is not None else CustomLeafSequence() + ) existing.append(new) return existing + registry._addValueToLeaf = addValue registry.rebuild() @@ -845,6 +919,7 @@ def _getLeafSequenceType(self): def _getBaseAdapterRegistry(self): from zope.interface.adapter import BaseAdapterRegistry + class CustomAdapterRegistry(BaseAdapterRegistry): _mappingType = self._getMappingType() _sequenceType = self._getMutableListType() @@ -880,33 +955,44 @@ def _getFallbackClass(self): _getTargetClass = _getFallbackClass - def _makeOne(self, uc_lookup=None, uc_lookupAll=None, - uc_subscriptions=None): + def _makeOne( + self, uc_lookup=None, uc_lookupAll=None, uc_subscriptions=None, + ): # pylint:disable=function-redefined if uc_lookup is None: + def uc_lookup(self, required, provided, name): pass + if uc_lookupAll is None: + def uc_lookupAll(self, required, provided): raise NotImplementedError() + if uc_subscriptions is None: + def uc_subscriptions(self, required, provided): raise NotImplementedError() + class Derived(self._getTargetClass()): _uncached_lookup = uc_lookup _uncached_lookupAll = uc_lookupAll _uncached_subscriptions = uc_subscriptions + return Derived() def test_lookup_w_invalid_name(self): + def _lookup(self, required, provided, name): self.fail("This should never be called") + lb = self._makeOne(uc_lookup=_lookup) with self.assertRaises(ValueError): lb.lookup(('A',), 'B', object()) def test_lookup_miss_no_default(self): _called_with = [] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) @@ -918,6 +1004,7 @@ def _lookup(self, required, provided, name): def test_lookup_miss_w_default(self): _called_with = [] _default = object() + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) @@ -930,9 +1017,11 @@ def test_lookup_not_cached(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup(('A',), 'B', 'C') self.assertIs(found, a) @@ -943,9 +1032,11 @@ def test_lookup_cached(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup(('A',), 'B', 'C') found = lb.lookup(('A',), 'B', 'C') @@ -957,9 +1048,11 @@ def test_lookup_not_cached_multi_required(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup(('A', 'D'), 'B', 'C') self.assertIs(found, a) @@ -970,9 +1063,11 @@ def test_lookup_cached_multi_required(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup(('A', 'D'), 'B', 'C') found = lb.lookup(('A', 'D'), 'B', 'C') @@ -984,9 +1079,11 @@ def test_lookup_not_cached_after_changed(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup(('A',), 'B', 'C') lb.changed(lb) @@ -997,6 +1094,7 @@ def _lookup(self, required, provided, name): self.assertEqual(_results, [c]) def test_lookup1_w_invalid_name(self): + def _lookup(self, required, provided, name): self.fail("This should never be called") @@ -1006,6 +1104,7 @@ def _lookup(self, required, provided, name): def test_lookup1_miss_no_default(self): _called_with = [] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) @@ -1017,6 +1116,7 @@ def _lookup(self, required, provided, name): def test_lookup1_miss_w_default(self): _called_with = [] _default = object() + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) @@ -1028,6 +1128,7 @@ def _lookup(self, required, provided, name): def test_lookup1_miss_w_default_negative_cache(self): _called_with = [] _default = object() + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) @@ -1042,9 +1143,11 @@ def test_lookup1_not_cached(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup1('A', 'B', 'C') self.assertIs(found, a) @@ -1055,9 +1158,11 @@ def test_lookup1_cached(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup1('A', 'B', 'C') found = lb.lookup1('A', 'B', 'C') @@ -1069,9 +1174,11 @@ def test_lookup1_not_cached_after_changed(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + lb = self._makeOne(uc_lookup=_lookup) found = lb.lookup1('A', 'B', 'C') lb.changed(lb) @@ -1101,11 +1208,13 @@ def test_adapter_hook_miss_w_default(self): def test_adapter_hook_hit_factory_returns_None(self): _f_called_with = [] + def _factory(context): _f_called_with.append(context) def _lookup(self, required, provided, name): return _factory + req, prv, _default = object(), object(), object() lb = self._makeOne(uc_lookup=_lookup) adapted = lb.adapter_hook(prv, req, 'C', _default) @@ -1115,11 +1224,14 @@ def _lookup(self, required, provided, name): def test_adapter_hook_hit_factory_returns_adapter(self): _f_called_with = [] _adapter = object() + def _factory(context): _f_called_with.append(context) return _adapter + def _lookup(self, required, provided, name): return _factory + req, prv, _default = object(), object(), object() lb = self._makeOne(uc_lookup=_lookup) adapted = lb.adapter_hook(prv, req, 'C', _default) @@ -1128,11 +1240,14 @@ def _lookup(self, required, provided, name): def test_adapter_hook_super_unwraps(self): _f_called_with = [] + def _factory(context): _f_called_with.append(context) return context + def _lookup(self, required, provided, name=''): return _factory + required = super() provided = object() lb = self._makeOne(uc_lookup=_lookup) @@ -1143,11 +1258,14 @@ def _lookup(self, required, provided, name=''): def test_queryAdapter(self): _f_called_with = [] _adapter = object() + def _factory(context): _f_called_with.append(context) return _adapter + def _lookup(self, required, provided, name): return _factory + req, prv, _default = object(), object(), object() lb = self._makeOne(uc_lookup=_lookup) adapted = lb.queryAdapter(req, prv, 'C', _default) @@ -1157,9 +1275,11 @@ def _lookup(self, required, provided, name): def test_lookupAll_uncached(self): _called_with = [] _results = [object(), object(), object()] + def _lookupAll(self, required, provided): _called_with.append((required, provided)) return tuple(_results) + lb = self._makeOne(uc_lookupAll=_lookupAll) found = lb.lookupAll('A', 'B') self.assertEqual(found, tuple(_results)) @@ -1168,9 +1288,11 @@ def _lookupAll(self, required, provided): def test_lookupAll_cached(self): _called_with = [] _results = [object(), object(), object()] + def _lookupAll(self, required, provided): _called_with.append((required, provided)) return tuple(_results) + lb = self._makeOne(uc_lookupAll=_lookupAll) found = lb.lookupAll('A', 'B') found = lb.lookupAll('A', 'B') @@ -1180,9 +1302,11 @@ def _lookupAll(self, required, provided): def test_subscriptions_uncached(self): _called_with = [] _results = [object(), object(), object()] + def _subscriptions(self, required, provided): _called_with.append((required, provided)) return tuple(_results) + lb = self._makeOne(uc_subscriptions=_subscriptions) found = lb.subscriptions('A', 'B') self.assertEqual(found, tuple(_results)) @@ -1191,9 +1315,11 @@ def _subscriptions(self, required, provided): def test_subscriptions_cached(self): _called_with = [] _results = [object(), object(), object()] + def _subscriptions(self, required, provided): _called_with.append((required, provided)) return tuple(_results) + lb = self._makeOne(uc_subscriptions=_subscriptions) found = lb.subscriptions('A', 'B') found = lb.subscriptions('A', 'B') @@ -1221,40 +1347,53 @@ def _makeOne(self, registry, uc_lookup=None, uc_lookupAll=None, uc_subscriptions=None): # pylint:disable=function-redefined if uc_lookup is None: + def uc_lookup(self, required, provided, name): raise NotImplementedError() + if uc_lookupAll is None: + def uc_lookupAll(self, required, provided): raise NotImplementedError() + if uc_subscriptions is None: + def uc_subscriptions(self, required, provided): raise NotImplementedError() + class Derived(self._getTargetClass()): _uncached_lookup = uc_lookup _uncached_lookupAll = uc_lookupAll _uncached_subscriptions = uc_subscriptions + def __init__(self, registry): super().__init__() self._registry = registry + derived = Derived(registry) - derived.changed(derived) # init. '_verify_ro' / '_verify_generations' + derived.changed(derived) # init. '_verify_ro' / '_verify_generations' return derived def _makeRegistry(self, depth): + class WithGeneration: _generation = 1 + class Registry: def __init__(self, depth): self.ro = [WithGeneration() for i in range(depth)] + return Registry(depth) def test_lookup(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_lookup=_lookup) found = lb.lookup(('A',), 'B', 'C') @@ -1273,9 +1412,11 @@ def test_lookup1(self): _called_with = [] a, b, c = object(), object(), object() _results = [a, b, c] + def _lookup(self, required, provided, name): _called_with.append((required, provided, name)) return _results.pop(0) + reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_lookup=_lookup) found = lb.lookup1('A', 'B', 'C') @@ -1291,16 +1432,22 @@ def _lookup(self, required, provided, name): self.assertEqual(_results, [c]) def test_adapter_hook(self): - a, b, _c = [object(), object(), object()] + a, b, _c = [object(), object(), object()] # noqa F841 + def _factory1(context): return a + def _factory2(context): return b + def _factory3(context): self.fail("This should never be called") + _factories = [_factory1, _factory2, _factory3] + def _lookup(self, required, provided, name): return _factories.pop(0) + req, prv, _default = object(), object(), object() reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_lookup=_lookup) @@ -1313,16 +1460,22 @@ def _lookup(self, required, provided, name): self.assertIs(adapted, b) def test_queryAdapter(self): - a, b, _c = [object(), object(), object()] + a, b, _c = [object(), object(), object()] # noqa F841 + def _factory1(context): return a + def _factory2(context): return b + def _factory3(context): self.fail("This should never be called") + _factories = [_factory1, _factory2, _factory3] + def _lookup(self, required, provided, name): return _factories.pop(0) + req, prv, _default = object(), object(), object() reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_lookup=_lookup) @@ -1338,8 +1491,10 @@ def test_lookupAll(self): _results_1 = [object(), object(), object()] _results_2 = [object(), object(), object()] _results = [_results_1, _results_2] + def _lookupAll(self, required, provided): return tuple(_results.pop(0)) + reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_lookupAll=_lookupAll) found = lb.lookupAll('A', 'B') @@ -1354,8 +1509,10 @@ def test_subscriptions(self): _results_1 = [object(), object(), object()] _results_2 = [object(), object(), object()] _results = [_results_1, _results_2] + def _subscriptions(self, required, provided): return tuple(_results.pop(0)) + reg = self._makeRegistry(3) lb = self._makeOne(reg, uc_subscriptions=_subscriptions) found = lb.subscriptions('A', 'B') @@ -1385,17 +1542,21 @@ def _makeOne(self, registry): return self._getTargetClass()(registry) def _makeSubregistry(self, *provided): + class Subregistry: def __init__(self): self._adapters = [] self._subscribers = [] + return Subregistry() def _makeRegistry(self, *provided): + class Registry: def __init__(self, provided): self._provided = provided self.ro = [] + return Registry(provided) def test_ctor_empty_registry(self): @@ -1419,30 +1580,40 @@ def test_ctor_w_registry_provided(self): def test_changed_empty_required(self): # ALB.changed expects to call a mixed in changed. + class Mixin: def changed(self, *other): pass + class Derived(self._getTargetClass(), Mixin): pass + registry = self._makeRegistry() alb = Derived(registry) alb.changed(alb) def test_changed_w_required(self): # ALB.changed expects to call a mixed in changed. + class Mixin: def changed(self, *other): pass + class Derived(self._getTargetClass(), Mixin): pass + class FauxWeakref: _unsub = None + def __init__(self, here): self._here = here + def __call__(self): return self if self._here else None + def unsubscribe(self, target): self._unsub = target + gone = FauxWeakref(False) here = FauxWeakref(True) registry = self._makeRegistry() @@ -1531,7 +1702,7 @@ def test__uncached_lookup_extendors_miss(self): IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() - subr._adapters = [{}, {}] #utilities, single adapters + subr._adapters = [{}, {}] # utilities, single adapters registry.ro.append(subr) alb = self._makeOne(registry) subr._v_lookup = alb @@ -1546,10 +1717,13 @@ def test__uncached_lookup_components_miss_wrong_iface(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() irrelevant = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, - {IFoo: {IQux: {'': irrelevant}, - }}, + { + IFoo: { + IQux: {'': irrelevant}, + }, + }, ] registry.ro.append(subr) alb = self._makeOne(registry) @@ -1565,10 +1739,13 @@ def test__uncached_lookup_components_miss_wrong_name(self): subr = self._makeSubregistry() wrongname = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, - {IFoo: {IBar: {'wrongname': wrongname}, - }}, + { + IFoo: { + IBar: {'wrongname': wrongname}, + }, + }, ] registry.ro.append(subr) alb = self._makeOne(registry) @@ -1583,7 +1760,7 @@ def test__uncached_lookup_simple_hit(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _expected}}}, ] @@ -1600,7 +1777,7 @@ def test__uncached_lookup_repeated_hit(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _expected}}}, ] @@ -1617,27 +1794,30 @@ def test_queryMultiAdaptor_lookup_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) + @implementer(IFoo) class Foo: pass + foo = Foo() registry = self._makeRegistry() subr = self._makeSubregistry() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {}, ] registry.ro.append(subr) alb = self._makeOne(registry) - alb.lookup = alb._uncached_lookup # provided by derived + alb.lookup = alb._uncached_lookup # provided by derived subr._v_lookup = alb _default = object() result = alb.queryMultiAdapter((foo,), IBar, default=_default) self.assertIs(result, _default) def test_queryMultiAdapter_errors_on_attribute_access(self): - # Any error on attribute access previously lead to using the _empty singleton as "requires" - # argument (See https://github.com/zopefoundation/zope.interface/issues/162) + # Any error on attribute access previously lead to using the _empty + # singleton as "requires" argument (See + # https://github.com/zopefoundation/zope.interface/issues/162) # but after https://github.com/zopefoundation/zope.interface/issues/200 # they get propagated. from zope.interface.interface import InterfaceClass @@ -1661,24 +1841,26 @@ def test_queryMultiAdaptor_factory_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) + @implementer(IFoo) class Foo: pass + foo = Foo() registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() - _expected = object() _called_with = [] + def _factory(context): _called_with.append(context) - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _factory}}}, ] registry.ro.append(subr) alb = self._makeOne(registry) - alb.lookup = alb._uncached_lookup # provided by derived + alb.lookup = alb._uncached_lookup # provided by derived subr._v_lookup = alb _default = object() result = alb.queryMultiAdapter((foo,), IBar, default=_default) @@ -1690,24 +1872,28 @@ def test_queryMultiAdaptor_factory_hit(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) + @implementer(IFoo) class Foo: pass + foo = Foo() registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() _called_with = [] + def _factory(context): _called_with.append(context) return _expected - subr._adapters = [ #utilities, single adapters + + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _factory}}}, ] registry.ro.append(subr) alb = self._makeOne(registry) - alb.lookup = alb._uncached_lookup # provided by derived + alb.lookup = alb._uncached_lookup # provided by derived subr._v_lookup = alb _default = object() result = alb.queryMultiAdapter((foo,), IBar, default=_default) @@ -1716,10 +1902,13 @@ def _factory(context): def test_queryMultiAdapter_super_unwraps(self): alb = self._makeOne(self._makeRegistry()) + def lookup(*args): return factory + def factory(*args): return args + alb.lookup = lookup objects = [ @@ -1766,7 +1955,7 @@ def test__uncached_lookupAll_extendors_miss(self): IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() - subr._adapters = [{}, {}] #utilities, single adapters + subr._adapters = [{}, {}] # utilities, single adapters registry.ro.append(subr) alb = self._makeOne(registry) subr._v_lookup = alb @@ -1781,7 +1970,7 @@ def test__uncached_lookupAll_components_miss(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() irrelevant = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IQux: {'': irrelevant}}}, ] @@ -1799,7 +1988,7 @@ def test__uncached_lookupAll_simple_hit(self): subr = self._makeSubregistry() _expected = object() _named = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _expected, 'named': _named}}}, ] @@ -1817,7 +2006,7 @@ def test_names(self): subr = self._makeSubregistry() _expected = object() _named = object() - subr._adapters = [ #utilities, single adapters + subr._adapters = [ # utilities, single adapters {}, {IFoo: {IBar: {'': _expected, 'named': _named}}}, ] @@ -1857,7 +2046,7 @@ def test__uncached_subscriptions_extendors_miss(self): IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() - subr._subscribers = [{}, {}] #utilities, single adapters + subr._subscribers = [{}, {}] # utilities, single adapters registry.ro.append(subr) alb = self._makeOne(registry) subr._v_lookup = alb @@ -1872,7 +2061,7 @@ def test__uncached_subscriptions_components_miss_wrong_iface(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() irrelevant = object() - subr._subscribers = [ #utilities, single adapters + subr._subscribers = [ # utilities, single adapters {}, {IFoo: {IQux: {'': irrelevant}}}, ] @@ -1889,7 +2078,7 @@ def test__uncached_subscriptions_components_miss_wrong_name(self): registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() wrongname = object() - subr._subscribers = [ #utilities, single adapters + subr._subscribers = [ # utilities, single adapters {}, {IFoo: {IBar: {'wrongname': wrongname}}}, ] @@ -1905,11 +2094,14 @@ def test__uncached_subscriptions_simple_hit(self): IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() + class Foo: + def __lt__(self, other): return True + _exp1, _exp2 = Foo(), Foo() - subr._subscribers = [ #utilities, single adapters + subr._subscribers = [ # utilities, single adapters {}, {IFoo: {IBar: {'': (_exp1, _exp2)}}}, ] @@ -1924,19 +2116,24 @@ def test_subscribers_wo_provided(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) + @implementer(IFoo) class Foo: pass + foo = Foo() registry = self._makeRegistry(IFoo, IBar) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _called = {} + def _factory1(context): _called.setdefault('_factory1', []).append(context) + def _factory2(context): _called.setdefault('_factory2', []).append(context) - subr._subscribers = [ #utilities, single adapters + + subr._subscribers = [ # utilities, single adapters {}, {IFoo: {None: {'': (_factory1, _factory2)}}}, ] @@ -1953,25 +2150,30 @@ def test_subscribers_w_provided(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) + @implementer(IFoo) class Foo: pass + foo = Foo() registry = self._makeRegistry(IFoo, IBar) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _called = {} _exp1, _exp2 = object(), object() + def _factory1(context): _called.setdefault('_factory1', []).append(context) return _exp1 + def _factory2(context): _called.setdefault('_factory2', []).append(context) return _exp2 + def _side_effect_only(context): _called.setdefault('_side_effect_only', []).append(context) - subr._subscribers = [ #utilities, single adapters + subr._subscribers = [ # utilities, single adapters {}, {IFoo: {IBar: {'': (_factory1, _factory2, _side_effect_only)}}}, ] @@ -1981,11 +2183,13 @@ def _side_effect_only(context): subr._v_lookup = alb result = alb.subscribers((foo,), IBar) self.assertEqual(result, [_exp1, _exp2]) - self.assertEqual(_called, - {'_factory1': [foo], - '_factory2': [foo], - '_side_effect_only': [foo], - }) + self.assertEqual( + _called, { + '_factory1': [foo], + '_factory2': [foo], + '_side_effect_only': [foo], + } + ) class VerifyingAdapterRegistryTests(unittest.TestCase): @@ -2060,10 +2264,13 @@ def test__setBases_w_existing_entry_continuing(self): def test_changed_w_subregistries(self): base = self._makeOne() + class Derived: _changed = None + def changed(self, originally_changed): self._changed = originally_changed + derived1, derived2 = Derived(), Derived() base._addSubregistry(derived1) base._addSubregistry(derived2) diff --git a/src/zope/interface/tests/test_advice.py b/src/zope/interface/tests/test_advice.py index d5582acf..4d484e04 100644 --- a/src/zope/interface/tests/test_advice.py +++ b/src/zope/interface/tests/test_advice.py @@ -78,6 +78,7 @@ def test_inside_exec(self): kind, module, f_locals, f_globals = getFrameInfo(sys._getframe()) """ + class Test_isClassAdvisor(unittest.TestCase): def _callFUT(self, *args, **kw): @@ -88,13 +89,17 @@ 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) @@ -106,24 +111,31 @@ def _callFUT(self, *args, **kw): 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 @@ -138,8 +150,8 @@ class B(type, metaclass=Meta_B): self.assertEqual(self._callFUT((A, B)), Meta_B) - def test_multiple_not_in_hierarchy_py3k(self): + class Meta_A(type): pass @@ -168,19 +180,26 @@ 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]) @@ -188,8 +207,11 @@ class D: 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]) diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py index a7f85463..a19a9805 100644 --- a/src/zope/interface/tests/test_declarations.py +++ b/src/zope/interface/tests/test_declarations.py @@ -26,12 +26,12 @@ class _Py3ClassAdvice: - def _run_generated_code(self, code, globs, locs, - fails_under_py3k=True, - ): + def _run_generated_code( + self, code, globs, locs, fails_under_py3k=True, + ): # pylint:disable=exec-used,no-member import warnings - with warnings.catch_warnings(record=True) as log: + with warnings.catch_warnings(record=True) as _: warnings.resetwarnings() try: @@ -53,7 +53,9 @@ def test_class(self): class Foo: pass - self.assertEqual(Foo.__component_name__, 'foo') # pylint:disable=no-member + self.assertEqual( + Foo.__component_name__, 'foo' + ) # pylint:disable=no-member def test_function(self): from zope.interface.declarations import named @@ -72,7 +74,9 @@ class Foo: foo = Foo() named('foo')(foo) - self.assertEqual(foo.__component_name__, 'foo') # pylint:disable=no-member + self.assertEqual( + foo.__component_name__, 'foo' + ) # pylint:disable=no-member class EmptyDeclarationTests(unittest.TestCase): @@ -105,8 +109,8 @@ def test_extends_empty(self): def test_interfaces_empty(self): decl = self._getEmpty() - l = list(decl.interfaces()) - self.assertEqual(l, []) + iface_list = list(decl.interfaces()) + self.assertEqual(iface_list, []) def test___sro___(self): from zope.interface.interface import Interface @@ -160,7 +164,7 @@ def test_ctor_w_implements_in_bases(self): def test_changed_wo_existing__v_attrs(self): decl = self._makeOne() - decl.changed(decl) # doesn't raise + decl.changed(decl) # doesn't raise self.assertIsNone(decl._v_attrs) def test___contains__w_self(self): @@ -197,7 +201,7 @@ def test___iter___inheritance(self): IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar', (IFoo,)) decl = self._makeOne(IBar) - self.assertEqual(list(decl), [IBar]) #IBar.interfaces() omits bases + self.assertEqual(list(decl), [IBar]) # IBar.interfaces() omits bases def test___iter___w_nested_sequence_overlap(self): from zope.interface.interface import InterfaceClass @@ -415,6 +419,7 @@ def _makeOne(self, *args, **kw): def _makeOneToCompare(self): from zope.interface.declarations import implementedBy + class A: pass @@ -439,17 +444,22 @@ def test___reduce__(self): def test_sort(self): from zope.interface.declarations import implementedBy + from zope.interface.interface import InterfaceClass + class A: pass + class B: pass - from zope.interface.interface import InterfaceClass + IFoo = InterfaceClass('IFoo') self.assertEqual(implementedBy(A), implementedBy(A)) self.assertEqual(hash(implementedBy(A)), hash(implementedBy(A))) self.assertTrue(implementedBy(A) < None) - self.assertTrue(None > implementedBy(A)) # pylint:disable=misplaced-comparison-constant + self.assertTrue( + None > implementedBy(A) + ) # pylint:disable=misplaced-comparison-constant self.assertTrue(implementedBy(A) < implementedBy(B)) self.assertTrue(implementedBy(A) > IFoo) self.assertTrue(implementedBy(A) <= implementedBy(B)) @@ -458,6 +468,8 @@ class B: def test_proxy_equality(self): # https://github.com/zopefoundation/zope.interface/issues/55 + from zope.interface.declarations import implementedBy + class Proxy: def __init__(self, wrapped): self._wrapped = wrapped @@ -471,7 +483,6 @@ def __eq__(self, other): def __ne__(self, other): return self._wrapped != other - from zope.interface.declarations import implementedBy class A: pass @@ -484,7 +495,9 @@ class B: # The order of arguments to the operators matters, # test both - self.assertTrue(implementedByA == implementedByA) # pylint:disable=comparison-with-itself + self.assertTrue( + implementedByA == implementedByA + ) # pylint:disable=comparison-with-itself self.assertTrue(implementedByA != implementedByB) self.assertTrue(implementedByB != implementedByA) @@ -538,22 +551,29 @@ class Foo: self.assertEqual(list(self._callFUT(foo)), []) def test_dictless_wo_existing_Implements_cant_assign___implemented__(self): + class Foo: def _get_impl(self): raise NotImplementedError() + def _set_impl(self, val): raise TypeError + __implemented__ = property(_get_impl, _set_impl) + def __call__(self): # act like a factory raise NotImplementedError() + foo = Foo() self.assertRaises(TypeError, self._callFUT, foo) def test_dictless_wo_existing_Implements_w_registrations(self): from zope.interface import declarations + class Foo: __slots__ = ('__implemented__',) + foo = Foo() foo.__implemented__ = None reg = object() @@ -565,16 +585,20 @@ class Foo: def test_dictless_w_existing_Implements(self): from zope.interface.declarations import Implements impl = Implements() + class Foo: __slots__ = ('__implemented__',) + foo = Foo() foo.__implemented__ = impl self.assertTrue(self._callFUT(foo) is impl) def test_dictless_w_existing_not_Implements(self): from zope.interface.interface import InterfaceClass + class Foo: __slots__ = ('__implemented__',) + foo = Foo() IFoo = InterfaceClass('IFoo') foo.__implemented__ = (IFoo,) @@ -583,8 +607,10 @@ class Foo: def test_w_existing_attr_as_Implements(self): from zope.interface.declarations import Implements impl = Implements() + class Foo: __implemented__ = impl + self.assertTrue(self._callFUT(Foo) is impl) def test_builtins_added_to_cache(self): @@ -616,26 +642,34 @@ def test_builtins_w_existing_cache(self): def test_oldstyle_class_no_assertions(self): # TODO: Figure out P3 story + class Foo: pass + self.assertEqual(list(self._callFUT(Foo)), []) def test_no_assertions(self): # TODO: Figure out P3 story + class Foo: pass + self.assertEqual(list(self._callFUT(Foo)), []) def test_w_None_no_bases_not_factory(self): + class Foo: __implemented__ = None + foo = Foo() self.assertRaises(TypeError, self._callFUT, foo) def test_w_None_no_bases_w_factory(self): from zope.interface.declarations import objectSpecificationDescriptor + class Foo: __implemented__ = None + def __call__(self): raise NotImplementedError() @@ -646,27 +680,39 @@ def __call__(self): 'zope.interface.tests.test_declarations.foo') self.assertIs(spec.inherit, foo) self.assertIs(foo.__implemented__, spec) - self.assertIs(foo.__providedBy__, objectSpecificationDescriptor) # pylint:disable=no-member + self.assertIs( + foo.__providedBy__, objectSpecificationDescriptor + ) # pylint:disable=no-member self.assertNotIn('__provides__', foo.__dict__) def test_w_None_no_bases_w_class(self): from zope.interface.declarations import ClassProvides + class Foo: __implemented__ = None + spec = self._callFUT(Foo) self.assertEqual(spec.__name__, 'zope.interface.tests.test_declarations.Foo') self.assertIs(spec.inherit, Foo) self.assertIs(Foo.__implemented__, spec) - self.assertIsInstance(Foo.__providedBy__, ClassProvides) # pylint:disable=no-member - self.assertIsInstance(Foo.__provides__, ClassProvides) # pylint:disable=no-member - self.assertEqual(Foo.__provides__, Foo.__providedBy__) # pylint:disable=no-member + self.assertIsInstance( + Foo.__providedBy__, ClassProvides + ) # pylint:disable=no-member + self.assertIsInstance( + Foo.__provides__, ClassProvides + ) # pylint:disable=no-member + self.assertEqual( + Foo.__provides__, Foo.__providedBy__ + ) # pylint:disable=no-member def test_w_existing_Implements(self): from zope.interface.declarations import Implements impl = Implements() + class Foo: __implemented__ = impl + self.assertTrue(self._callFUT(Foo) is impl) def test_super_when_base_implements_interface(self): @@ -729,7 +775,6 @@ class IBase(Interface): class IDerived(IBase): pass - class Base: pass @@ -744,7 +789,9 @@ class Child2(Base): class Derived(Child1, Child2): pass - self.assertEqual(Derived.__mro__, (Derived, Child1, Child2, Base, object)) + self.assertEqual( + Derived.__mro__, (Derived, Child1, Child2, Base, object) + ) self.assertEqual(list(self._callFUT(Derived)), [IDerived, IBase]) sup = super(Derived, Derived) fut = self._callFUT(sup) @@ -791,6 +838,7 @@ class Derived: sup = super(Derived, Derived) self.assertEqual(list(self._callFUT(sup)), []) + def test_super_multi_level_multi_inheritance(self): from zope.interface import Interface from zope.interface.declarations import implementer @@ -885,10 +933,13 @@ def _check_implementer(self, Foo, return Foo, IFoo def test_class(self): + class Foo: pass + self._check_implementer(Foo) + class Test_classImplementsOnly(_ImplementsTestMixin, unittest.TestCase): FUT_SETS_PROVIDED_BY = False @@ -904,8 +955,10 @@ def test_w_existing_Implements(self): IBar = InterfaceClass('IBar') impl = Implements(IFoo) impl.declared = (IFoo,) + class Foo: __implemented__ = impl + impl.inherit = Foo self._callFUT(Foo, IBar) # Same spec, now different values @@ -921,8 +974,8 @@ def test_class(self): class Foo: __implemented__ = old_spec - self._check_implementer(Foo, old_spec, '?', inherit=None) + self._check_implementer(Foo, old_spec, '?', inherit=None) def test_redundant_with_super_still_implements(self): Base, IBase = self._check_implementer( @@ -941,13 +994,15 @@ class Test_classImplements(_ImplementsTestMixin, unittest.TestCase): def _callFUT(self, cls, iface): from zope.interface.declarations import classImplements - result = classImplements(cls, iface) # pylint:disable=assignment-from-no-return + result = classImplements( + cls, iface + ) # pylint:disable=assignment-from-no-return self.assertIsNone(result) return cls def __check_implementer_redundant(self, Base): - # If we @implementer exactly what was already present, we write - # no declared attributes on the parent (we still set everything, though) + # If we @implementer exactly what was already present, we write no + # declared attributes on the parent (we still set everything, though) Base, IBase = self._check_implementer(Base) class Child(Base): @@ -965,8 +1020,10 @@ class Child(Base): self.assertTrue(IBase.providedBy(Child())) def test_redundant_implementer_empty_class_declarations(self): + class Foo: pass + self.__check_implementer_redundant(Foo) def test_redundant_implementer_Interface(self): @@ -998,8 +1055,10 @@ def test_w_existing_Implements(self): IBar = InterfaceClass('IBar') impl = Implements(IFoo) impl.declared = (IFoo,) + class Foo: __implemented__ = impl + impl.inherit = Foo self._callFUT(Foo, IBar) # Same spec, now different values @@ -1020,13 +1079,16 @@ def test_w_existing_Implements_w_bases(self): class Root1: __implemented__ = impl_root + class Root2: __implemented__ = impl_root impl_extends_root = Implements.named('ExtendsRoot1', IExtendsRoot) impl_extends_root.declared = (IExtendsRoot,) + class ExtendsRoot(Root1, Root2): __implemented__ = impl_extends_root + impl_extends_root.inherit = ExtendsRoot self._callFUT(ExtendsRoot, ISecondRoot) @@ -1035,15 +1097,19 @@ class ExtendsRoot(Root1, Root2): self.assertEqual(impl_extends_root.inherit, ExtendsRoot) self.assertEqual(impl_extends_root.declared, self._order_for_two(IExtendsRoot, ISecondRoot,)) - self.assertEqual(impl_extends_root.__bases__, - self._order_for_two(IExtendsRoot, ISecondRoot) + (impl_root,)) + self.assertEqual( + impl_extends_root.__bases__, + self._order_for_two(IExtendsRoot, ISecondRoot) + (impl_root,) + ) class Test_classImplementsFirst(Test_classImplements): def _callFUT(self, cls, iface): from zope.interface.declarations import classImplementsFirst - result = classImplementsFirst(cls, iface) # pylint:disable=assignment-from-no-return + result = classImplementsFirst( + cls, iface + ) # pylint:disable=assignment-from-no-return self.assertIsNone(result) return cls @@ -1062,12 +1128,18 @@ def test_no_existing_implements(self): from zope.interface.declarations import classImplements from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') + class Foo: __implements_advice_data__ = ((IFoo,), classImplements) + self._callFUT(Foo) self.assertNotIn('__implements_advice_data__', Foo.__dict__) - self.assertIsInstance(Foo.__implemented__, Implements) # pylint:disable=no-member - self.assertEqual(list(Foo.__implemented__), [IFoo]) # pylint:disable=no-member + self.assertIsInstance( + Foo.__implemented__, Implements + ) # pylint:disable=no-member + self.assertEqual( + list(Foo.__implemented__), [IFoo] + ) # pylint:disable=no-member class Test_implementer(Test_classImplements): @@ -1092,16 +1164,20 @@ def test_nonclass_cannot_assign_attr(self): def test_nonclass_can_assign_attr(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') + class Foo: pass + foo = Foo() decorator = self._makeOne(IFoo) returned = decorator(foo) self.assertTrue(returned is foo) - spec = foo.__implemented__ # pylint:disable=no-member - self.assertEqual(spec.__name__, 'zope.interface.tests.test_declarations.?') + spec = foo.__implemented__ # pylint:disable=no-member + self.assertEqual( + spec.__name__, 'zope.interface.tests.test_declarations.?' + ) self.assertIsNone(spec.inherit,) - self.assertIs(foo.__implemented__, spec) # pylint:disable=no-member + self.assertIs(foo.__implemented__, spec) # pylint:disable=no-member def test_does_not_leak_on_unique_classes(self): # Make sure nothing is hanging on to the class or Implements @@ -1134,7 +1210,6 @@ class TestClass: self.assertLessEqual(end_count, begin_count + fudge_factor) - class Test_implementer_only(Test_classImplementsOnly): def _getTargetClass(self): @@ -1152,21 +1227,22 @@ def test_function(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') decorator = self._makeOne(IFoo) + def _function(): raise NotImplementedError() + self.assertRaises(ValueError, decorator, _function) def test_method(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') decorator = self._makeOne(IFoo) + class Bar: def _method(self): raise NotImplementedError() - self.assertRaises(ValueError, decorator, Bar._method) - - + self.assertRaises(ValueError, decorator, Bar._method) class ProvidesClassTests(unittest.TestCase): @@ -1181,8 +1257,10 @@ def _makeOne(self, *args, **kw): def test_simple_class_one_interface(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + spec = self._makeOne(Foo, IFoo) self.assertEqual(list(spec), [IFoo]) @@ -1190,8 +1268,10 @@ def test___reduce__(self): from zope.interface.declarations import Provides # the function from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + spec = self._makeOne(Foo, IFoo) klass, args = spec.__reduce__() self.assertIs(klass, Provides) @@ -1200,8 +1280,10 @@ class Foo: def test___get___class(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + spec = self._makeOne(Foo, IFoo) Foo.__provides__ = spec self.assertIs(Foo.__provides__, spec) @@ -1209,13 +1291,17 @@ class Foo: def test___get___instance(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + spec = self._makeOne(Foo, IFoo) Foo.__provides__ = spec + def _test(): foo = Foo() return foo.__provides__ + self.assertRaises(AttributeError, _test) @@ -1224,9 +1310,13 @@ class ProvidesClassStrictTests(ProvidesClassTests): def _getTargetClass(self): ProvidesClass = super()._getTargetClass() + class StrictProvides(ProvidesClass): def _do_calculate_ro(self, base_mros): - return ProvidesClass._do_calculate_ro(self, base_mros=base_mros, strict=True) + return ProvidesClass._do_calculate_ro( + self, base_mros=base_mros, strict=True, + ) + return StrictProvides def test_overlapping_interfaces_corrected(self): @@ -1281,10 +1371,12 @@ def test__repr__module_provides_typical_use(self): # as created through a ``moduleProvides()`` statement # in a module body from zope.interface.tests import dummy - provides = dummy.__provides__ # pylint:disable=no-member + provides = dummy.__provides__ # pylint:disable=no-member self.assertEqual( repr(provides), - "directlyProvides(sys.modules['zope.interface.tests.dummy'], IDummyModule)" + "directlyProvides(" + "sys.modules['zope.interface.tests.dummy'], " + "IDummyModule)" ) def test__repr__module_after_pickle(self): @@ -1292,7 +1384,7 @@ def test__repr__module_after_pickle(self): import pickle from zope.interface.tests import dummy - provides = dummy.__provides__ # pylint:disable=no-member + provides = dummy.__provides__ # pylint:disable=no-member for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(pickle.PicklingError): pickle.dumps(provides, proto) @@ -1308,12 +1400,12 @@ def test__repr__directlyProvides_module(self): IFoo = InterfaceClass('IFoo') IBar = InterfaceClass('IBar') - orig_provides = dummy.__provides__ # pylint:disable=no-member - del dummy.__provides__ # pylint:disable=no-member + orig_provides = dummy.__provides__ # pylint:disable=no-member + del dummy.__provides__ # pylint:disable=no-member self.addCleanup(setattr, dummy, '__provides__', orig_provides) directlyProvides(dummy, IFoo) - provides = dummy.__provides__ # pylint:disable=no-member + provides = dummy.__provides__ # pylint:disable=no-member self.assertEqual( repr(provides), @@ -1321,11 +1413,13 @@ def test__repr__directlyProvides_module(self): ) alsoProvides(dummy, IBar) - provides = dummy.__provides__ # pylint:disable=no-member + provides = dummy.__provides__ # pylint:disable=no-member self.assertEqual( repr(provides), - "directlyProvides(sys.modules['zope.interface.tests.dummy'], IFoo, IBar)" + "directlyProvides(" + "sys.modules['zope.interface.tests.dummy'], " + "IFoo, IBar)" ) # If we make this module also provide IFoo and IBar, then the repr @@ -1371,6 +1465,7 @@ def test__repr__duplicate_names(self): def test__repr__implementedBy_in_interfaces(self): from zope.interface import Interface from zope.interface import implementedBy + class IFoo(Interface): "Does nothing" @@ -1382,7 +1477,9 @@ class Bar: inst = self._makeOne(Bar, IFoo, impl) self.assertEqual( repr(inst), - 'directlyProvides(Bar, IFoo, classImplements(TestProvidesClassRepr))' + 'directlyProvides(' + 'Bar, IFoo, ' + 'classImplements(TestProvidesClassRepr))' ) def test__repr__empty_interfaces(self): @@ -1393,12 +1490,17 @@ def test__repr__empty_interfaces(self): ) def test__repr__non_class(self): + + def str___dont_call_me(): + self.fail("Should not call str") + class Object: __bases__ = () - __str__ = lambda _: self.fail("Should not call str") + __str__ = str___dont_call_me def __repr__(self): return '' + inst = self._makeOne(Object()) self.assertEqual( repr(inst), @@ -1443,7 +1545,6 @@ class Foo: ) - class Test_Provides(unittest.TestCase): def _callFUT(self, *args, **kw): @@ -1455,8 +1556,10 @@ def test_no_cached_spec(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") cache = {} + class Foo: pass + with _Monkey(declarations, InstanceDeclarations=cache): spec = self._callFUT(Foo, IFoo) self.assertEqual(list(spec), [IFoo]) @@ -1467,8 +1570,10 @@ def test_w_cached_spec(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") prior = object() + class Foo: pass + cache = {(Foo, IFoo): prior} with _Monkey(declarations, InstanceDeclarations=cache): spec = self._callFUT(Foo, IFoo) @@ -1485,36 +1590,51 @@ def test_w_normal_object(self): from zope.interface.declarations import ProvidesClass from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + obj = Foo() self._callFUT(obj, IFoo) - self.assertIsInstance(obj.__provides__, ProvidesClass) # pylint:disable=no-member - self.assertEqual(list(obj.__provides__), [IFoo]) # pylint:disable=no-member + self.assertIsInstance( + obj.__provides__, ProvidesClass + ) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [IFoo] + ) # pylint:disable=no-member def test_w_class(self): from zope.interface.declarations import ClassProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + self._callFUT(Foo, IFoo) - self.assertIsInstance(Foo.__provides__, ClassProvides) # pylint:disable=no-member - self.assertEqual(list(Foo.__provides__), [IFoo]) # pylint:disable=no-member + self.assertIsInstance( + Foo.__provides__, ClassProvides + ) # pylint:disable=no-member + self.assertEqual( + list(Foo.__provides__), [IFoo] + ) # pylint:disable=no-member def test_w_classless_object(self): from zope.interface.declarations import ProvidesClass from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") the_dict = {} + class Foo: def __getattribute__(self, name): # Emulate object w/o any class if name == '__class__': return None raise NotImplementedError(name) + def __setattr__(self, name, value): the_dict[name] = value + obj = Foo() self._callFUT(obj, IFoo) self.assertIsInstance(the_dict['__provides__'], ProvidesClass) @@ -1531,12 +1651,18 @@ def test_wo_existing_provides(self): from zope.interface.declarations import ProvidesClass from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + obj = Foo() self._callFUT(obj, IFoo) - self.assertIsInstance(obj.__provides__, ProvidesClass) # pylint:disable=no-member - self.assertEqual(list(obj.__provides__), [IFoo]) # pylint:disable=no-member + self.assertIsInstance( + obj.__provides__, ProvidesClass + ) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [IFoo] + ) # pylint:disable=no-member def test_w_existing_provides(self): from zope.interface.declarations import ProvidesClass @@ -1544,13 +1670,19 @@ def test_w_existing_provides(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + class Foo: pass + obj = Foo() directlyProvides(obj, IFoo) self._callFUT(obj, IBar) - self.assertIsInstance(obj.__provides__, ProvidesClass) # pylint:disable=no-member - self.assertEqual(list(obj.__provides__), [IFoo, IBar]) # pylint:disable=no-member + self.assertIsInstance( + obj.__provides__, ProvidesClass + ) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [IFoo, IBar] + ) # pylint:disable=no-member class Test_noLongerProvides(unittest.TestCase): @@ -1562,42 +1694,56 @@ def _callFUT(self, *args, **kw): def test_wo_existing_provides(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + obj = Foo() self._callFUT(obj, IFoo) - self.assertEqual(list(obj.__provides__), []) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [] + ) # pylint:disable=no-member def test_w_existing_provides_hit(self): from zope.interface.declarations import directlyProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + obj = Foo() directlyProvides(obj, IFoo) self._callFUT(obj, IFoo) - self.assertEqual(list(obj.__provides__), []) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [] + ) # pylint:disable=no-member def test_w_existing_provides_miss(self): from zope.interface.declarations import directlyProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + class Foo: pass + obj = Foo() directlyProvides(obj, IFoo) self._callFUT(obj, IBar) - self.assertEqual(list(obj.__provides__), [IFoo]) # pylint:disable=no-member + self.assertEqual( + list(obj.__provides__), [IFoo] + ) # pylint:disable=no-member def test_w_iface_implemented_by_class(self): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @implementer(IFoo) class Foo: pass + obj = Foo() self.assertRaises(ValueError, self._callFUT, obj, IFoo) @@ -1612,25 +1758,31 @@ def _getTargetClass(self): def _makeOne(self, klass, implements): # Don't instantiate directly: the C version can't have attributes # assigned. + class Derived(self._getTargetClass()): def __init__(self, k, i): self._cls = k self._implements = i + return Derived(klass, implements) def test_w_same_class_via_class(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + cpbp = Foo.__provides__ = self._makeOne(Foo, IFoo) self.assertTrue(Foo.__provides__ is cpbp) def test_w_same_class_via_instance(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + foo = Foo() Foo.__provides__ = self._makeOne(Foo, IFoo) self.assertIs(foo.__provides__, IFoo) @@ -1638,10 +1790,13 @@ class Foo: def test_w_different_class(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + class Bar(Foo): pass + bar = Bar() Foo.__provides__ = self._makeOne(Foo, IFoo) self.assertRaises(AttributeError, getattr, Bar, '__provides__') @@ -1676,9 +1831,11 @@ def test_w_simple_metaclass(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + @implementer(IFoo) class Foo: pass + cp = Foo.__provides__ = self._makeOne(Foo, type(Foo), IBar) self.assertTrue(Foo.__provides__ is cp) self.assertEqual(list(Foo().__provides__), [IFoo]) @@ -1688,9 +1845,11 @@ def test___reduce__(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + @implementer(IFoo) class Foo: pass + cp = Foo.__provides__ = self._makeOne(Foo, type(Foo), IBar) self.assertEqual(cp.__reduce__(), (type(cp), (Foo, type(Foo), IBar))) @@ -1701,9 +1860,13 @@ class ClassProvidesStrictTests(ClassProvidesTests): def _getTargetClass(self): ClassProvides = super()._getTargetClass() + class StrictClassProvides(ClassProvides): def _do_calculate_ro(self, base_mros): - return ClassProvides._do_calculate_ro(self, base_mros=base_mros, strict=True) + return ClassProvides._do_calculate_ro( + self, base_mros=base_mros, strict=True + ) + return StrictClassProvides def test_overlapping_interfaces_corrected(self): @@ -1755,6 +1918,7 @@ def test__repr__empty(self): def test__repr__providing_one(self): from zope.interface import Interface + class IFoo(Interface): "Does nothing" @@ -1823,8 +1987,10 @@ def _callFUT(self, *args, **kw): return directlyProvidedBy(*args, **kw) def test_wo_declarations_in_class_or_instance(self): + class Foo: pass + foo = Foo() self.assertEqual(list(self._callFUT(foo)), []) @@ -1832,9 +1998,11 @@ def test_w_declarations_in_class_but_not_instance(self): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @implementer(IFoo) class Foo: pass + foo = Foo() self.assertEqual(list(self._callFUT(foo)), []) @@ -1842,8 +2010,10 @@ def test_w_declarations_in_instance_but_not_class(self): from zope.interface.declarations import directlyProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + foo = Foo() directlyProvides(foo, IFoo) self.assertEqual(list(self._callFUT(foo)), [IFoo]) @@ -1854,9 +2024,11 @@ def test_w_declarations_in_instance_and_class(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + @implementer(IFoo) class Foo: pass + foo = Foo() directlyProvides(foo, IBar) self.assertEqual(list(self._callFUT(foo)), [IBar]) @@ -1875,11 +2047,17 @@ def test_w_class(self): from zope.interface.declarations import ClassProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @self._makeOne(IFoo) class Foo: pass - self.assertIsInstance(Foo.__provides__, ClassProvides) # pylint:disable=no-member - self.assertEqual(list(Foo.__provides__), [IFoo]) # pylint:disable=no-member + + self.assertIsInstance( + Foo.__provides__, ClassProvides + ) # pylint:disable=no-member + self.assertEqual( + list(Foo.__provides__), [IFoo] + ) # pylint:disable=no-member class Test_moduleProvides(unittest.TestCase): @@ -1895,7 +2073,7 @@ def test_called_from_function(self): CODE = "\n".join([ 'def foo():', ' moduleProvides(IFoo)' - ]) + ]) exec(CODE, globs, locs) foo = locs['foo'] self.assertRaises(TypeError, foo) @@ -1910,7 +2088,7 @@ def test_called_from_class(self): CODE = "\n".join([ 'class Foo(object):', ' moduleProvides(IFoo)', - ]) + ]) with self.assertRaises(TypeError): exec(CODE, globs, locs) @@ -1922,7 +2100,7 @@ def test_called_once_from_module_scope(self): 'moduleProvides': moduleProvides, 'IFoo': IFoo} CODE = "\n".join([ 'moduleProvides(IFoo)', - ]) + ]) exec(CODE, globs) spec = globs['__provides__'] self.assertEqual(list(spec), [IFoo]) @@ -1937,7 +2115,7 @@ def test_called_twice_from_module_scope(self): CODE = "\n".join([ 'moduleProvides(IFoo)', 'moduleProvides(IFoo)', - ]) + ]) with self.assertRaises(TypeError): exec(CODE, globs) @@ -1956,6 +2134,7 @@ def _callFUT(self, *args, **kw): def test_wo_existing_provides_classless(self): the_dict = {} + class Foo: def __getattribute__(self, name): # Emulate object w/o any class @@ -1965,8 +2144,10 @@ def __getattribute__(self, name): return the_dict[name] except KeyError: raise AttributeError(name) + def __setattr__(self, name, value): raise NotImplementedError() + foo = Foo() spec = self._callFUT(foo) self.assertEqual(list(spec), []) @@ -1975,16 +2156,20 @@ def test_existing_provides_is_spec(self): from zope.interface.declarations import directlyProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + def foo(): raise NotImplementedError() + directlyProvides(foo, IFoo) spec = self._callFUT(foo) - self.assertIs(spec, foo.__provides__) # pylint:disable=no-member + self.assertIs(spec, foo.__provides__) # pylint:disable=no-member def test_existing_provides_is_not_spec(self): + def foo(): raise NotImplementedError() - foo.__provides__ = object() # not a valid spec + + foo.__provides__ = object() # not a valid spec spec = self._callFUT(foo) self.assertEqual(list(spec), []) @@ -1992,8 +2177,10 @@ def test_existing_provides(self): from zope.interface.declarations import directlyProvides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + foo = Foo() directlyProvides(foo, IFoo) spec = self._callFUT(foo) @@ -2003,28 +2190,38 @@ def test_wo_provides_on_class_w_implements(self): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @implementer(IFoo) class Foo: pass + foo = Foo() spec = self._callFUT(foo) self.assertEqual(list(spec), [IFoo]) def test_wo_provides_on_class_wo_implements(self): + class Foo: pass + foo = Foo() spec = self._callFUT(foo) self.assertEqual(list(spec), []) def test_catches_only_AttributeError_on_provides(self): - MissingSomeAttrs.test_raises(self, self._callFUT, expected_missing='__provides__') + MissingSomeAttrs.test_raises( + self, self._callFUT, expected_missing='__provides__' + ) def test_catches_only_AttributeError_on_class(self): - MissingSomeAttrs.test_raises(self, self._callFUT, expected_missing='__class__', - __provides__=None) + MissingSomeAttrs.test_raises( + self, + self._callFUT, + expected_missing='__class__', + __provides__=None, + ) - def test_raises_AttributeError_when_provides_fails_type_check_AttributeError(self): + def test_raises_AttrError_w_provides_fails_type_check_AttrError(self): # isinstance(ob.__provides__, SpecificationBase) is not # protected inside any kind of block. @@ -2034,7 +2231,7 @@ class Foo: # isinstance() ignores AttributeError on __class__ self._callFUT(Foo()) - def test_raises_AttributeError_when_provides_fails_type_check_RuntimeError(self): + def test_raises_AttrError_w_provides_fails_type_check_RuntimeError(self): # isinstance(ob.__provides__, SpecificationBase) is not # protected inside any kind of block. class Foo: @@ -2068,8 +2265,10 @@ def _callFUT(self, *args, **kw): return self._getTargetClass()(*args, **kw) def test_wo_providedBy_on_class_wo_implements(self): + class Foo: pass + foo = Foo() spec = self._callFUT(foo) self.assertEqual(list(spec), []) @@ -2078,16 +2277,20 @@ def test_w_providedBy_valid_spec(self): from zope.interface.declarations import Provides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + foo = Foo() foo.__providedBy__ = Provides(Foo, IFoo) spec = self._callFUT(foo) self.assertEqual(list(spec), [IFoo]) def test_w_providedBy_invalid_spec(self): + class Foo: pass + foo = Foo() foo.__providedBy__ = object() spec = self._callFUT(foo) @@ -2097,17 +2300,21 @@ def test_w_providedBy_invalid_spec_class_w_implements(self): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @implementer(IFoo) class Foo: pass + foo = Foo() foo.__providedBy__ = object() spec = self._callFUT(foo) self.assertEqual(list(spec), [IFoo]) def test_w_providedBy_invalid_spec_w_provides_no_provides_on_class(self): + class Foo: pass + foo = Foo() foo.__providedBy__ = object() expected = foo.__provides__ = object() @@ -2115,8 +2322,10 @@ class Foo: self.assertTrue(spec is expected) def test_w_providedBy_invalid_spec_w_provides_diff_provides_on_class(self): + class Foo: pass + foo = Foo() foo.__providedBy__ = object() expected = foo.__provides__ = object() @@ -2128,9 +2337,11 @@ def test_w_providedBy_invalid_spec_w_provides_same_provides_on_class(self): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + @implementer(IFoo) class Foo: pass + foo = Foo() foo.__providedBy__ = object() foo.__provides__ = Foo.__provides__ = object() @@ -2298,7 +2509,6 @@ def test_catches_only_AttributeError_on_class(self): self, self._callFUT, expected_missing='__class__') - class Test_providedBy(Test_providedByFallback, OptimizationTestMixin): # Repeat tests for C optimizations @@ -2325,8 +2535,10 @@ def test_accessed_via_class(self): from zope.interface.declarations import Provides from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") + class Foo: pass + Foo.__provides__ = Provides(Foo, IFoo) Foo.__providedBy__ = self._makeOne() self.assertEqual(list(Foo.__providedBy__), [IFoo]) @@ -2337,9 +2549,11 @@ def test_accessed_via_inst_wo_provides(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") + @implementer(IFoo) class Foo: pass + Foo.__provides__ = Provides(Foo, IBar) Foo.__providedBy__ = self._makeOne() foo = Foo() @@ -2353,9 +2567,11 @@ def test_accessed_via_inst_w_provides(self): IFoo = InterfaceClass("IFoo") IBar = InterfaceClass("IBar") IBaz = InterfaceClass("IBaz") + @implementer(IFoo) class Foo: pass + Foo.__provides__ = Provides(Foo, IBar) Foo.__providedBy__ = self._makeOne() foo = Foo() @@ -2413,6 +2629,7 @@ def __provides__(self): provided = getattr(Foo(), '__providedBy__') self.assertIsNone(provided) + class ObjectSpecificationDescriptorTests( ObjectSpecificationDescriptorFallbackTests, OptimizationTestMixin): @@ -2443,7 +2660,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): class _MonkeyDict: - # context-manager for restoring a dict w/in a module in the scope of a test. + # context-manager for restoring a dict w/in a module in the scope of a + # test. def __init__(self, module, attrname, **kw): self.module = module self.target = getattr(module, attrname) diff --git a/src/zope/interface/tests/test_document.py b/src/zope/interface/tests/test_document.py index 2a954970..82b175a8 100644 --- a/src/zope/interface/tests/test_document.py +++ b/src/zope/interface/tests/test_document.py @@ -31,8 +31,10 @@ def test_asStructuredText_no_docstring(self): " Methods:", "" ]) + class INoDocstring(Interface): pass + self.assertEqual(self._callFUT(INoDocstring), EXPECTED) def test_asStructuredText_empty_with_docstring(self): @@ -44,9 +46,11 @@ def test_asStructuredText_empty_with_docstring(self): " Methods:", "" ]) + class IEmpty(Interface): """ This is an empty interface. """ + self.assertEqual(self._callFUT(IEmpty), EXPECTED) def test_asStructuredText_empty_with_multiline_docstring(self): @@ -61,7 +65,7 @@ def test_asStructuredText_empty_with_multiline_docstring(self): " This is an empty interface.", " ", (f"{indent} It can be used to annotate any class or object, " - "because it promises"), + "because it promises"), # noqa E127 f"{indent} nothing.", "", " Attributes:", @@ -70,12 +74,14 @@ def test_asStructuredText_empty_with_multiline_docstring(self): "", "" ]) + 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): @@ -89,6 +95,7 @@ def test_asStructuredText_with_attribute_no_docstring(self): " Methods:", "" ]) + class IHasAttribute(Interface): """ This interface has an attribute. """ @@ -107,6 +114,7 @@ def test_asStructuredText_with_attribute_with_docstring(self): " Methods:", "" ]) + class IHasAttribute(Interface): """ This interface has an attribute. """ @@ -125,6 +133,7 @@ def test_asStructuredText_with_method_no_args_no_docstring(self): " aMethod() -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -143,6 +152,7 @@ def test_asStructuredText_with_method_positional_args_no_docstring(self): " aMethod(first, second) -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -161,6 +171,7 @@ def test_asStructuredText_with_method_starargs_no_docstring(self): " aMethod(first, second, *rest) -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -179,6 +190,7 @@ def test_asStructuredText_with_method_kwargs_no_docstring(self): " aMethod(first, second, **kw) -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -197,6 +209,7 @@ def test_asStructuredText_with_method_with_docstring(self): " aMethod() -- This method is documented.", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -227,6 +240,7 @@ def test_asStructuredText_derived_ignores_base(self): class IBase(Interface): def method1(): """docstring""" + def method2(): """docstring""" @@ -237,8 +251,10 @@ class IDerived(IBase): def method3(): "method3 doc" + def method4(): pass # pragma: no cover + def method5(): "method5 doc" @@ -259,8 +275,10 @@ def test_asReStructuredText_no_docstring(self): " Methods:", "" ]) + class INoDocstring(Interface): pass + self.assertEqual(self._callFUT(INoDocstring), EXPECTED) def test_asReStructuredText_empty_with_docstring(self): @@ -272,9 +290,11 @@ def test_asReStructuredText_empty_with_docstring(self): " Methods:", "" ]) + class IEmpty(Interface): """ This is an empty interface. """ + self.assertEqual(self._callFUT(IEmpty), EXPECTED) def test_asReStructuredText_empty_with_multiline_docstring(self): @@ -289,8 +309,9 @@ def test_asReStructuredText_empty_with_multiline_docstring(self): " This is an empty interface.", " ", (f"{indent} It can be used to annotate any class or object, " - "because it promises"), - f"{indent} nothing.", + f"because it" + ), # noqa E124 + f"{indent} promises nothing.", "", " Attributes:", "", @@ -298,12 +319,14 @@ def test_asReStructuredText_empty_with_multiline_docstring(self): "", "" ]) + class IEmpty(Interface): """ This is an empty interface. - It can be used to annotate any class or object, because it promises - nothing. + 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): @@ -317,6 +340,7 @@ def test_asReStructuredText_with_attribute_no_docstring(self): " Methods:", "" ]) + class IHasAttribute(Interface): """ This interface has an attribute. """ @@ -335,6 +359,7 @@ def test_asReStructuredText_with_attribute_with_docstring(self): " Methods:", "" ]) + class IHasAttribute(Interface): """ This interface has an attribute. """ @@ -353,6 +378,7 @@ def test_asReStructuredText_with_method_no_args_no_docstring(self): " ``aMethod()`` -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -371,6 +397,7 @@ def test_asReStructuredText_with_method_positional_args_no_docstring(self): " ``aMethod(first, second)`` -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -389,6 +416,7 @@ def test_asReStructuredText_with_method_starargs_no_docstring(self): " ``aMethod(first, second, *rest)`` -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -407,6 +435,7 @@ def test_asReStructuredText_with_method_kwargs_no_docstring(self): " ``aMethod(first, second, **kw)`` -- no documentation", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -425,6 +454,7 @@ def test_asReStructuredText_with_method_with_docstring(self): " ``aMethod()`` -- This method is documented.", "" ]) + class IHasMethod(Interface): """ This interface has a method. """ @@ -455,6 +485,7 @@ def test_asReStructuredText_derived_ignores_base(self): class IBase(Interface): def method1(): pass # pragma: no cover + def method2(): pass # pragma: no cover @@ -465,8 +496,10 @@ class IDerived(IBase): def method3(): "method3 doc" + def method4(): pass # pragma: no cover + def method5(): "method5 doc" diff --git a/src/zope/interface/tests/test_exceptions.py b/src/zope/interface/tests/test_exceptions.py index 7b683912..e48c00f6 100644 --- a/src/zope/interface/tests/test_exceptions.py +++ b/src/zope/interface/tests/test_exceptions.py @@ -18,10 +18,13 @@ def _makeIface(): from zope.interface import Interface + class IDummy(Interface): pass + return IDummy + class DoesNotImplementTests(unittest.TestCase): def _getTargetClass(self): @@ -138,7 +141,8 @@ def test___repr__w_candidate(self): dni = self._makeOne(None, 'candidate') self.assertEqual( repr(dni), - "BrokenMethodImplementation('aMethod', 'I said so', None, 'candidate')" + "BrokenMethodImplementation(" + "'aMethod', 'I said so', None, 'candidate')" ) @@ -178,7 +182,8 @@ def test__repr__(self): dni = self._makeOne(excs) self.assertEqual( repr(dni), - "MultipleInvalid(," + "MultipleInvalid(" + "," " 'target'," " (BrokenMethodImplementation('aMethod', 'I said so')," " Exception('Regular', 'exception')))" diff --git a/src/zope/interface/tests/test_interface.py b/src/zope/interface/tests/test_interface.py index 236d4817..12f75bbe 100644 --- a/src/zope/interface/tests/test_interface.py +++ b/src/zope/interface/tests/test_interface.py @@ -14,11 +14,19 @@ """Test Interface implementation """ # Things we let slide because it's a test -# pylint:disable=protected-access,blacklisted-name,attribute-defined-outside-init -# pylint:disable=too-many-public-methods,too-many-lines,abstract-method -# pylint:disable=redefined-builtin,signature-differs,arguments-differ +# pylint:disable=protected-access +# pylint:disable=blacklisted-name +# pylint:disable=attribute-defined-outside-init +# pylint:disable=too-many-public-methods +# pylint:disable=too-many-lines +# pylint:disable=abstract-method +# pylint:disable=redefined-builtin +# pylint:disable=signature-differs +# pylint:disable=arguments-differ # Things you get inheriting from Interface -# pylint:disable=inherit-non-class,no-self-argument,no-method-argument +# pylint:disable=inherit-non-class +# pylint:disable=no-self-argument +# pylint:disable=no-method-argument # Things you get using methods of an Interface 'subclass' # pylint:disable=no-value-for-parameter import unittest @@ -155,7 +163,9 @@ def test_queryDirectTaggedValue_miss(self): def test_queryDirectTaggedValue_miss_w_default(self): element = self._makeOne() - self.assertEqual(element.queryDirectTaggedValue('nonesuch', 'bar'), 'bar') + self.assertEqual( + element.queryDirectTaggedValue('nonesuch', 'bar'), 'bar' + ) def test_setTaggedValue(self): element = self._makeOne() @@ -187,8 +197,10 @@ def test_providedBy_miss(self): from zope.interface import interface from zope.interface.declarations import _empty sb = self._makeOne() + def _providedBy(obj): return _empty + with _Monkey(interface, providedBy=_providedBy): self.assertFalse(sb.providedBy(object())) @@ -196,8 +208,10 @@ def test_implementedBy_miss(self): from zope.interface import interface from zope.interface.declarations import _empty sb = self._makeOne() + def _implementedBy(obj): return _empty + with _Monkey(interface, implementedBy=_implementedBy): self.assertFalse(sb.implementedBy(object())) @@ -210,6 +224,7 @@ def _getTargetClass(self): from zope.interface.interface import SpecificationBase return SpecificationBase + class SpecificationBasePyTests(GenericSpecificationBaseTests): # Tests that only work with the Python implementation @@ -238,20 +253,26 @@ def test_isOrExtends_hit(self): def test_implementedBy_hit(self): from zope.interface import interface sb = self._makeOne() + class _Decl: - _implied = {sb: {},} + _implied = {sb: {}} + def _implementedBy(obj): return _Decl() + with _Monkey(interface, implementedBy=_implementedBy): self.assertTrue(sb.implementedBy(object())) def test_providedBy_hit(self): from zope.interface import interface sb = self._makeOne() + class _Decl: - _implied = {sb: {},} + _implied = {sb: {}} + def _providedBy(obj): return _Decl() + with _Monkey(interface, providedBy=_providedBy): self.assertTrue(sb.providedBy(object())) @@ -275,6 +296,7 @@ def __check_NotImplemented_comparison(self, name): # NotImplemented. class RaisesErrorOnMissing: Exc = AttributeError + def __getattribute__(self, name): try: return object.__getattribute__(self, name) @@ -285,6 +307,7 @@ def __getattribute__(self, name): class RaisesErrorOnModule(RaisesErrorOnMissing): def __init__(self): self.__name__ = 'foo' + @property def __module__(self): raise AttributeError @@ -373,19 +396,24 @@ def _getFallbackClass(self): return InterfaceBasePy def _makeOne(self, object_should_provide=False, name=None, module=None): + class IB(self._getTargetClass()): def _call_conform(self, conform): return conform(self) + def providedBy(self, obj): return object_should_provide + return IB(name, module) def test___call___w___conform___returning_value(self): ib = self._makeOne(False) conformed = object() + class _Adapted: def __conform__(self, iface): return conformed + self.assertIs(ib(_Adapted()), conformed) def test___call___wo___conform___ob_no_provides_w_alternate(self): @@ -403,7 +431,9 @@ def test___call___w___conform___ob_no_provides_wo_alternate(self): self.assertIn('Could not adapt', str(exc.exception)) def test___call___w_no_conform_catches_only_AttributeError(self): - MissingSomeAttrs.test_raises(self, self._makeOne(), expected_missing='__conform__') + MissingSomeAttrs.test_raises( + self, self._makeOne(), expected_missing='__conform__' + ) class InterfaceBaseTests(InterfaceBaseTestsMixin, @@ -422,9 +452,11 @@ class InterfaceBasePyTests(InterfaceBaseTestsMixin, unittest.TestCase): def test___call___w___conform___miss_ob_provides(self): ib = self._makeOne(True) + class _Adapted: def __conform__(self, iface): return None + adapted = _Adapted() self.assertIs(ib(adapted), adapted) @@ -438,14 +470,18 @@ def test___adapt___ob_no_provides_uses_hooks(self): ib = self._makeOne(False) adapted = object() _missed = [] + def _hook_miss(iface, obj): _missed.append((iface, obj)) + def _hook_hit(iface, obj): return obj + with _Monkey(interface, adapter_hooks=[_hook_miss, _hook_hit]): self.assertIs(ib.__adapt__(adapted), adapted) self.assertEqual(_missed, [(ib, adapted)]) + class SpecificationTests(unittest.TestCase): def _getTargetClass(self): @@ -500,39 +536,48 @@ def test___setBases_subscribes_bases_and_notifies_dependents(self): spec = self._makeOne() dep = DummyDependent() spec.subscribe(dep) - class I(Interface): + + class IFoo(Interface): pass - class J(Interface): + + class IBar(Interface): pass - spec.__bases__ = (I,) + + spec.__bases__ = (IFoo,) self.assertEqual(dep._changed, [spec]) - self.assertEqual(I.dependents[spec], 1) - spec.__bases__ = (J,) - self.assertEqual(I.dependents.get(spec), None) - self.assertEqual(J.dependents[spec], 1) + self.assertEqual(IFoo.dependents[spec], 1) + spec.__bases__ = (IBar,) + self.assertEqual(IFoo.dependents.get(spec), None) + self.assertEqual(IBar.dependents[spec], 1) def test_changed_clears_volatiles_and_implied(self): from zope.interface.interface import Interface - class I(Interface): + + class IFoo(Interface): pass + spec = self._makeOne() spec._v_attrs = 'Foo' - spec._implied[I] = () + spec._implied[IFoo] = () spec.changed(spec) self.assertIsNone(spec._v_attrs) - self.assertFalse(I in spec._implied) + self.assertFalse(IFoo in spec._implied) def test_interfaces_skips_already_seen(self): from zope.interface.interface import Interface + class IFoo(Interface): pass + spec = self._makeOne([IFoo, IFoo]) self.assertEqual(list(spec.interfaces()), [IFoo]) def test_extends_strict_wo_self(self): from zope.interface.interface import Interface + class IFoo(Interface): pass + spec = self._makeOne(IFoo) self.assertFalse(spec.extends(IFoo, strict=True)) @@ -553,10 +598,13 @@ def test_get_hit_w__v_attrs(self): def test_get_hit_from_base_wo__v_attrs(self): from zope.interface.interface import Attribute from zope.interface.interface import Interface + class IFoo(Interface): foo = Attribute('foo') + class IBar(Interface): bar = Attribute('bar') + spec = self._makeOne([IFoo, IBar]) self.assertTrue(spec.get('foo') is IFoo.get('foo')) self.assertTrue(spec.get('bar') is IBar.get('bar')) @@ -598,7 +646,7 @@ class Model(OtherBase, Context): IOther, implementedBy(Context), implementedBy(object), - Interface, # This used to be wrong, it used to be 2 too high. + Interface, # This used to be wrong, it used to be 2 too high. ) ) @@ -628,11 +676,14 @@ def test_ctor_bad_bases(self): def test_ctor_w_attrs_attrib_methods(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } klass = self._getTargetClass() inst = klass('ITesting', attrs=ATTRS) self.assertEqual(inst.__name__, 'ITesting') @@ -708,13 +759,17 @@ def test_isEqualOrExtendedBy_unrelated(self): def test_names_w_all_False_ignores_bases(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) self.assertEqual(sorted(derived.names(all=False)), ['baz']) @@ -722,58 +777,79 @@ def _bar(): def test_names_w_all_True_no_bases(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } one = self._makeOne(attrs=ATTRS) self.assertEqual(sorted(one.names(all=True)), ['bar', 'foo']) def test_names_w_all_True_w_bases_simple(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) - self.assertEqual(sorted(derived.names(all=True)), ['bar', 'baz', 'foo']) + self.assertEqual( + sorted(derived.names(all=True)), ['bar', 'baz', 'foo'] + ) def test_names_w_all_True_bases_w_same_names(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" + def _foo(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'foo': fromFunction(_foo), - 'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) - self.assertEqual(sorted(derived.names(all=True)), ['bar', 'baz', 'foo']) + self.assertEqual(sorted( + derived.names(all=True)), ['bar', 'baz', 'foo'] + ) def test___iter__(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" + def _foo(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'foo': fromFunction(_foo), - 'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) self.assertEqual(sorted(derived), ['bar', 'baz', 'foo']) @@ -781,71 +857,95 @@ def _foo(): def test_namesAndDescriptions_w_all_False_ignores_bases(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) - self.assertEqual(sorted(derived.namesAndDescriptions(all=False)), - [('baz', DERIVED_ATTRS['baz']), - ]) + self.assertEqual( + sorted(derived.namesAndDescriptions(all=False)), [ + ('baz', DERIVED_ATTRS['baz']), + ] + ) def test_namesAndDescriptions_w_all_True_no_bases(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } one = self._makeOne(attrs=ATTRS) - self.assertEqual(sorted(one.namesAndDescriptions(all=False)), - [('bar', ATTRS['bar']), - ('foo', ATTRS['foo']), - ]) + self.assertEqual( + sorted(one.namesAndDescriptions(all=False)), [ + ('bar', ATTRS['bar']), + ('foo', ATTRS['foo']), + ] + ) def test_namesAndDescriptions_w_all_True_simple(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) - self.assertEqual(sorted(derived.namesAndDescriptions(all=True)), - [('bar', BASE_ATTRS['bar']), - ('baz', DERIVED_ATTRS['baz']), - ('foo', BASE_ATTRS['foo']), - ]) + self.assertEqual( + sorted(derived.namesAndDescriptions(all=True)), [ + ('bar', BASE_ATTRS['bar']), + ('baz', DERIVED_ATTRS['baz']), + ('foo', BASE_ATTRS['foo']), + ] + ) def test_namesAndDescriptions_w_all_True_bases_w_same_names(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" + def _foo(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'foo': fromFunction(_foo), - 'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) - self.assertEqual(sorted(derived.namesAndDescriptions(all=True)), - [('bar', BASE_ATTRS['bar']), - ('baz', DERIVED_ATTRS['baz']), - ('foo', DERIVED_ATTRS['foo']), - ]) + self.assertEqual( + sorted(derived.namesAndDescriptions(all=True)), [ + ('bar', BASE_ATTRS['bar']), + ('baz', DERIVED_ATTRS['baz']), + ('foo', DERIVED_ATTRS['foo']), + ] + ) def test_getDescriptionFor_miss(self): one = self._makeOne() @@ -854,29 +954,37 @@ def test_getDescriptionFor_miss(self): def test_getDescriptionFor_hit(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } one = self._makeOne(attrs=ATTRS) self.assertEqual(one.getDescriptionFor('foo'), ATTRS['foo']) self.assertEqual(one.getDescriptionFor('bar'), ATTRS['bar']) def test___getitem___miss(self): one = self._makeOne() + def _test(): return one['nonesuch'] + self.assertRaises(KeyError, _test) def test___getitem___hit(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } one = self._makeOne(attrs=ATTRS) self.assertEqual(one['foo'], ATTRS['foo']) self.assertEqual(one['bar'], ATTRS['bar']) @@ -888,11 +996,14 @@ def test___contains___miss(self): def test___contains___hit(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" - ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } + + ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } one = self._makeOne(attrs=ATTRS) self.assertTrue('foo' in one) self.assertTrue('bar' in one) @@ -904,16 +1015,21 @@ def test_direct_miss(self): def test_direct_hit_local_miss_bases(self): from zope.interface.interface import Attribute from zope.interface.interface import fromFunction + def _bar(): """DOCSTRING""" + def _foo(): """DOCSTRING""" - BASE_ATTRS = {'foo': Attribute('Foo', ''), - 'bar': fromFunction(_bar), - } - DERIVED_ATTRS = {'foo': fromFunction(_foo), - 'baz': Attribute('Baz', ''), - } + + BASE_ATTRS = { + 'foo': Attribute('Foo', ''), + 'bar': fromFunction(_bar), + } + DERIVED_ATTRS = { + 'foo': fromFunction(_foo), + 'baz': Attribute('Baz', ''), + } base = self._makeOne('IBase', attrs=BASE_ATTRS) derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS) self.assertEqual(derived.direct('foo'), DERIVED_ATTRS['foo']) @@ -932,9 +1048,11 @@ def test_queryDescriptionFor_hit(self): def test_validateInvariants_pass(self): _called_with = [] + def _passable(*args, **kw): _called_with.append((args, kw)) return True + iface = self._makeOne() obj = object() iface.setTaggedValue('invariants', [_passable]) @@ -944,13 +1062,17 @@ def _passable(*args, **kw): def test_validateInvariants_fail_wo_errors_passed(self): from zope.interface.exceptions import Invalid _passable_called_with = [] + def _passable(*args, **kw): _passable_called_with.append((args, kw)) return True + _fail_called_with = [] + def _fail(*args, **kw): _fail_called_with.append((args, kw)) raise Invalid + iface = self._makeOne() obj = object() iface.setTaggedValue('invariants', [_passable, _fail]) @@ -962,9 +1084,11 @@ def test_validateInvariants_fail_w_errors_passed(self): from zope.interface.exceptions import Invalid _errors = [] _fail_called_with = [] + def _fail(*args, **kw): _fail_called_with.append((args, kw)) raise Invalid + iface = self._makeOne() obj = object() iface.setTaggedValue('invariants', [_fail]) @@ -976,13 +1100,17 @@ def _fail(*args, **kw): def test_validateInvariants_fail_in_base_wo_errors_passed(self): from zope.interface.exceptions import Invalid _passable_called_with = [] + def _passable(*args, **kw): _passable_called_with.append((args, kw)) return True + _fail_called_with = [] + def _fail(*args, **kw): _fail_called_with.append((args, kw)) raise Invalid + base = self._makeOne('IBase') derived = self._makeOne('IDerived', (base,)) obj = object() @@ -996,13 +1124,17 @@ def test_validateInvariants_fail_in_base_w_errors_passed(self): from zope.interface.exceptions import Invalid _errors = [] _passable_called_with = [] + def _passable(*args, **kw): _passable_called_with.append((args, kw)) return True + _fail_called_with = [] + def _fail(*args, **kw): _fail_called_with.append((args, kw)) raise Invalid + base = self._makeOne('IBase') derived = self._makeOne('IDerived', (base,)) obj = object() @@ -1034,14 +1166,17 @@ def test___reduce__(self): def test___hash___normal(self): iface = self._makeOne('HashMe') - self.assertEqual(hash(iface), - hash(('HashMe', - 'zope.interface.tests.test_interface'))) + self.assertEqual( + hash(iface), + hash(('HashMe', 'zope.interface.tests.test_interface')) + ) def test___hash___missing_required_attrs(self): + class Derived(self._getTargetClass()): - def __init__(self): # pylint:disable=super-init-not-called - pass # Don't call base class. + def __init__(self): # pylint:disable=super-init-not-called + pass # Don't call base class. + derived = Derived() with self.assertRaises(AttributeError): hash(derived) @@ -1049,19 +1184,19 @@ def __init__(self): # pylint:disable=super-init-not-called def test_comparison_with_None(self): # pylint:disable=singleton-comparison,misplaced-comparison-constant iface = self._makeOne() - self.assertTrue(iface < None) - self.assertTrue(iface <= None) - self.assertFalse(iface == None) - self.assertTrue(iface != None) - self.assertFalse(iface >= None) - self.assertFalse(iface > None) - - self.assertFalse(None < iface) - self.assertFalse(None <= iface) - self.assertFalse(None == iface) - self.assertTrue(None != iface) - self.assertTrue(None >= iface) - self.assertTrue(None > iface) + self.assertTrue(iface < None) # noqa E711 + self.assertTrue(iface <= None) # noqa E711 + self.assertFalse(iface == None) # noqa E711 + self.assertTrue(iface != None) # noqa E711 + self.assertFalse(iface >= None) # noqa E711 + self.assertFalse(iface > None) # noqa E711 + + self.assertFalse(None < iface) # noqa E711 + self.assertFalse(None <= iface) # noqa E711 + self.assertFalse(None == iface) # noqa E711 + self.assertTrue(None != iface) # noqa E711 + self.assertTrue(None >= iface) # noqa E711 + self.assertTrue(None > iface) # noqa E711 def test_comparison_with_same_instance(self): # pylint:disable=comparison-with-itself @@ -1120,6 +1255,7 @@ def test_assignment_to__class__2(self): # This is essentially a transcription of the # test presented in the bug report. from zope.interface import Interface + class MyInterfaceClass(self._getTargetClass()): def __call__(self, *args): return args @@ -1162,7 +1298,6 @@ def test_methods_link_to_interface(self): from zope.interface import Interface class I1(Interface): - def method(foo, bar, bingo): "A method" @@ -1176,6 +1311,7 @@ def test_classImplements_simple(self): class ICurrent(Interface): def method1(a, b): """docstring""" + def method2(a, b): """docstring""" @@ -1184,8 +1320,10 @@ class IOther(Interface): class Current: __implemented__ = ICurrent + def method1(self, a, b): raise NotImplementedError() + def method2(self, a, b): raise NotImplementedError() @@ -1203,15 +1341,20 @@ def test_classImplements_base_not_derived(self): from zope.interface import Interface from zope.interface import implementedBy from zope.interface import providedBy + class IBase(Interface): def method(): """docstring""" + class IDerived(IBase): pass + class Current(): __implemented__ = IBase + def method(self): raise NotImplementedError() + current = Current() self.assertTrue(IBase.implementedBy(Current)) @@ -1235,6 +1378,7 @@ class IDerived(IBase): class Current: __implemented__ = IDerived + def method(self): raise NotImplementedError() @@ -1347,7 +1491,6 @@ def test_verifyClass(self): from zope.interface import Interface from zope.interface.verify import verifyClass - class ICheckMe(Interface): attr = Attribute('My attr') @@ -1368,7 +1511,6 @@ def test_verifyObject(self): from zope.interface import Interface from zope.interface.verify import verifyObject - class ICheckMe(Interface): attr = Attribute('My attr') @@ -1398,7 +1540,6 @@ def test_names_simple(self): from zope.interface import Attribute from zope.interface import Interface - class ISimple(Interface): attr = Attribute('My attr') @@ -1411,7 +1552,6 @@ def test_names_derived(self): from zope.interface import Attribute from zope.interface import Interface - class IBase(Interface): attr = Attribute('My attr') @@ -1437,7 +1577,6 @@ def test_namesAndDescriptions_simple(self): from zope.interface import Interface from zope.interface.interface import Method - class ISimple(Interface): attr = Attribute('My attr') @@ -1461,7 +1600,6 @@ def test_namesAndDescriptions_derived(self): from zope.interface import Interface from zope.interface.interface import Method - class IBase(Interface): attr = Attribute('My attr') @@ -1526,7 +1664,6 @@ def test_getDescriptionFor_simple(self): from zope.interface import Interface from zope.interface.interface import Method - class ISimple(Interface): attr = Attribute('My attr') @@ -1548,7 +1685,6 @@ def test_getDescriptionFor_derived(self): from zope.interface import Interface from zope.interface.interface import Method - class IBase(Interface): attr = Attribute('My attr') @@ -1597,7 +1733,6 @@ def test___getitem__simple(self): from zope.interface import Interface from zope.interface.interface import Method - class ISimple(Interface): attr = Attribute('My attr') @@ -1619,7 +1754,6 @@ def test___getitem___derived(self): from zope.interface import Interface from zope.interface.interface import Method - class IBase(Interface): attr = Attribute('My attr') @@ -1667,7 +1801,6 @@ def test___contains__simple(self): from zope.interface import Attribute from zope.interface import Interface - class ISimple(Interface): attr = Attribute('My attr') @@ -1681,7 +1814,6 @@ def test___contains__derived(self): from zope.interface import Attribute from zope.interface import Interface - class IBase(Interface): attr = Attribute('My attr') @@ -1714,7 +1846,6 @@ def test___iter__simple(self): from zope.interface import Attribute from zope.interface import Interface - class ISimple(Interface): attr = Attribute('My attr') @@ -1727,7 +1858,6 @@ def test___iter__derived(self): from zope.interface import Attribute from zope.interface import Interface - class IBase(Interface): attr = Attribute('My attr') @@ -1906,8 +2036,12 @@ class HasInvariant: # number then we'll get the new error has_invariant.foo = 2 has_invariant.bar = 1 - self._errorsEqual(has_invariant, 1, - ['Please, Boo MUST be greater than Foo!'], IInvariant) + self._errorsEqual( + has_invariant, + 1, + ['Please, Boo MUST be greater than Foo!'], + IInvariant + ) # and if we set foo to a positive number and boo to 0, we'll # get both errors! has_invariant.foo = 1 @@ -1926,6 +2060,7 @@ class HasInvariant: def test___doc___element(self): from zope.interface import Attribute from zope.interface import Interface + class IDocstring(Interface): "xxx" @@ -1997,21 +2132,26 @@ class IDerived2(IDerived): def _make_taggedValue_tree(self, base): from zope.interface import Attribute from zope.interface import taggedValue - O = base - class F(O): + + class F(base): taggedValue('tag', 'F') tag = Attribute('F') - class E(O): + + class E(base): taggedValue('tag', 'E') tag = Attribute('E') - class D(O): + + class D(base): taggedValue('tag', 'D') tag = Attribute('D') + class C(D, F): taggedValue('tag', 'C') tag = Attribute('C') + class B(D, E): pass + class A(B, C): pass @@ -2085,53 +2225,53 @@ def test___call___defers_to___conform___(self): from zope.interface import Interface from zope.interface import implementer - class I(Interface): + class IFoo(Interface): pass - @implementer(I) + @implementer(IFoo) class C: def __conform__(self, proto): return 0 - self.assertEqual(I(C()), 0) + self.assertEqual(IFoo(C()), 0) def test___call___object_implements(self): from zope.interface import Interface from zope.interface import implementer - class I(Interface): + class IFoo(Interface): pass - @implementer(I) + @implementer(IFoo) class C: pass c = C() - self.assertTrue(I(c) is c) + self.assertTrue(IFoo(c) is c) def test___call___miss_wo_alternate(self): from zope.interface import Interface - class I(Interface): + class IFoo(Interface): pass class C: pass c = C() - self.assertRaises(TypeError, I, c) + self.assertRaises(TypeError, IFoo, c) def test___call___miss_w_alternate(self): from zope.interface import Interface - class I(Interface): + class IFoo(Interface): pass class C: pass c = C() - self.assertTrue(I(c, self) is self) + self.assertTrue(IFoo(c, self) is self) def test___call___w_adapter_hook(self): from zope.interface import Interface @@ -2143,7 +2283,7 @@ def _miss(iface, obj): def _hit(iface, obj): return self - class I(Interface): + class IFoo(Interface): pass class C: @@ -2154,7 +2294,7 @@ class C: old_adapter_hooks = adapter_hooks[:] adapter_hooks[:] = [_miss, _hit] try: - self.assertTrue(I(c) is self) + self.assertTrue(IFoo(c) is self) finally: adapter_hooks[:] = old_adapter_hooks @@ -2163,20 +2303,20 @@ def test___call___w_overridden_adapt(self): from zope.interface import implementer from zope.interface import interfacemethod - class I(Interface): + class IFoo(Interface): @interfacemethod def __adapt__(self, obj): return 42 - @implementer(I) - class O: + @implementer(IFoo) + class Obj: pass - self.assertEqual(42, I(object())) + self.assertEqual(42, IFoo(object())) # __adapt__ can ignore the fact that the object provides # the interface if it chooses. - self.assertEqual(42, I(O())) + self.assertEqual(42, IFoo(Obj())) def test___call___w_overridden_adapt_and_conform(self): # Conform is first, taking precedence over __adapt__, @@ -2213,7 +2353,6 @@ def __conform__(self, iface): self.assertEqual(42, IAdapt(ConformNone())) - def test___call___w_overridden_adapt_call_super(self): import sys @@ -2221,7 +2360,7 @@ def test___call___w_overridden_adapt_call_super(self): from zope.interface import implementer from zope.interface import interfacemethod - class I(Interface): + class IFoo(Interface): @interfacemethod def __adapt__(self, obj): @@ -2229,28 +2368,28 @@ def __adapt__(self, obj): return 42 return super().__adapt__(obj) - @implementer(I) - class O: + @implementer(IFoo) + class Obj: pass - self.assertEqual(42, I(object())) - o = O() - self.assertIs(o, I(o)) + self.assertEqual(42, IFoo(object())) + obj = Obj() + self.assertIs(obj, IFoo(obj)) def test___adapt___as_method_and_implementation(self): from zope.interface import Interface from zope.interface import interfacemethod - class I(Interface): + class IFoo(Interface): @interfacemethod def __adapt__(self, obj): return 42 - def __adapt__(to_adapt): + def __adapt__(to_adapt): # noqa F811 "This is a protocol" - self.assertEqual(42, I(object())) - self.assertEqual(I['__adapt__'].getSignatureString(), '(to_adapt)') + self.assertEqual(42, IFoo(object())) + self.assertEqual(IFoo['__adapt__'].getSignatureString(), '(to_adapt)') def test___adapt__inheritance_and_type(self): from zope.interface import Interface @@ -2300,7 +2439,7 @@ def test_interfacemethod_is_general(self): from zope.interface import Interface from zope.interface import interfacemethod - class I(Interface): + class IFoo(Interface): @interfacemethod def __call__(self, obj): @@ -2311,8 +2450,8 @@ def __call__(self, obj): def this_is_new(self): return 42 - self.assertEqual(I(self), 42) - self.assertEqual(I.this_is_new(), 42) + self.assertEqual(IFoo(self), 42) + self.assertEqual(IFoo.this_is_new(), 42) class AttributeTests(ElementTests): @@ -2327,13 +2466,19 @@ def test__repr__w_interface(self): method = self._makeOne() method.interface = type(self) r = repr(method) - self.assertTrue(r.startswith(''), r) + self.assertTrue( + r.startswith(''), r + ) def test__repr__wo_interface(self): method = self._makeOne() r = repr(method) - self.assertTrue(r.startswith(''), r) def test__str__w_interface(self): @@ -2414,14 +2559,20 @@ def test__repr__w_interface(self): method.kwargs = 'kw' method.interface = type(self) r = repr(method) - self.assertTrue(r.startswith(''), r) + self.assertTrue( + r.startswith(''), r + ) def test__repr__wo_interface(self): method = self._makeOne() method.kwargs = 'kw' r = repr(method) - self.assertTrue(r.startswith(''), r) def test__str__w_interface(self): @@ -2445,8 +2596,10 @@ def _callFUT(self, *args, **kw): return fromFunction(*args, **kw) def test_bare(self): + def _func(): "DOCSTRING" + method = self._callFUT(_func) self.assertEqual(method.getName(), '_func') self.assertEqual(method.getDoc(), 'DOCSTRING') @@ -2461,22 +2614,29 @@ def _func(): def test_w_interface(self): from zope.interface.interface import InterfaceClass + class IFoo(InterfaceClass): pass + def _func(): "DOCSTRING" + method = self._callFUT(_func, interface=IFoo) self.assertEqual(method.interface, IFoo) def test_w_name(self): + def _func(): "DOCSTRING" + method = self._callFUT(_func, name='anotherName') self.assertEqual(method.getName(), 'anotherName') def test_w_only_required(self): + def _func(foo): "DOCSTRING" + method = self._callFUT(_func) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), ['foo']) @@ -2486,8 +2646,10 @@ def _func(foo): self.assertEqual(info['kwargs'], None) def test_w_optional(self): + def _func(foo='bar'): "DOCSTRING" + method = self._callFUT(_func) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), ['foo']) @@ -2504,8 +2666,10 @@ def test_w_optional_self(self): # if nr < 0: # defaults=defaults[-nr:] # nr = 0 + def _func(self='bar'): "DOCSTRING" + method = self._callFUT(_func, imlevel=1) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), []) @@ -2515,8 +2679,10 @@ def _func(self='bar'): self.assertEqual(info['kwargs'], None) def test_w_varargs(self): + def _func(*args): "DOCSTRING" + method = self._callFUT(_func) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), []) @@ -2526,8 +2692,10 @@ def _func(*args): self.assertEqual(info['kwargs'], None) def test_w_kwargs(self): + def _func(**kw): "DOCSTRING" + method = self._callFUT(_func) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), []) @@ -2537,8 +2705,12 @@ def _func(**kw): self.assertEqual(info['kwargs'], 'kw') def test_full_spectrum(self): - def _func(foo, bar='baz', *args, **kw): # pylint:disable=keyword-arg-before-vararg + + def _func( + foo, bar='baz', *args, **kw + ): # pylint:disable=keyword-arg-before-vararg "DOCSTRING" + method = self._callFUT(_func) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), ['foo', 'bar']) @@ -2555,9 +2727,11 @@ def _callFUT(self, *args, **kw): return fromMethod(*args, **kw) def test_no_args(self): + class Foo: def bar(self): "DOCSTRING" + method = self._callFUT(Foo.bar) self.assertEqual(method.getName(), 'bar') self.assertEqual(method.getDoc(), 'DOCSTRING') @@ -2571,9 +2745,13 @@ def bar(self): self.assertEqual(info['kwargs'], None) def test_full_spectrum(self): + class Foo: - def bar(self, foo, bar='baz', *args, **kw): # pylint:disable=keyword-arg-before-vararg + def bar( + self, foo, bar='baz', *args, **kw + ): # pylint:disable=keyword-arg-before-vararg "DOCSTRING" + method = self._callFUT(Foo.bar) info = method.getSignatureInfo() self.assertEqual(list(info['positional']), ['foo', 'bar']) @@ -2583,8 +2761,10 @@ def bar(self, foo, bar='baz', *args, **kw): # pylint:disable=keyword-arg-before- self.assertEqual(info['kwargs'], 'kw') def test_w_non_method(self): + def foo(): "DOCSTRING" + method = self._callFUT(foo) self.assertEqual(method.getName(), 'foo') self.assertEqual(method.getDoc(), 'DOCSTRING') @@ -2597,6 +2777,7 @@ def foo(): self.assertEqual(info['varargs'], None) self.assertEqual(info['kwargs'], None) + class DummyDependent: def __init__(self): @@ -2618,6 +2799,7 @@ def _barGreaterThanFoo(obj): if not bar > foo: raise Invalid('Please, Boo MUST be greater than Foo!') + def _ifFooThenBar(obj): from zope.interface.exceptions import Invalid if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None): @@ -2639,6 +2821,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): for key, value in self.to_restore.items(): setattr(self.module, key, value) + class TestTypeAnnotations(unittest.TestCase): """Test using Interfaces in type annotations.""" @@ -2647,14 +2830,16 @@ def test___or__(self): from typing import Union from zope.interface import Interface + class I1(Interface): pass + class I2(Interface): pass class B: - a: I1|None - b: I1|I2 + a: I1 | None + b: I1 | I2 self.assertEqual( B.__annotations__, {'a': Optional[I1], 'b': Union[I1, I2]}) @@ -2664,6 +2849,7 @@ def test___ror__(self): from typing import Union from zope.interface import Interface + class I1(Interface): pass @@ -2671,8 +2857,8 @@ class A: pass class B: - a: None|I1 - b: A|I1 + a: None | I1 + b: A | I1 self.assertEqual( B.__annotations__, {'a': Optional[I1], 'b': Union[A, I1]}) diff --git a/src/zope/interface/tests/test_interfaces.py b/src/zope/interface/tests/test_interfaces.py index cc1273a2..6c41d494 100644 --- a/src/zope/interface/tests/test_interfaces.py +++ b/src/zope/interface/tests/test_interfaces.py @@ -125,4 +125,6 @@ def test_class_consistent__iro__(self): from zope.interface import implementedBy from zope.interface import ro - self.assertTrue(ro.is_consistent(implementedBy(self._getTargetClass()))) + self.assertTrue( + ro.is_consistent(implementedBy(self._getTargetClass())) + ) diff --git a/src/zope/interface/tests/test_odd_declarations.py b/src/zope/interface/tests/test_odd_declarations.py index b92015f5..c1e7df0d 100644 --- a/src/zope/interface/tests/test_odd_declarations.py +++ b/src/zope/interface/tests/test_odd_declarations.py @@ -29,19 +29,39 @@ from zope.interface.tests import odd -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 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 +class B(Odd): + __implemented__ = I2 # TODO: We are going to need more magic to make classProvides work with odd @@ -51,10 +71,15 @@ class B(Odd): __implemented__ = I2 # from zope.interface import classProvides class A(Odd): pass + + classImplements(A, I1) + class C(A, B): pass + + classImplements(C, I31) @@ -98,12 +123,15 @@ class D(COnly): self.assertTrue(providedBy(c).extends(I31)) self.assertTrue(providedBy(c).extends(I5)) - class COnly(A, B): __implemented__ = I31 + class COnly(A, B): + __implemented__ = I31 + class D(COnly): pass - classImplements(D, I5) classImplements(D, I5) + classImplements(D, I5) + c = D() directlyProvides(c, I4) self.assertEqual([i.getName() for i in providedBy(c)], @@ -129,14 +157,17 @@ class B(Odd): 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 @@ -147,16 +178,25 @@ class B(Odd): 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 IA1(Interface): + pass + + class IA2(Interface): + pass + + class IB(Interface): + pass + + class IC(Interface): + pass + class A(Odd): pass classImplements(A, IA1, IA2) @@ -169,7 +209,6 @@ class C(A, B): pass classImplements(C, IC) - ob = C() directlyProvides(ob, I1, I2) self.assertTrue(I1 in providedBy(ob)) @@ -179,7 +218,7 @@ class C(A, B): self.assertTrue(IB in providedBy(ob)) self.assertTrue(IC in providedBy(ob)) - directlyProvides(ob, directlyProvidedBy(ob)-I2) + directlyProvides(ob, directlyProvidedBy(ob) - I2) self.assertTrue(I1 in providedBy(ob)) self.assertFalse(I2 in providedBy(ob)) self.assertFalse(I2 in providedBy(ob)) @@ -187,25 +226,30 @@ class C(A, B): 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 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 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)], @@ -216,7 +260,8 @@ def test_odd_metaclass_that_doesnt_subclass_type(self): # 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. + # This is used for testing support for ExtensionClass in new + # interfaces. class A: a = 1 diff --git a/src/zope/interface/tests/test_registry.py b/src/zope/interface/tests/test_registry.py index abdd9511..09b7621f 100644 --- a/src/zope/interface/tests/test_registry.py +++ b/src/zope/interface/tests/test_registry.py @@ -31,8 +31,10 @@ def _makeOne(self, name='test', *args, **kw): def _wrapEvents(self): from zope.interface import registry _events = [] + def _notify(*args, **kw): _events.append((args, kw)) + _monkey = _Monkey(registry, notify=_notify) return _monkey, _events @@ -79,14 +81,15 @@ def test_registerUtility_with_component_name(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import named - class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') @named('foo') class Foo: pass + foo = Foo() _info = 'info' @@ -111,6 +114,7 @@ def test_registerUtility_w_component(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -143,12 +147,15 @@ def test_registerUtility_w_factory(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' _to_reg = object() + def _factory(): return _to_reg + comp = self._makeOne() _monkey, _events = self._wrapEvents() with _monkey: @@ -167,6 +174,7 @@ def _factory(): self.assertTrue(event.object.factory is _factory) def test_registerUtility_no_provided_available(self): + class Foo: pass @@ -185,8 +193,10 @@ def test_registerUtility_wo_provided(self): class IFoo(InterfaceClass): pass + class Foo: pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -214,6 +224,7 @@ def test_registerUtility_duplicates_existing_reg(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -230,6 +241,7 @@ def test_registerUtility_w_different_info(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info1 = 'info1' _info2 = 'info2' @@ -251,6 +263,7 @@ def test_registerUtility_w_different_names_same_component(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -278,6 +291,7 @@ def test_registerUtility_replaces_existing_reg(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -316,6 +330,7 @@ def test_registerUtility_w_existing_subscr(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -333,6 +348,7 @@ def test_registerUtility_wo_event(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -348,11 +364,14 @@ def test_registerUtility_changes_object_identity_after(self): # the cache is updated and the right thing still happens. class CompThatChangesAfter1Reg(self._getTargetClass()): reg_count = 0 + def registerUtility(self, *args): self.reg_count += 1 super().registerUtility(*args) if self.reg_count == 1: - self._utility_registrations = dict(self._utility_registrations) + self._utility_registrations = dict( + self._utility_registrations + ) comp = CompThatChangesAfter1Reg() comp.registerUtility(object(), Interface) @@ -370,10 +389,13 @@ def test_registerUtility_changes_object_identity_before(self): # the cache is updated and the right thing still happens. class CompThatChangesAfter2Reg(self._getTargetClass()): reg_count = 0 + def registerUtility(self, *args): self.reg_count += 1 if self.reg_count == 2: - self._utility_registrations = dict(self._utility_registrations) + self._utility_registrations = dict( + self._utility_registrations + ) super().registerUtility(*args) @@ -388,15 +410,13 @@ class IFoo(Interface): comp.registerUtility(object(), IFoo) self.assertEqual(len(list(comp.registeredUtilities())), 2) - class IBar(Interface): pass comp.registerUtility(object(), IBar) self.assertEqual(len(list(comp.registeredUtilities())), 3) - - def test_unregisterUtility_neither_factory_nor_component_nor_provided(self): + def test_unregisterUtility_wo_factory_nor_component_nor_provided(self): comp = self._makeOne() self.assertRaises(TypeError, comp.unregisterUtility, component=None, provided=None, factory=None) @@ -414,6 +434,7 @@ def test_unregisterUtility_w_component_miss(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _name = 'name' _to_reg = object() @@ -431,6 +452,7 @@ def test_unregisterUtility_w_component(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _name = 'name' _to_reg = object() @@ -440,7 +462,7 @@ class IFoo(InterfaceClass): with _monkey: unreg = comp.unregisterUtility(_to_reg, ifoo, _name) self.assertTrue(unreg) - self.assertFalse(comp.utilities._adapters) # all erased + self.assertFalse(comp.utilities._adapters) # all erased self.assertFalse((ifoo, _name) in comp._utility_registrations) self.assertFalse(comp.utilities._subscribers) self.assertEqual(len(_events), 1) @@ -462,12 +484,15 @@ def test_unregisterUtility_w_factory(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' _to_reg = object() + def _factory(): return _to_reg + comp = self._makeOne() comp.registerUtility(None, ifoo, _name, _info, factory=_factory) _monkey, _events = self._wrapEvents() @@ -494,8 +519,10 @@ def test_unregisterUtility_wo_explicit_provided(self): class IFoo(InterfaceClass): pass + class Foo: pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -528,8 +555,10 @@ def test_unregisterUtility_wo_component_or_factory(self): class IFoo(InterfaceClass): pass + class Foo: pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' @@ -560,6 +589,7 @@ def test_unregisterUtility_w_existing_subscr(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -578,6 +608,7 @@ def test_unregisterUtility_w_existing_subscr_non_hashable(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -591,7 +622,7 @@ class IFoo(InterfaceClass): comp.unregisterUtility(_to_reg, ifoo, _name2) self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_to_reg,)) - def test_unregisterUtility_w_existing_subscr_non_hashable_fresh_cache(self): + def test_unregisterUtility_w_existing_subs_non_hashable_fresh_cache(self): # We correctly populate the cache of registrations if it has gone away # (for example, the Components was unpickled) from zope.interface.declarations import InterfaceClass @@ -599,6 +630,7 @@ def test_unregisterUtility_w_existing_subscr_non_hashable_fresh_cache(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -614,12 +646,13 @@ class IFoo(InterfaceClass): self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_to_reg,)) def test_unregisterUtility_w_existing_subscr_non_hashable_reinitted(self): - # We correctly populate the cache of registrations if the base objects change - # out from under us + # We correctly populate the cache of registrations if the base objects + # change out from under us from zope.interface.declarations import InterfaceClass class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -645,6 +678,7 @@ def test_unregisterUtility_w_existing_subscr_other_component(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -660,11 +694,12 @@ class IFoo(InterfaceClass): self.assertEqual(comp.utilities._subscribers[0][ifoo][''], (_other_reg,)) - def test_unregisterUtility_w_existing_subscr_other_component_mixed_hash(self): + def test_unregisterUtility_w_existing_subscr_oter_comp_mixed_hash(self): from zope.interface.declarations import InterfaceClass class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -689,8 +724,10 @@ def test_registeredUtilities_empty(self): def test_registeredUtilities_notempty(self): from zope.interface.declarations import InterfaceClass from zope.interface.registry import UtilityRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name1 = 'name1' @@ -718,16 +755,20 @@ class IFoo(InterfaceClass): def test_queryUtility_miss_no_default(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertTrue(comp.queryUtility(ifoo) is None) def test_queryUtility_miss_w_default(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() _default = object() @@ -735,8 +776,10 @@ class IFoo(InterfaceClass): def test_queryUtility_hit(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _to_reg = object() comp = self._makeOne() @@ -746,16 +789,20 @@ class IFoo(InterfaceClass): def test_getUtility_miss(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertRaises(ComponentLookupError, comp.getUtility, ifoo) def test_getUtility_hit(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _to_reg = object() comp = self._makeOne() @@ -764,8 +811,10 @@ class IFoo(InterfaceClass): def test_getUtilitiesFor_miss(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertEqual(list(comp.getUtilitiesFor(ifoo)), []) @@ -775,6 +824,7 @@ def test_getUtilitiesFor_hit(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _name1 = 'name1' _name2 = 'name2' @@ -787,8 +837,10 @@ class IFoo(InterfaceClass): def test_getAllUtilitiesRegisteredFor_miss(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertEqual(list(comp.getAllUtilitiesRegisteredFor(ifoo)), []) @@ -798,6 +850,7 @@ def test_getAllUtilitiesRegisteredFor_hit(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _name1 = 'name1' _name2 = 'name2' @@ -812,9 +865,9 @@ def test_registerAdapter_with_component_name(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import named - class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') @@ -837,6 +890,7 @@ def test_registerAdapter_w_explicit_provided_and_required(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' @@ -890,11 +944,11 @@ def test_registerAdapter_wo_explicit_provided(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' _name = 'name' - _to_reg = object() @implementer(ifoo) class _Factory: @@ -926,12 +980,14 @@ def test_registerAdapter_no_required_available(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' + class _Factory: - pass + pass comp = self._makeOne() self.assertRaises(TypeError, comp.registerAdapter, _Factory, @@ -942,12 +998,15 @@ def test_registerAdapter_w_invalid_required(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' _name = 'name' + class _Factory: pass + comp = self._makeOne() self.assertRaises(TypeError, comp.registerAdapter, _Factory, ibar, provided=ifoo, name=_name, info=_info) @@ -960,20 +1019,26 @@ def test_registerAdapter_w_required_containing_None(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' + class _Factory: pass + comp = self._makeOne() _monkey, _events = self._wrapEvents() with _monkey: comp.registerAdapter(_Factory, [None], provided=ifoo, name=_name, info=_info) - self.assertTrue(comp.adapters._adapters[1][Interface][ifoo][_name] - is _Factory) - self.assertEqual(comp._adapter_registrations[(Interface,), ifoo, _name], - (_Factory, _info)) + self.assertTrue( + comp.adapters._adapters[1][Interface][ifoo][_name] is _Factory + ) + self.assertEqual( + comp._adapter_registrations[(Interface,), ifoo, _name], + (_Factory, _info) + ) self.assertEqual(len(_events), 1) args, kw = _events[0] event, = args @@ -996,26 +1061,32 @@ def test_registerAdapter_w_required_containing_class(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' _name = 'name' + class _Factory: pass @implementer(ibar) class _Context: pass + _ctx_impl = implementedBy(_Context) comp = self._makeOne() _monkey, _events = self._wrapEvents() with _monkey: comp.registerAdapter(_Factory, [_Context], provided=ifoo, name=_name, info=_info) - self.assertTrue(comp.adapters._adapters[1][_ctx_impl][ifoo][_name] - is _Factory) - self.assertEqual(comp._adapter_registrations[(_ctx_impl,), ifoo, _name], - (_Factory, _info)) + self.assertTrue( + comp.adapters._adapters[1][_ctx_impl][ifoo][_name] is _Factory + ) + self.assertEqual( + comp._adapter_registrations[(_ctx_impl,), ifoo, _name], + (_Factory, _info) + ) self.assertEqual(len(_events), 1) args, kw = _events[0] event, = args @@ -1034,15 +1105,20 @@ def test_registerAdapter_w_required_containing_junk(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _name = 'name' + class _Factory: pass + comp = self._makeOne() - self.assertRaises(TypeError, comp.registerAdapter, _Factory, [object()], - provided=ifoo, name=_name, info=_info) + with self.assertRaises(TypeError): + comp.registerAdapter( + _Factory, [object()], provided=ifoo, name=_name, info=_info, + ) def test_registerAdapter_wo_explicit_required(self): from zope.interface.declarations import InterfaceClass @@ -1051,10 +1127,12 @@ def test_registerAdapter_wo_explicit_required(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' _name = 'name' + class _Factory: __component_adapts__ = (ibar,) @@ -1085,6 +1163,7 @@ def test_registerAdapter_wo_event(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' @@ -1106,8 +1185,10 @@ def test_unregisterAdapter_neither_factory_nor_provided(self): def test_unregisterAdapter_neither_factory_nor_required(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertRaises(TypeError, comp.unregisterAdapter, @@ -1115,10 +1196,13 @@ class IFoo(InterfaceClass): def test_unregisterAdapter_miss(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: pass @@ -1132,10 +1216,13 @@ def test_unregisterAdapter_hit_w_explicit_provided_and_required(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: pass @@ -1165,10 +1252,13 @@ def test_unregisterAdapter_wo_explicit_provided(self): from zope.interface.declarations import implementer from zope.interface.interfaces import Unregistered from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + @implementer(ifoo) class _Factory: pass @@ -1196,10 +1286,13 @@ def test_unregisterAdapter_wo_explicit_required(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: __component_adapts__ = (ibar,) @@ -1229,13 +1322,16 @@ def test_registeredAdapters_empty(self): def test_registeredAdapters_notempty(self): from zope.interface.declarations import InterfaceClass from zope.interface.registry import AdapterRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IFoo') _info = 'info' _name1 = 'name1' _name2 = 'name2' + class _Factory: pass @@ -1261,8 +1357,10 @@ class _Factory: def test_queryAdapter_miss_no_default(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() _context = object() @@ -1270,8 +1368,10 @@ class IFoo(InterfaceClass): def test_queryAdapter_miss_w_default(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() _context = object() @@ -1282,16 +1382,21 @@ class IFoo(InterfaceClass): def test_queryAdapter_hit(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: def __init__(self, context): self.context = context + @implementer(ibar) class _Context: pass + _context = _Context() comp = self._makeOne() comp.registerAdapter(_Factory, (ibar,), ifoo) @@ -1303,13 +1408,17 @@ def test_getAdapter_miss(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + @implementer(ibar) class _Context: pass + _context = _Context() comp = self._makeOne() self.assertRaises(ComponentLookupError, @@ -1318,16 +1427,21 @@ class _Context: def test_getAdapter_hit(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: def __init__(self, context): self.context = context + @implementer(ibar) class _Context: pass + _context = _Context() comp = self._makeOne() comp.registerAdapter(_Factory, (ibar,), ifoo) @@ -1379,7 +1493,7 @@ def __init__(self, context): self.assertIsInstance(adapter, AdapterBase) self.assertIs(adapter.context, derived) - def test_getAdapter_hit_super_when_parent_implements_interface_diamond(self): + def test_getAdapter_hit_super_w_parent_implements_interface_diamond(self): from zope.interface import Interface from zope.interface.declarations import implementer @@ -1432,17 +1546,21 @@ def __init__(self, context): def test_queryMultiAdapter_miss(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() comp = self._makeOne() @@ -1452,17 +1570,22 @@ class _Context2: def test_queryMultiAdapter_miss_w_default(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() _default = object() @@ -1474,22 +1597,29 @@ class _Context2: def test_queryMultiAdapter_hit(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() + class _Factory: def __init__(self, context1, context2): self.context = context1, context2 + comp = self._makeOne() comp.registerAdapter(_Factory, (ibar, ibaz), ifoo) adapter = comp.queryMultiAdapter((_context1, _context2), ifoo) @@ -1500,17 +1630,22 @@ def test_getMultiAdapter_miss(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer from zope.interface.interfaces import ComponentLookupError + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() comp = self._makeOne() @@ -1520,22 +1655,29 @@ class _Context2: def test_getMultiAdapter_hit(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() + class _Factory: def __init__(self, context1, context2): self.context = context1, context2 + comp = self._makeOne() comp.registerAdapter(_Factory, (ibar, ibaz), ifoo) adapter = comp.getMultiAdapter((_context1, _context2), ifoo) @@ -1602,17 +1744,22 @@ class AdapterDerived(AdapterBase): def test_getAdapters_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() comp = self._makeOne() @@ -1622,24 +1769,31 @@ class _Context2: def test_getAdapters_factory_returns_None(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() comp = self._makeOne() _called_with = [] + def _side_effect_only(context1, context2): _called_with.append((context1, context2)) return None + comp.registerAdapter(_side_effect_only, (ibar, ibaz), ifoo) self.assertEqual( list(comp.getAdapters((_context1, _context2), ifoo)), []) @@ -1651,23 +1805,30 @@ def test_getAdapters_non_empty(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') ibaz = IFoo('IBaz') + @implementer(ibar) class _Context1: pass + @implementer(ibaz) class _Context2: pass + _context1 = _Context1() _context2 = _Context2() + class _Factory1: def __init__(self, context1, context2): self.context = context1, context2 + class _Factory2: def __init__(self, context1, context2): self.context = context1, context2 + _name1 = 'name1' _name2 = 'name2' comp = self._makeOne() @@ -1685,10 +1846,12 @@ def test_registerSubscriptionAdapter_w_nonblank_name(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _name = 'name' _info = 'info' + def _factory(context): raise NotImplementedError() @@ -1696,19 +1859,22 @@ def _factory(context): self.assertRaises(TypeError, comp.registerSubscriptionAdapter, _factory, (ibar,), ifoo, _name, _info) - def test_registerSubscriptionAdapter_w_explicit_provided_and_required(self): + def test_registerSubscriptionAdapter_w_explicit_provided_n_required(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Registered from zope.interface.registry import SubscriptionRegistration class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _blank = '' _info = 'info' + def _factory(context): raise NotImplementedError() + comp = self._makeOne() _monkey, _events = self._wrapEvents() with _monkey: @@ -1740,6 +1906,7 @@ def test_registerSubscriptionAdapter_wo_explicit_provided(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' @@ -1778,10 +1945,12 @@ def test_registerSubscriptionAdapter_wo_explicit_required(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _info = 'info' _blank = '' + class _Factory: __component_adapts__ = (ibar,) @@ -1789,7 +1958,8 @@ class _Factory: _monkey, _events = self._wrapEvents() with _monkey: comp.registerSubscriptionAdapter( - _Factory, provided=ifoo, info=_info) + _Factory, provided=ifoo, info=_info, + ) reg = comp.adapters._subscribers[1][ibar][ifoo][_blank] self.assertEqual(len(reg), 1) self.assertTrue(reg[0] is _Factory) @@ -1813,9 +1983,9 @@ def test_registerSubscriptionAdapter_wo_event(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') - _blank = '' _info = 'info' def _factory(context): @@ -1835,12 +2005,15 @@ def test_registeredSubscriptionAdapters_empty(self): def test_registeredSubscriptionAdapters_notempty(self): from zope.interface.declarations import InterfaceClass from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IFoo') _info = 'info' _blank = '' + class _Factory: pass @@ -1869,6 +2042,7 @@ def test_unregisterSubscriptionAdapter_w_nonblank_name(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') _nonblank = 'nonblank' @@ -1883,8 +2057,10 @@ def test_unregisterSubscriptionAdapter_neither_factory_nor_provided(self): def test_unregisterSubscriptionAdapter_neither_factory_nor_required(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() self.assertRaises(TypeError, comp.unregisterSubscriptionAdapter, @@ -1892,10 +2068,13 @@ class IFoo(InterfaceClass): def test_unregisterSubscriptionAdapter_miss(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: pass @@ -1910,10 +2089,13 @@ def test_unregisterSubscriptionAdapter_hit_wo_factory(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: pass @@ -1942,10 +2124,13 @@ def test_unregisterSubscriptionAdapter_hit_w_factory(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: pass @@ -1975,10 +2160,13 @@ def test_unregisterSubscriptionAdapter_wo_explicit_provided(self): from zope.interface.declarations import implementer from zope.interface.interfaces import Unregistered from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + @implementer(ifoo) class _Factory: pass @@ -2006,10 +2194,13 @@ def test_unregisterSubscriptionAdapter_wo_explicit_required(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import SubscriptionRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: __component_adapts__ = (ibar,) @@ -2035,40 +2226,54 @@ class _Factory: def test_subscribers_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') comp = self._makeOne() + @implementer(ibar) class Bar: pass + bar = Bar() self.assertEqual(list(comp.subscribers((bar,), ifoo)), []) def test_subscribers_non_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Factory: __component_adapts__ = (ibar,) + def __init__(self, context): self._context = context + class _Derived(_Factory): pass + comp = self._makeOne() comp.registerSubscriptionAdapter(_Factory, (ibar,), ifoo) comp.registerSubscriptionAdapter(_Derived, (ibar,), ifoo) + @implementer(ibar) class Bar: pass + bar = Bar() subscribers = comp.subscribers((bar,), ifoo) + def _klassname(x): return x.__class__.__name__ + subscribers = sorted(subscribers, key=_klassname) self.assertEqual(len(subscribers), 2) self.assertTrue(isinstance(subscribers[0], _Derived)) @@ -2079,9 +2284,11 @@ def test_registerHandler_w_nonblank_name(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _nonblank = 'nonblank' comp = self._makeOne() + def _factory(context): raise NotImplementedError() @@ -2095,9 +2302,11 @@ def test_registerHandler_w_explicit_required(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _blank = '' _info = 'info' + def _factory(context): raise NotImplementedError() @@ -2127,9 +2336,11 @@ def test_registerHandler_wo_explicit_required_no_event(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _info = 'info' _blank = '' + class _Factory: __component_adapts__ = (ifoo,) pass @@ -2152,18 +2363,25 @@ def test_registeredHandlers_empty(self): def test_registeredHandlers_non_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') + def _factory1(context): raise NotImplementedError() + def _factory2(context): raise NotImplementedError() + comp = self._makeOne() comp.registerHandler(_factory1, (ifoo,)) comp.registerHandler(_factory2, (ifoo,)) + def _factory_name(x): return x.factory.__code__.co_name + subscribers = sorted(comp.registeredHandlers(), key=_factory_name) self.assertEqual(len(subscribers), 2) self.assertTrue(isinstance(subscribers[0], HandlerRegistration)) @@ -2182,6 +2400,7 @@ def test_unregisterHandler_w_nonblank_name(self): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _nonblank = 'nonblank' comp = self._makeOne() @@ -2194,8 +2413,10 @@ def test_unregisterHandler_neither_factory_nor_required(self): def test_unregisterHandler_miss(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() unreg = comp.unregisterHandler(required=(ifoo,)) @@ -2205,12 +2426,16 @@ def test_unregisterHandler_hit_w_factory_and_explicit_provided(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() + def _factory(context): raise NotImplementedError() + comp = self._makeOne() comp.registerHandler(_factory, (ifoo,)) _monkey, _events = self._wrapEvents() @@ -2232,12 +2457,16 @@ def test_unregisterHandler_hit_w_only_explicit_provided(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() + def _factory(context): raise NotImplementedError() + comp = self._makeOne() comp.registerHandler(_factory, (ifoo,)) _monkey, _events = self._wrapEvents() @@ -2259,9 +2488,12 @@ def test_unregisterHandler_wo_explicit_required(self): from zope.interface.declarations import InterfaceClass from zope.interface.interfaces import Unregistered from zope.interface.registry import HandlerRegistration + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') + class _Factory: __component_adapts__ = (ifoo,) @@ -2286,40 +2518,54 @@ class _Factory: def test_handle_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') comp = self._makeOne() + @implementer(ifoo) class Bar: pass + bar = Bar() - comp.handle((bar,)) # doesn't raise + comp.handle((bar,)) # doesn't raise def test_handle_non_empty(self): from zope.interface.declarations import InterfaceClass from zope.interface.declarations import implementer + class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') _called_1 = [] + def _factory_1(context): - _called_1.append(context) + _called_1.append(context) + _called_2 = [] + def _factory_2(context): - _called_2.append(context) + _called_2.append(context) + comp = self._makeOne() comp.registerHandler(_factory_1, (ifoo,)) comp.registerHandler(_factory_2, (ifoo,)) + @implementer(ifoo) class Bar: pass + bar = Bar() comp.handle(bar) self.assertEqual(_called_1, [bar]) self.assertEqual(_called_2, [bar]) - def test_register_unregister_identical_objects_provided(self, identical=True): + def test_register_unregister_identical_objects_provided( + self, identical=True, + ): # https://github.com/zopefoundation/zope.interface/issues/227 class IFoo(Interface): pass @@ -2348,9 +2594,12 @@ class IFoo(Interface): self.assertEqual(len(comp.utilities._subscribers), 0) def test_register_unregister_nonequal_objects_provided(self): - self.test_register_unregister_identical_objects_provided(identical=False) + self.test_register_unregister_identical_objects_provided( + identical=False, + ) def test_rebuildUtilityRegistryFromLocalCache(self): + class IFoo(Interface): "Does nothing" @@ -2360,7 +2609,9 @@ class UtilityImplementingFoo: comps = self._makeOne() for i in range(30): - comps.registerUtility(UtilityImplementingFoo(), IFoo, name='{}'.format(i)) + comps.registerUtility( + UtilityImplementingFoo(), IFoo, name='{}'.format(i) + ) orig_generation = comps.utilities._generation @@ -2385,21 +2636,21 @@ class UtilityImplementingFoo: self.assertNotEqual(orig_adapters, new_adapters) - new_subscribers = comps.utilities._subscribers = type(orig_subscribers)() - new_subscribers.append({}) - d = new_subscribers[0][IFoo] = {} + new_subs = comps.utilities._subscribers = type(orig_subscribers)() + new_subs.append({}) + d = new_subs[0][IFoo] = {} d[''] = () - for name in range(5, 12): # 12 - 5 = 7 + for name in range(5, 12): # 12 - 5 = 7 name = str(str(name)) comp = orig_adapters[0][IFoo][name] d[''] += (comp,) # We can preflight (by default) and nothing changes - rebuild_results_preflight = comps.rebuildUtilityRegistryFromLocalCache() + rebuild_preflight = comps.rebuildUtilityRegistryFromLocalCache() self.assertEqual(comps.utilities._generation, orig_generation) - self.assertEqual(rebuild_results_preflight, { + self.assertEqual(rebuild_preflight, { 'did_not_register': 10, 'needed_registered': 20, @@ -2408,19 +2659,21 @@ class UtilityImplementingFoo: }) # Now for real - rebuild_results = comps.rebuildUtilityRegistryFromLocalCache(rebuild=True) + rebuild_results = comps.rebuildUtilityRegistryFromLocalCache( + rebuild=True, + ) # The generation only got incremented once self.assertEqual(comps.utilities._generation, orig_generation + 1) # The result was the same - self.assertEqual(rebuild_results_preflight, rebuild_results) + self.assertEqual(rebuild_preflight, rebuild_results) self.assertEqual(new_adapters, orig_adapters) self.assertEqual( - len(new_subscribers[0][IFoo]['']), + len(new_subs[0][IFoo]['']), len(orig_subscribers[0][IFoo][''])) for orig_subscriber in orig_subscribers[0][IFoo]['']: - self.assertIn(orig_subscriber, new_subscribers[0][IFoo]['']) + self.assertIn(orig_subscriber, new_subs[0][IFoo]['']) # Preflighting, rebuilding again produce no changes. preflight_after = comps.rebuildUtilityRegistryFromLocalCache() @@ -2432,7 +2685,9 @@ class UtilityImplementingFoo: 'needed_subscribed': 0, }) - rebuild_after = comps.rebuildUtilityRegistryFromLocalCache(rebuild=True) + rebuild_after = comps.rebuildUtilityRegistryFromLocalCache( + rebuild=True, + ) self.assertEqual(rebuild_after, preflight_after) self.assertEqual(comps.utilities._generation, orig_generation + 1) @@ -2442,8 +2697,12 @@ class UnhashableComponentsTests(ComponentsTests): def _getTargetClass(self): # Mimic what pyramid does to create an unhashable # registry - class Components(super(UnhashableComponentsTests, self)._getTargetClass(), dict): + + class Components( + super(UnhashableComponentsTests, self)._getTargetClass(), dict, + ): pass + return Components # Test _getUtilityProvided, _getAdapterProvided, _getAdapterRequired via their @@ -2463,17 +2722,20 @@ class InterfaceClassSubclass(InterfaceClass): pass ifoo = InterfaceClassSubclass('IFoo') + class _Registry: def __repr__(self): return '_REGISTRY' + registry = _Registry() name = 'name' doc = 'DOCSTRING' klass = self._getTargetClass() - return (klass(registry, ifoo, name, component, doc, factory), - registry, - name, - ) + return ( + klass(registry, ifoo, name, component, doc, factory), + registry, + name, + ) def test_class_conforms_to_IUtilityRegistration(self): from zope.interface.interfaces import IUtilityRegistration @@ -2483,39 +2745,54 @@ def test_class_conforms_to_IUtilityRegistration(self): def test_instance_conforms_to_IUtilityRegistration(self): from zope.interface.interfaces import IUtilityRegistration from zope.interface.verify import verifyObject - ur, _, _ = self._makeOne() + ur, _, _ = self._makeOne() verifyObject(IUtilityRegistration, ur) def test___repr__(self): + class _Component: __name__ = 'TEST' + _component = _Component() ur, _registry, _name = self._makeOne(_component) - self.assertEqual(repr(ur), - "UtilityRegistration(_REGISTRY, IFoo, %r, TEST, None, 'DOCSTRING')" - % (_name)) + self.assertEqual( + repr(ur), ( + "UtilityRegistration(" + "_REGISTRY, IFoo, %r, TEST, None, 'DOCSTRING')" + ) % (_name) + ) def test___repr___provided_wo_name(self): + class _Component: def __repr__(self): return 'TEST' + _component = _Component() ur, _registry, _name = self._makeOne(_component) ur.provided = object() - self.assertEqual(repr(ur), - "UtilityRegistration(_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" - % (_name)) + self.assertEqual( + repr(ur), ( + "UtilityRegistration(" + "_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" + ) % (_name) + ) def test___repr___component_wo_name(self): + class _Component: def __repr__(self): return 'TEST' + _component = _Component() ur, _registry, _name = self._makeOne(_component) ur.provided = object() - self.assertEqual(repr(ur), - "UtilityRegistration(_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" - % (_name)) + self.assertEqual( + repr(ur), ( + "UtilityRegistration(" + "_REGISTRY, None, %r, TEST, None, 'DOCSTRING')" + ) % (_name) + ) def test___hash__(self): _component = object() @@ -2647,19 +2924,23 @@ def _makeOne(self, component=None): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Registry: def __repr__(self): return '_REGISTRY' + registry = _Registry() name = 'name' doc = 'DOCSTRING' klass = self._getTargetClass() - return (klass(registry, (ibar,), ifoo, name, component, doc), - registry, - name, - ) + return ( + klass(registry, (ibar,), ifoo, name, component, doc), + registry, + name, + ) def test_class_conforms_to_IAdapterRegistration(self): from zope.interface.interfaces import IAdapterRegistration @@ -2669,39 +2950,54 @@ def test_class_conforms_to_IAdapterRegistration(self): def test_instance_conforms_to_IAdapterRegistration(self): from zope.interface.interfaces import IAdapterRegistration from zope.interface.verify import verifyObject - ar, _, _ = self._makeOne() + ar, _, _ = self._makeOne() verifyObject(IAdapterRegistration, ar) def test___repr__(self): + class _Component: __name__ = 'TEST' + _component = _Component() ar, _registry, _name = self._makeOne(_component) - self.assertEqual(repr(ar), - ("AdapterRegistration(_REGISTRY, [IBar], IFoo, %r, TEST, " - + "'DOCSTRING')") % (_name)) + self.assertEqual( + repr(ar), ( + "AdapterRegistration(_REGISTRY, [IBar], IFoo, %r, TEST, " + "'DOCSTRING')" + ) % (_name) + ) def test___repr___provided_wo_name(self): + class _Component: def __repr__(self): return 'TEST' + _component = _Component() ar, _registry, _name = self._makeOne(_component) ar.provided = object() - self.assertEqual(repr(ar), - ("AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " - + "'DOCSTRING')") % (_name)) + self.assertEqual( + repr(ar), ( + "AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " + "'DOCSTRING')" + ) % (_name) + ) def test___repr___component_wo_name(self): + class _Component: def __repr__(self): return 'TEST' + _component = _Component() ar, _registry, _name = self._makeOne(_component) ar.provided = object() - self.assertEqual(repr(ar), - ("AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " - + "'DOCSTRING')") % (_name)) + self.assertEqual( + repr(ar), ( + "AdapterRegistration(_REGISTRY, [IBar], None, %r, TEST, " + "'DOCSTRING')" + ) % (_name) + ) def test___hash__(self): _component = object() @@ -2746,8 +3042,10 @@ def test___ne___hit_component(self): def test___ne___hit_provided(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ibaz = IFoo('IBaz') _component = object() ar, _registry, _name = self._makeOne(_component) @@ -2757,8 +3055,10 @@ class IFoo(InterfaceClass): def test___ne___hit_required(self): from zope.interface.declarations import InterfaceClass + class IFoo(InterfaceClass): pass + ibaz = IFoo('IBaz') _component = object() _component2 = object() @@ -2856,19 +3156,23 @@ def _makeOne(self, component=None): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') ibar = IFoo('IBar') + class _Registry: - def __repr__(self): # pragma: no cover + def __repr__(self): # pragma: no cover return '_REGISTRY' + registry = _Registry() name = 'name' doc = 'DOCSTRING' klass = self._getTargetClass() - return (klass(registry, (ibar,), ifoo, name, component, doc), - registry, - name, - ) + return ( + klass(registry, (ibar,), ifoo, name, component, doc), + registry, + name, + ) def test_class_conforms_to_ISubscriptionAdapterRegistration(self): from zope.interface.interfaces import ISubscriptionAdapterRegistration @@ -2878,7 +3182,7 @@ def test_class_conforms_to_ISubscriptionAdapterRegistration(self): def test_instance_conforms_to_ISubscriptionAdapterRegistration(self): from zope.interface.interfaces import ISubscriptionAdapterRegistration from zope.interface.verify import verifyObject - sar, _, _ = self._makeOne() + sar, _, _ = self._makeOne() verifyObject(ISubscriptionAdapterRegistration, sar) @@ -2893,18 +3197,22 @@ def _makeOne(self, component=None): class IFoo(InterfaceClass): pass + ifoo = IFoo('IFoo') + class _Registry: def __repr__(self): return '_REGISTRY' + registry = _Registry() name = 'name' doc = 'DOCSTRING' klass = self._getTargetClass() - return (klass(registry, (ifoo,), name, component, doc), - registry, - name, - ) + return ( + klass(registry, (ifoo,), name, component, doc), + registry, + name, + ) def test_class_conforms_to_IHandlerRegistration(self): from zope.interface.interfaces import IHandlerRegistration @@ -2914,33 +3222,43 @@ def test_class_conforms_to_IHandlerRegistration(self): def test_instance_conforms_to_IHandlerRegistration(self): from zope.interface.interfaces import IHandlerRegistration from zope.interface.verify import verifyObject - hr, _, _ = self._makeOne() + hr, _, _ = self._makeOne() verifyObject(IHandlerRegistration, hr) def test_properties(self): def _factory(context): raise NotImplementedError() - hr, _, _ = self._makeOne(_factory) + hr, _, _ = self._makeOne(_factory) self.assertTrue(hr.handler is _factory) self.assertTrue(hr.factory is hr.handler) self.assertTrue(hr.provided is None) def test___repr___factory_w_name(self): + class _Factory: __name__ = 'TEST' - hr, _registry, _name = self._makeOne(_Factory()) - self.assertEqual(repr(hr), - ("HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " - + "'DOCSTRING')") % (_name)) + + hr, _registry, _name = self._makeOne(_Factory()) + self.assertEqual( + repr(hr), ( + "HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " + "'DOCSTRING')" + ) % (_name)) def test___repr___factory_wo_name(self): + class _Factory: def __repr__(self): return 'TEST' - hr, _registry, _name = self._makeOne(_Factory()) - self.assertEqual(repr(hr), - ("HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " - + "'DOCSTRING')") % (_name)) + + hr, _registry, _name = self._makeOne(_Factory()) + self.assertEqual( + repr(hr), ( + "HandlerRegistration(_REGISTRY, [IFoo], %r, TEST, " + "'DOCSTRING')" + ) % (_name) + ) + class PersistentAdapterRegistry(VerifyingAdapterRegistry): @@ -2959,6 +3277,7 @@ def __setstate__(self, state): self.__bases__ = bases self._v_lookup.changed(self) + class PersistentComponents(Components): # Mimic zope.component.persistentregistry.PersistentComponents: # we should be picklalable, but not persistent.Persistent ourself. @@ -2967,6 +3286,7 @@ def _init_registries(self): self.adapters = PersistentAdapterRegistry() self.utilities = PersistentAdapterRegistry() + class PersistentDictComponents(PersistentComponents, dict): # Like Pyramid's Registry, we subclass Components and dict pass @@ -2978,6 +3298,7 @@ def __init__(self, name): dict.__init__(self) PersistentComponents.__init__(self, name) + class TestPersistentComponents(unittest.TestCase): def _makeOne(self): @@ -3035,11 +3356,13 @@ def _check_equality_after_pickle(self, made): self.assertIn('key', made) self.assertEqual(made['key'], 42) + class TestPersistentComponentsDict(TestPersistentDictComponents): def _getTargetClass(self): return PersistentComponentsDict + class _Monkey: # context-manager for replacing module names in the scope of a test. def __init__(self, module, **kw): diff --git a/src/zope/interface/tests/test_ro.py b/src/zope/interface/tests/test_ro.py index 49c46259..26376c64 100644 --- a/src/zope/interface/tests/test_ro.py +++ b/src/zope/interface/tests/test_ro.py @@ -15,7 +15,9 @@ import unittest -# pylint:disable=blacklisted-name,protected-access,attribute-defined-outside-init +# pylint:disable=blacklisted-name +# pylint:disable=protected-access +# pylint:disable=attribute-defined-outside-init class Test__mergeOrderings(unittest.TestCase): @@ -48,81 +50,108 @@ def _callFUT(self, ob): 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 + + def __repr__(self): # pragma: no cover return self.__name__ # Mimic what classImplements(IOError, IIOError) @@ -191,6 +220,7 @@ 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): @@ -205,17 +235,22 @@ def _callFUT(self, ob, **kwargs): def _make_complex_diamond(self, base): # https://github.com/zopefoundation/zope.interface/issues/21 - O = base - class F(O): + + class F(base): pass - class E(O): + + class E(base): pass - class D(O): + + class D(base): pass + class C(D, F): pass + class B(D, E): pass + class A(B, C): pass @@ -261,8 +296,8 @@ def _check_handler_complex_diamond(self): self.assertEqual(1, len(handler.records)) record = handler.records[0] - self.assertEqual('\n'.join(l.rstrip() for l in record.getMessage().splitlines()), """\ -Object has different legacy and C3 MROs: + expected = """\ +Object 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 @@ -272,10 +307,18 @@ def _check_handler_complex_diamond(self): 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""") + zope.interface.Interface zope.interface.Interface""".format( + name="zope.interface.tests.test_ro.A" + ) + + self.assertEqual( + '\n'.join(ln.rstrip() for ln in record.getMessage().splitlines()), + expected, + ) def test_ExtendedPathIndex_implement_thing_implementedby_super(self): - # See https://github.com/zopefoundation/zope.interface/pull/182#issuecomment-598754056 + # See + # https://github.com/zopefoundation/zope.interface/pull/182#issuecomment-598754056 from zope.interface import ro # pylint:disable=inherit-non-class @@ -316,12 +359,16 @@ class IPathIndex(Interface): # @implementer(ILimitedResultIndex, IQueryIndex) # class ExtendedPathIndex(PathIndex): # pass - ExtendedPathIndex = _Based('ExtendedPathIndex', - (ILimitedResultIndex, IQueryIndex, PathIndex)) + 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) + result = self._callFUT( + ExtendedPathIndex, log_changed_ro=True, strict=False + ) self.assertEqual(result, [ ExtendedPathIndex, ILimitedResultIndex, @@ -365,7 +412,11 @@ def test_non_orderable(self): with warnings.catch_warnings(): warnings.simplefilter('error') - with C3Setting(ro.C3.WARN_BAD_IRO, True), C3Setting(ro.C3.STRICT_IRO, False): + with C3Setting( + ro.C3.WARN_BAD_IRO, True + ), C3Setting( + ro.C3.STRICT_IRO, False + ): with self.assertRaises(ro.InconsistentResolutionOrderWarning): super().test_non_orderable() @@ -373,7 +424,11 @@ def test_non_orderable(self): 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 C3Setting( + ro.C3.TRACK_BAD_IRO, True + ), C3Setting( + ro.C3.STRICT_IRO, False + ): with warnings.catch_warnings(): warnings.simplefilter('ignore') self._callFUT(IOErr) @@ -390,7 +445,10 @@ def _makeOne(self, C, strict=False, base_mros=None): 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__}) + 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 @@ -400,7 +458,7 @@ 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 + self.assertIsNotNone(c3._C3__mro) # pylint:disable=no-member c3._merge = None self.assertEqual(c3.mro(), list(type(self).__mro__)) diff --git a/src/zope/interface/tests/test_sorting.py b/src/zope/interface/tests/test_sorting.py index 8c0df4c3..813d9d3f 100644 --- a/src/zope/interface/tests/test_sorting.py +++ b/src/zope/interface/tests/test_sorting.py @@ -19,33 +19,49 @@ 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 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]) + iface_list = [I1, I3, I5, I6, I4, I2] + iface_list.sort() + self.assertEqual(iface_list, [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]) + iface_list = [I1, None, I3, I5, I6, I4, I2] + iface_list.sort() + self.assertEqual(iface_list, [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]) + iface_list = [I1, m1_I1] + iface_list.sort() + self.assertEqual(iface_list, [m1_I1, I1]) def test_I1_I2(self): self.assertLess(I1.__name__, I2.__name__) @@ -54,8 +70,10 @@ def test_I1_I2(self): self.assertLess(I1, I2) def _makeI1(self): + class I1(Interface): pass + return I1 def test_nested(self): diff --git a/src/zope/interface/tests/test_verify.py b/src/zope/interface/tests/test_verify.py index 5080d025..046cb6a8 100644 --- a/src/zope/interface/tests/test_verify.py +++ b/src/zope/interface/tests/test_verify.py @@ -30,7 +30,8 @@ def _get_FUT(cls): from zope.interface.verify import verifyClass return verifyClass - _adjust_object_before_verify = lambda self, x: x + def _adjust_object_before_verify(self, x): + return x def _callFUT(self, iface, klass, **kwargs): return self.verifier(iface, @@ -403,7 +404,6 @@ def method(self, a, *args): self.assertRaises(BrokenMethodImplementation, self._callFUT, ICurrent, Current) - def test_method_doesnt_take_required_kwargs(self): from zope.interface import Interface from zope.interface import implementer @@ -423,7 +423,6 @@ def method(self, a): self.assertRaises(BrokenMethodImplementation, self._callFUT, ICurrent, Current) - def test_class_has_method_for_iface_attr(self): from zope.interface import Attribute from zope.interface import Interface @@ -508,7 +507,6 @@ class Current: self._callFUT(ICurrent, Current) - def test_w_decorated_method(self): from zope.interface import Interface from zope.interface import implementer @@ -551,7 +549,6 @@ def test_tuple_IReadSequence(self): from zope.interface.common.sequence import IReadSequence self._callFUT(IReadSequence, tuple, tentative=True) - def test_multiple_invalid(self): from zope.interface import Interface from zope.interface import classImplements @@ -577,14 +574,15 @@ class SeveralMethods: self.assertIsInstance(ex.exceptions[1], BrokenImplementation) self.assertIsInstance(ex.exceptions[2], BrokenImplementation) - # If everything else is correct, only the single error is raised without - # the wrapper. + # If everything else is correct, only the single error is raised + # without the wrapper. classImplements(SeveralMethods, ISeveralMethods) SeveralMethods.meth1 = lambda self, arg1: "Hi" with self.assertRaises(BrokenImplementation): self._callFUT(ISeveralMethods, SeveralMethods) + class Test_verifyObject(Test_verifyClass): @classmethod @@ -653,5 +651,6 @@ def bar(a, b): # class. verifyObject(IFoo, Foo) + class OldSkool: pass diff --git a/src/zope/interface/verify.py b/src/zope/interface/verify.py index 0894d2d2..5bee470b 100644 --- a/src/zope/interface/verify.py +++ b/src/zope/interface/verify.py @@ -45,10 +45,11 @@ def _verify(iface, candidate, tentative=False, vtype=None): This involves: - Making sure the candidate claims that it provides the - interface using ``iface.providedBy`` (unless *tentative* is `True`, - in which case this step is skipped). This means that the candidate's class - declares that it `implements ` the interface, - or the candidate itself declares that it `provides ` + interface using ``iface.providedBy`` (unless *tentative* is `True`, in + which case this step is skipped). This means that the candidate's class + declares that it `implements ` the + interface, or the candidate itself declares that it `provides + ` the interface - Making sure the candidate defines all the necessary methods @@ -65,9 +66,9 @@ def _verify(iface, candidate, tentative=False, vtype=None): .. versionchanged:: 5.0 If multiple methods or attributes are invalid, all such errors - are collected and reported. Previously, only the first error was reported. - As a special case, if only one such error is present, it is raised - alone, like before. + are collected and reported. Previously, only the first error was + reported. As a special case, if only one such error is present, it is + raised alone, like before. """ if vtype == 'c': @@ -92,15 +93,18 @@ def _verify(iface, candidate, tentative=False, vtype=None): return True + def _verify_element(iface, name, desc, candidate, vtype): # Here the `desc` is either an `Attribute` or `Method` instance try: attr = getattr(candidate, name) except AttributeError: + if (not isinstance(desc, Method)) and vtype == 'c': # We can't verify non-methods on classes, since the # class may provide attrs in it's __init__. return + # TODO: This should use ``raise...from`` raise BrokenImplementation(iface, desc, candidate) @@ -118,11 +122,13 @@ def _verify_element(iface, name, desc, candidate, vtype): # ValueError: no signature found. The ``__text_signature__`` attribute # isn't typically populated either. # - # Note that on PyPy 2 or 3 (up through 7.3 at least), these are - # not true for things like ``dict.pop`` (but might be true for C extensions?) + # Note that on PyPy 2 or 3 (up through 7.3 at least), these are not + # true for things like ``dict.pop`` (but might be true for C + # extensions?) return if isinstance(attr, FunctionType): + if isinstance(candidate, type) and vtype == 'c': # This is an "unbound method". # Only unwrap this if we're verifying implementedBy; @@ -132,9 +138,13 @@ def _verify_element(iface, name, desc, candidate, vtype): else: # Nope, just a normal function meth = fromFunction(attr, iface, name=name) - elif (isinstance(attr, MethodTypes) - and type(attr.__func__) is FunctionType): + + elif ( + isinstance(attr, MethodTypes) and + type(attr.__func__) is FunctionType + ): meth = fromMethod(attr, iface, name) + elif isinstance(attr, property) and vtype == 'c': # Without an instance we cannot be sure it's not a # callable. @@ -144,8 +154,13 @@ def _verify_element(iface, name, desc, candidate, vtype): else: if not callable(attr): - raise BrokenMethodImplementation(desc, "implementation is not a method", - attr, iface, candidate) + raise BrokenMethodImplementation( + desc, + "implementation is not a method", + attr, + iface, + candidate + ) # sigh, it's callable, but we don't know how to introspect it, so # we have to give it a pass. return @@ -157,31 +172,38 @@ def _verify_element(iface, name, desc, candidate, vtype): raise BrokenMethodImplementation(desc, mess, attr, iface, candidate) - def verifyClass(iface, candidate, tentative=False): """ Verify that the *candidate* might correctly provide *iface*. """ return _verify(iface, candidate, tentative, vtype='c') + def verifyObject(iface, candidate, tentative=False): return _verify(iface, candidate, tentative, vtype='o') + verifyObject.__doc__ = _verify.__doc__ _MSG_TOO_MANY = 'implementation requires too many arguments' + def _incompat(required, implemented): - #if (required['positional'] != - # implemented['positional'][:len(required['positional'])] - # and implemented['kwargs'] is None): - # return 'imlementation has different argument names' + # if (required['positional'] != + # implemented['positional'][:len(required['positional'])] + # and implemented['kwargs'] is None): + # return 'imlementation has different argument names' if len(implemented['required']) > len(required['required']): return _MSG_TOO_MANY - if ((len(implemented['positional']) < len(required['positional'])) - and not implemented['varargs']): + + if ( + (len(implemented['positional']) < len(required['positional'])) and + not implemented['varargs'] + ): return "implementation doesn't allow enough arguments" + if required['kwargs'] and not implemented['kwargs']: return "implementation doesn't support keyword arguments" + if required['varargs'] and not implemented['varargs']: return "implementation doesn't support variable arguments"