diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-03-30 09:41:32 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-30 09:41:32 -0500 |
| commit | f20604d5ca34cff2fc56cf4333ec6a4439201745 (patch) | |
| tree | 677dd6679d3a79cd6bb5cada20235bd6d0224ed3 | |
| parent | 1b83ad47e400358dc27e28d1dea013d44b394bde (diff) | |
| parent | bfedd6f58706810ee5bac3c0d08650dcac30c215 (diff) | |
| download | zope-interface-f20604d5ca34cff2fc56cf4333ec6a4439201745.tar.gz | |
Merge pull request #198 from zopefoundation/issue197
Ensure that objects that implement no interfaces still have Interface in iro and sro
| -rw-r--r-- | CHANGES.rst | 7 | ||||
| -rw-r--r-- | src/zope/interface/declarations.py | 2 | ||||
| -rw-r--r-- | src/zope/interface/interface.py | 6 | ||||
| -rw-r--r-- | src/zope/interface/tests/test_declarations.py | 58 |
4 files changed, 60 insertions, 13 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 961bf72..d6965cb 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,12 @@ 5.0.2 (unreleased) ================== -- Nothing changed yet. +- Ensure that objects that implement no interfaces (such as direct + subclasses of ``object``) still include ``Interface`` itself in + their ``__iro___`` and ``__sro___``. This fixes adapter registry + lookups for such objects when the adapter is registered for + ``Interface``. See `issue 197 + <https://github.com/zopefoundation/zope.interface/issues/197>`_. 5.0.1 (2020-03-21) diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py index d85dbf4..e84a728 100644 --- a/src/zope/interface/declarations.py +++ b/src/zope/interface/declarations.py @@ -180,7 +180,7 @@ class _ImmutableDeclaration(Declaration): return iter(()) def extends(self, interface, strict=True): - return False + return interface is self._ROOT def get(self, name, default=None): return default diff --git a/src/zope/interface/interface.py b/src/zope/interface/interface.py index 6a1ca2a..ac55633 100644 --- a/src/zope/interface/interface.py +++ b/src/zope/interface/interface.py @@ -1064,3 +1064,9 @@ from zope.interface.declarations import implementedBy from zope.interface.declarations import providedBy from zope.interface.exceptions import InvalidInterface from zope.interface.exceptions import BrokenImplementation + +# This ensures that ``Interface`` winds up in the flattened() +# list of the immutable declaration. It correctly overrides changed() +# as a no-op, so we bypass that. +from zope.interface.declarations import _empty +Specification.changed(_empty, _empty) diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py index b0875c4..9344968 100644 --- a/src/zope/interface/tests/test_declarations.py +++ b/src/zope/interface/tests/test_declarations.py @@ -74,7 +74,51 @@ class NamedTests(unittest.TestCase): self.assertEqual(foo.__component_name__, u'foo') -class DeclarationTests(unittest.TestCase): +class EmptyDeclarationTests(unittest.TestCase): + # Tests that should pass for all objects that are empty + # declarations. This includes a Declaration explicitly created + # that way, and the empty ImmutableDeclaration. + def _getEmpty(self): + from zope.interface.declarations import Declaration + return Declaration() + + def test___iter___empty(self): + decl = self._getEmpty() + self.assertEqual(list(decl), []) + + def test_flattened_empty(self): + from zope.interface.interface import Interface + decl = self._getEmpty() + self.assertEqual(list(decl.flattened()), [Interface]) + + def test___contains___empty(self): + from zope.interface.interface import Interface + decl = self._getEmpty() + self.assertNotIn(Interface, decl) + + def test_extends_empty(self): + from zope.interface.interface import Interface + decl = self._getEmpty() + self.assertTrue(decl.extends(Interface)) + self.assertTrue(decl.extends(Interface, strict=True)) + + def test_interfaces_empty(self): + decl = self._getEmpty() + l = list(decl.interfaces()) + self.assertEqual(l, []) + + def test___sro___(self): + from zope.interface.interface import Interface + decl = self._getEmpty() + self.assertEqual(decl.__sro__, (decl, Interface,)) + + def test___iro___(self): + from zope.interface.interface import Interface + decl = self._getEmpty() + self.assertEqual(decl.__iro__, (Interface,)) + + +class DeclarationTests(EmptyDeclarationTests): def _getTargetClass(self): from zope.interface.declarations import Declaration @@ -128,10 +172,6 @@ class DeclarationTests(unittest.TestCase): decl = self._makeOne(IFoo) self.assertIn(IFoo, decl) - def test___iter___empty(self): - decl = self._makeOne() - self.assertEqual(list(decl), []) - def test___iter___single_base(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') @@ -159,11 +199,6 @@ class DeclarationTests(unittest.TestCase): decl = self._makeOne(IBar, (IFoo, IBar)) self.assertEqual(list(decl), [IBar, IFoo]) - def test_flattened_empty(self): - from zope.interface.interface import Interface - decl = self._makeOne() - self.assertEqual(list(decl.flattened()), [Interface]) - def test_flattened_single_base(self): from zope.interface.interface import Interface from zope.interface.interface import InterfaceClass @@ -244,7 +279,7 @@ class DeclarationTests(unittest.TestCase): self.assertEqual(list(after), [IFoo, IBar, IBaz]) -class TestImmutableDeclaration(unittest.TestCase): +class TestImmutableDeclaration(EmptyDeclarationTests): def _getTargetClass(self): from zope.interface.declarations import _ImmutableDeclaration @@ -297,6 +332,7 @@ class TestImmutableDeclaration(unittest.TestCase): self.assertIsNone(self._getEmpty().get('name')) self.assertEqual(self._getEmpty().get('name', 42), 42) + class TestImplements(NameAndModuleComparisonTestsMixin, unittest.TestCase): |
