Special case the base Interface in @implementer/classImplements to skip the redundancy detection for the sake of plone.app.caching.

This commit is contained in:
Jason Madden 2020-04-06 11:17:50 -05:00
parent 46781f87cc
commit 4cb3e63d3f
No known key found for this signature in database
GPG Key ID: 349F84431A08B99E
4 changed files with 44 additions and 11 deletions

View File

@ -518,7 +518,7 @@ declarations. Here's a silly example:
... zope.interface.implementedBy(Foo),
... ISpecial,
... )
... class Special2(Foo):
... class Special2(object):
... reason = 'I just am'
... def brag(self):
... return "I'm special because %s" % self.reason

View File

@ -33,6 +33,7 @@ from types import ModuleType
import weakref
from zope.interface.advice import addClassAdvisor
from zope.interface.interface import Interface
from zope.interface.interface import InterfaceClass
from zope.interface.interface import SpecificationBase
from zope.interface.interface import Specification
@ -470,9 +471,6 @@ def classImplements(cls, *interfaces):
# order, while still allowing for BWC (in the past, we always
# appended)
for iface in interfaces:
if spec.isOrExtends(iface):
continue
for b in spec.declared:
if iface.extends(b):
before.append(iface)
@ -493,18 +491,34 @@ def classImplementsFirst(cls, iface):
.. versionadded:: 5.0.0
"""
spec = implementedBy(cls)
if not spec.isOrExtends(iface):
_classImplements_ordered(spec, (iface,), ())
_classImplements_ordered(spec, (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.)
before = [
x
for x in before
if not spec.isOrExtends(x) or (x is Interface and not spec.declared)
]
after = [
x
for x in after
if not spec.isOrExtends(x) or (x is Interface and not spec.declared)
]
# eliminate duplicates
new_declared = []
seen = set()
for b in before + spec.declared + after:
if b not in seen:
new_declared.append(b)
seen.add(b)
for l in before, spec.declared, after:
for b in l:
if b not in seen:
new_declared.append(b)
seen.add(b)
spec.declared = tuple(new_declared)

View File

@ -890,6 +890,25 @@ class Test_classImplements(unittest.TestCase):
pass
self.__check_implementer_redundant(Foo)
def test_redundant_implementer_Interface(self):
from zope.interface import Interface
from zope.interface import implementedBy
from zope.interface import ro
from zope.interface.tests.test_ro import C3Setting
class Foo(object):
pass
with C3Setting(ro.C3.STRICT_IRO, False):
self._callFUT(Foo, Interface)
self.assertEqual(list(implementedBy(Foo)), [Interface])
class Baz(Foo):
pass
self._callFUT(Baz, Interface)
self.assertEqual(list(implementedBy(Baz)), [Interface])
def _order_for_two(self, applied_first, applied_second):
return (applied_first, applied_second)

View File

@ -873,7 +873,7 @@ class ComponentsTests(unittest.TestCase):
ibar = IFoo('IBar')
_info = u'info'
_name = u'name'
_to_reg = object()
class _Factory(object):
pass