diff options
| author | Jason Madden <jamadden@gmail.com> | 2020-04-03 09:55:43 -0500 |
|---|---|---|
| committer | Jason Madden <jamadden@gmail.com> | 2020-04-06 09:14:45 -0500 |
| commit | 10eadd6305ee57910dbcc508b293f4bf0364fd84 (patch) | |
| tree | 63a450400cf79c33cb21a1a81d4c00371bf84dcc /src/zope/interface/tests | |
| parent | 1af83ef9f90aa7a558314892b72eec6d62263981 (diff) | |
| download | zope-interface-issue3.tar.gz | |
Let interface 'subclasses' override __adapt__.issue3
Cooperate with InterfaceClass to ensure there is no performance penalty for this. Fixes #3
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| Benchmark | bench_master38 | bench_issue3 | bench_issue3_opt |
+=============================================================+================+==============================+==============================+
| call interface (provides; deep) | 369 ns | 454 ns: 1.23x slower (+23%) | not significant |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (provides; wide) | 373 ns | 457 ns: 1.22x slower (+22%) | 365 ns: 1.02x faster (-2%) |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (no alternate, no conform, not provided) | 671 ns | 760 ns: 1.13x slower (+13%) | 636 ns: 1.06x faster (-5%) |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (alternate, no conform, not provided) | 395 ns | 494 ns: 1.25x slower (+25%) | not significant |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (no alternate, valid conform, not provided) | 250 ns | not significant | 227 ns: 1.10x faster (-9%) |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
| call interface (alternate, invalid conform, not provided) | 348 ns | 424 ns: 1.22x slower (+22%) | not significant |
+-------------------------------------------------------------+----------------+------------------------------+------------------------------+
Diffstat (limited to 'src/zope/interface/tests')
| -rw-r--r-- | src/zope/interface/tests/test_adapter.py | 64 | ||||
| -rw-r--r-- | src/zope/interface/tests/test_declarations.py | 41 | ||||
| -rw-r--r-- | src/zope/interface/tests/test_interface.py | 126 |
3 files changed, 179 insertions, 52 deletions
diff --git a/src/zope/interface/tests/test_adapter.py b/src/zope/interface/tests/test_adapter.py index 869df66..8ff96f0 100644 --- a/src/zope/interface/tests/test_adapter.py +++ b/src/zope/interface/tests/test_adapter.py @@ -796,12 +796,12 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface import Interface from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) alb = self._makeOne(registry) self.assertEqual(sorted(alb._extendors.keys()), sorted([IBar, IFoo, Interface])) - self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IFoo], [IFoo, IBar]) self.assertEqual(alb._extendors[IBar], [IBar]) self.assertEqual(sorted(alb._extendors[Interface]), sorted([IFoo, IBar])) @@ -847,14 +847,14 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface import Interface from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() alb = self._makeOne(registry) registry._provided = [IFoo, IBar] alb.init_extendors() self.assertEqual(sorted(alb._extendors.keys()), sorted([IBar, IFoo, Interface])) - self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IFoo], [IFoo, IBar]) self.assertEqual(alb._extendors[IBar], [IBar]) self.assertEqual(sorted(alb._extendors[Interface]), sorted([IFoo, IBar])) @@ -863,14 +863,14 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface import Interface from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() alb = self._makeOne(registry) alb.add_extendor(IFoo) alb.add_extendor(IBar) self.assertEqual(sorted(alb._extendors.keys()), sorted([IBar, IFoo, Interface])) - self.assertEqual(alb._extendors[IFoo], [IFoo]) + self.assertEqual(alb._extendors[IFoo], [IFoo, IBar]) self.assertEqual(alb._extendors[IBar], [IBar]) self.assertEqual(sorted(alb._extendors[Interface]), sorted([IFoo, IBar])) @@ -879,13 +879,13 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface import Interface from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) alb = self._makeOne(registry) alb.remove_extendor(IFoo) self.assertEqual(sorted(alb._extendors.keys()), sorted([IFoo, IBar, Interface])) - self.assertEqual(alb._extendors[IFoo], []) + self.assertEqual(alb._extendors[IFoo], [IBar]) self.assertEqual(alb._extendors[IBar], [IBar]) self.assertEqual(sorted(alb._extendors[Interface]), sorted([IBar])) @@ -895,7 +895,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_empty_ro(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() alb = self._makeOne(registry) result = alb._uncached_lookup((IFoo,), IBar) @@ -906,7 +906,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_order_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() registry.ro.append(subr) @@ -917,7 +917,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_extendors_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() subr._adapters = [{}, {}] #utilities, single adapters @@ -930,7 +930,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_components_miss_wrong_iface(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) IQux = InterfaceClass('IQux') registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() @@ -949,7 +949,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_components_miss_wrong_name(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() @@ -968,7 +968,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_simple_hit(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() @@ -985,7 +985,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookup_repeated_hit(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() @@ -1005,7 +1005,7 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) @implementer(IFoo) class Foo(object): pass @@ -1051,7 +1051,7 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) @implementer(IFoo) class Foo(object): pass @@ -1080,7 +1080,7 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) @implementer(IFoo) class Foo(object): pass @@ -1131,7 +1131,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookupAll_empty_ro(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() alb = self._makeOne(registry) result = alb._uncached_lookupAll((IFoo,), IBar) @@ -1142,7 +1142,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookupAll_order_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() registry.ro.append(subr) @@ -1154,7 +1154,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookupAll_extendors_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() subr._adapters = [{}, {}] #utilities, single adapters @@ -1167,7 +1167,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookupAll_components_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) IQux = InterfaceClass('IQux') registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() @@ -1185,7 +1185,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_lookupAll_simple_hit(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() @@ -1203,7 +1203,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test_names(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() _expected = object() @@ -1222,7 +1222,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_empty_ro(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() alb = self._makeOne(registry) result = alb._uncached_subscriptions((IFoo,), IBar) @@ -1233,7 +1233,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_order_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() registry.ro.append(subr) @@ -1245,7 +1245,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_extendors_miss(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry() subr = self._makeSubregistry() subr._subscribers = [{}, {}] #utilities, single adapters @@ -1258,7 +1258,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_components_miss_wrong_iface(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) IQux = InterfaceClass('IQux') registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() @@ -1276,7 +1276,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_components_miss_wrong_name(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() wrongname = object() @@ -1293,7 +1293,7 @@ class AdapterLookupBaseTests(unittest.TestCase): def test__uncached_subscriptions_simple_hit(self): from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) registry = self._makeRegistry(IFoo, IBar) subr = self._makeSubregistry() class Foo(object): @@ -1314,7 +1314,7 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) @implementer(IFoo) class Foo(object): pass @@ -1343,7 +1343,7 @@ class AdapterLookupBaseTests(unittest.TestCase): from zope.interface.declarations import implementer from zope.interface.interface import InterfaceClass IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar', IFoo) + IBar = InterfaceClass('IBar', (IFoo,)) @implementer(IFoo) class Foo(object): pass diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py index 5d7272a..83815d7 100644 --- a/src/zope/interface/tests/test_declarations.py +++ b/src/zope/interface/tests/test_declarations.py @@ -864,25 +864,30 @@ class Test_classImplements(unittest.TestCase): def test_w_existing_Implements_w_bases(self): from zope.interface.declarations import Implements from zope.interface.interface import InterfaceClass - IFoo = InterfaceClass('IFoo') - IBar = InterfaceClass('IBar') - IBaz = InterfaceClass('IBaz', IFoo) - b_impl = Implements(IBaz) - impl = Implements(IFoo) - impl.declared = (IFoo,) - class Base1(object): - __implemented__ = b_impl - class Base2(object): - __implemented__ = b_impl - class Foo(Base1, Base2): - __implemented__ = impl - impl.inherit = Foo - self._callFUT(Foo, IBar) + IRoot = InterfaceClass('IRoot') + ISecondRoot = InterfaceClass('ISecondRoot') + IExtendsRoot = InterfaceClass('IExtendsRoot', (IRoot,)) + + impl_root = Implements.named('Root', IRoot) + impl_root.declared = (IRoot,) + + class Root1(object): + __implemented__ = impl_root + class Root2(object): + __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) # Same spec, now different values - self.assertTrue(Foo.__implemented__ is impl) - self.assertEqual(impl.inherit, Foo) - self.assertEqual(impl.declared, (IFoo, IBar,)) - self.assertEqual(impl.__bases__, (IFoo, IBar, b_impl)) + self.assertIs(ExtendsRoot.__implemented__, impl_extends_root) + self.assertEqual(impl_extends_root.inherit, ExtendsRoot) + self.assertEqual(impl_extends_root.declared, (IExtendsRoot, ISecondRoot,)) + self.assertEqual(impl_extends_root.__bases__, (IExtendsRoot, ISecondRoot, impl_root)) class Test__implements_advice(unittest.TestCase): diff --git a/src/zope/interface/tests/test_interface.py b/src/zope/interface/tests/test_interface.py index 2100340..4bbed1a 100644 --- a/src/zope/interface/tests/test_interface.py +++ b/src/zope/interface/tests/test_interface.py @@ -1318,9 +1318,9 @@ class InterfaceTests(unittest.TestCase): new = Interface.__class__ FunInterface = new('FunInterface') - BarInterface = new('BarInterface', [FunInterface]) + BarInterface = new('BarInterface', (FunInterface,)) BobInterface = new('BobInterface') - BazInterface = new('BazInterface', [BobInterface, BarInterface]) + BazInterface = new('BazInterface', (BobInterface, BarInterface,)) self.assertTrue(BazInterface.extends(BobInterface)) self.assertTrue(BazInterface.extends(BarInterface)) @@ -2161,6 +2161,128 @@ class InterfaceTests(unittest.TestCase): finally: adapter_hooks[:] = old_adapter_hooks + def test___call___w_overridden_adapt(self): + from zope.interface import Interface + from zope.interface import interfacemethod + from zope.interface import implementer + + class I(Interface): + + @interfacemethod + def __adapt__(self, obj): + return 42 + + @implementer(I) + class O(object): + pass + + self.assertEqual(42, I(object())) + # __adapt__ supercedes providedBy() if defined. + self.assertEqual(42, I(O())) + + def test___call___w_overridden_adapt_call_super(self): + import sys + from zope.interface import Interface + from zope.interface import interfacemethod + from zope.interface import implementer + + class I(Interface): + + @interfacemethod + def __adapt__(self, obj): + if not self.providedBy(obj): + return 42 + if sys.version_info[:2] > (3, 5): + # Python 3.5 raises 'RuntimeError: super() __class__ is not a type' + return super().__adapt__(obj) + + return super(type(I), self).__adapt__(obj) + + @implementer(I) + class O(object): + pass + + self.assertEqual(42, I(object())) + o = O() + self.assertIs(o, I(o)) + + def test___adapt___as_method_and_implementation(self): + from zope.interface import Interface + from zope.interface import interfacemethod + + class I(Interface): + @interfacemethod + def __adapt__(self, obj): + return 42 + + def __adapt__(to_adapt): + "This is a protocol" + + self.assertEqual(42, I(object())) + self.assertEqual(I['__adapt__'].getSignatureString(), '(to_adapt)') + + def test___adapt__inheritance_and_type(self): + from zope.interface import Interface + from zope.interface import interfacemethod + + class IRoot(Interface): + """Root""" + + class IWithAdapt(IRoot): + @interfacemethod + def __adapt__(self, obj): + return 42 + + class IOther(IRoot): + """Second branch""" + + class IUnrelated(Interface): + """Unrelated""" + + class IDerivedAdapt(IUnrelated, IWithAdapt, IOther): + """Inherits an adapt""" + # Order of "inheritance" matters here. + + class IDerived2Adapt(IDerivedAdapt): + """Overrides an inherited custom adapt.""" + @interfacemethod + def __adapt__(self, obj): + return 24 + + self.assertEqual(42, IDerivedAdapt(object())) + for iface in IRoot, IWithAdapt, IOther, IUnrelated, IDerivedAdapt: + self.assertEqual(__name__, iface.__module__) + + for iface in IRoot, IOther, IUnrelated: + self.assertEqual(type(IRoot), type(Interface)) + + # But things that implemented __adapt__ got a new type + self.assertNotEqual(type(Interface), type(IWithAdapt)) + self.assertEqual(type(IWithAdapt), type(IDerivedAdapt)) + self.assertIsInstance(IWithAdapt, type(Interface)) + + self.assertEqual(24, IDerived2Adapt(object())) + self.assertNotEqual(type(IDerived2Adapt), type(IDerivedAdapt)) + self.assertIsInstance(IDerived2Adapt, type(IDerivedAdapt)) + + def test_interfacemethod_is_general(self): + from zope.interface import Interface + from zope.interface import interfacemethod + + class I(Interface): + + @interfacemethod + def __call__(self, obj): + """Replace an existing method""" + return 42 + + @interfacemethod + def this_is_new(self): + return 42 + + self.assertEqual(I(self), 42) + self.assertEqual(I.this_is_new(), 42) + class AttributeTests(ElementTests): |
