2684 lines
81 KiB
Python
2684 lines
81 KiB
Python
##############################################################################
|
|
#
|
|
# Copyright (c) 2003 Zope Foundation and Contributors.
|
|
# All Rights Reserved.
|
|
#
|
|
# This software is subject to the provisions of the Zope Public License,
|
|
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
|
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
|
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE.
|
|
#
|
|
##############################################################################
|
|
"""Test the new API for making and checking interface declarations
|
|
"""
|
|
import unittest
|
|
|
|
from zope.interface.tests import MissingSomeAttrs
|
|
from zope.interface.tests import OptimizationTestMixin
|
|
from zope.interface.tests import SubclassableMixin
|
|
from zope.interface.tests.test_interface import \
|
|
NameAndModuleComparisonTestsMixin
|
|
|
|
|
|
# pylint:disable=inherit-non-class,too-many-lines,protected-access
|
|
# pylint:disable=blacklisted-name,attribute-defined-outside-init
|
|
|
|
class _Py3ClassAdvice:
|
|
|
|
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 _:
|
|
warnings.resetwarnings()
|
|
|
|
try:
|
|
exec(code, globs, locs)
|
|
except TypeError:
|
|
return False
|
|
else:
|
|
if fails_under_py3k:
|
|
self.fail("Didn't raise TypeError")
|
|
return None
|
|
|
|
|
|
class NamedTests(unittest.TestCase):
|
|
|
|
def test_class(self):
|
|
from zope.interface.declarations import named
|
|
|
|
@named('foo')
|
|
class Foo:
|
|
pass
|
|
|
|
self.assertEqual(
|
|
Foo.__component_name__, 'foo'
|
|
) # pylint:disable=no-member
|
|
|
|
def test_function(self):
|
|
from zope.interface.declarations import named
|
|
|
|
@named('foo')
|
|
def doFoo(o):
|
|
raise NotImplementedError()
|
|
|
|
self.assertEqual(doFoo.__component_name__, 'foo')
|
|
|
|
def test_instance(self):
|
|
from zope.interface.declarations import named
|
|
|
|
class Foo:
|
|
pass
|
|
foo = Foo()
|
|
named('foo')(foo)
|
|
|
|
self.assertEqual(
|
|
foo.__component_name__, 'foo'
|
|
) # pylint:disable=no-member
|
|
|
|
|
|
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()
|
|
iface_list = list(decl.interfaces())
|
|
self.assertEqual(iface_list, [])
|
|
|
|
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,))
|
|
|
|
def test_get(self):
|
|
decl = self._getEmpty()
|
|
self.assertIsNone(decl.get('attr'))
|
|
self.assertEqual(decl.get('abc', 'def'), 'def')
|
|
# It's a positive cache only (when it even exists)
|
|
# so this added nothing.
|
|
self.assertFalse(decl._v_attrs)
|
|
|
|
def test_changed_w_existing__v_attrs(self):
|
|
decl = self._getEmpty()
|
|
decl._v_attrs = object()
|
|
decl.changed(decl)
|
|
self.assertFalse(decl._v_attrs)
|
|
|
|
|
|
class DeclarationTests(EmptyDeclarationTests):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import Declaration
|
|
return Declaration
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test_ctor_no_bases(self):
|
|
decl = self._makeOne()
|
|
self.assertEqual(list(decl.__bases__), [])
|
|
|
|
def test_ctor_w_interface_in_bases(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decl = self._makeOne(IFoo)
|
|
self.assertEqual(list(decl.__bases__), [IFoo])
|
|
|
|
def test_ctor_w_implements_in_bases(self):
|
|
from zope.interface.declarations import Implements
|
|
impl = Implements()
|
|
decl = self._makeOne(impl)
|
|
self.assertEqual(list(decl.__bases__), [impl])
|
|
|
|
def test_changed_wo_existing__v_attrs(self):
|
|
decl = self._makeOne()
|
|
decl.changed(decl) # doesn't raise
|
|
self.assertIsNone(decl._v_attrs)
|
|
|
|
def test___contains__w_self(self):
|
|
decl = self._makeOne()
|
|
self.assertNotIn(decl, decl)
|
|
|
|
def test___contains__w_unrelated_iface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decl = self._makeOne()
|
|
self.assertNotIn(IFoo, decl)
|
|
|
|
def test___contains__w_base_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decl = self._makeOne(IFoo)
|
|
self.assertIn(IFoo, decl)
|
|
|
|
def test___iter___single_base(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decl = self._makeOne(IFoo)
|
|
self.assertEqual(list(decl), [IFoo])
|
|
|
|
def test___iter___multiple_bases(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
decl = self._makeOne(IFoo, IBar)
|
|
self.assertEqual(list(decl), [IFoo, IBar])
|
|
|
|
def test___iter___inheritance(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar', (IFoo,))
|
|
decl = self._makeOne(IBar)
|
|
self.assertEqual(list(decl), [IBar]) # IBar.interfaces() omits bases
|
|
|
|
def test___iter___w_nested_sequence_overlap(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
decl = self._makeOne(IBar, (IFoo, IBar))
|
|
self.assertEqual(list(decl), [IBar, IFoo])
|
|
|
|
def test_flattened_single_base(self):
|
|
from zope.interface.interface import Interface
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decl = self._makeOne(IFoo)
|
|
self.assertEqual(list(decl.flattened()), [IFoo, Interface])
|
|
|
|
def test_flattened_multiple_bases(self):
|
|
from zope.interface.interface import Interface
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
decl = self._makeOne(IFoo, IBar)
|
|
self.assertEqual(list(decl.flattened()), [IFoo, IBar, Interface])
|
|
|
|
def test_flattened_inheritance(self):
|
|
from zope.interface.interface import Interface
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar', (IFoo,))
|
|
decl = self._makeOne(IBar)
|
|
self.assertEqual(list(decl.flattened()), [IBar, IFoo, Interface])
|
|
|
|
def test_flattened_w_nested_sequence_overlap(self):
|
|
from zope.interface.interface import Interface
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
# This is the same as calling ``Declaration(IBar, IFoo, IBar)``
|
|
# which doesn't make much sense, but here it is. In older
|
|
# versions of zope.interface, the __iro__ would have been
|
|
# IFoo, IBar, Interface, which especially makes no sense.
|
|
decl = self._makeOne(IBar, (IFoo, IBar))
|
|
# Note that decl.__iro__ has IFoo first.
|
|
self.assertEqual(list(decl.flattened()), [IBar, IFoo, Interface])
|
|
|
|
def test___sub___unrelated_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
before = self._makeOne(IFoo)
|
|
after = before - IBar
|
|
self.assertIsInstance(after, self._getTargetClass())
|
|
self.assertEqual(list(after), [IFoo])
|
|
|
|
def test___sub___related_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
before = self._makeOne(IFoo)
|
|
after = before - IFoo
|
|
self.assertEqual(list(after), [])
|
|
|
|
def test___sub___related_interface_by_inheritance(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar', (IFoo,))
|
|
before = self._makeOne(IBar)
|
|
after = before - IBar
|
|
self.assertEqual(list(after), [])
|
|
|
|
def test___add___unrelated_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
before = self._makeOne(IFoo)
|
|
after = before + IBar
|
|
self.assertIsInstance(after, self._getTargetClass())
|
|
self.assertEqual(list(after), [IFoo, IBar])
|
|
|
|
def test___add___related_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
IBaz = InterfaceClass('IBaz')
|
|
before = self._makeOne(IFoo, IBar)
|
|
other = self._makeOne(IBar, IBaz)
|
|
after = before + other
|
|
self.assertEqual(list(after), [IFoo, IBar, IBaz])
|
|
|
|
def test___add___overlapping_interface(self):
|
|
# The derived interfaces end up with higher priority, and
|
|
# don't produce a C3 resolution order violation. This
|
|
# example produced a C3 error, and the resulting legacy order
|
|
# used to be wrong ([IBase, IDerived] instead of
|
|
# the other way).
|
|
from zope.interface import Interface
|
|
from zope.interface import ro
|
|
from zope.interface.interface import InterfaceClass
|
|
from zope.interface.tests.test_ro import C3Setting
|
|
|
|
IBase = InterfaceClass('IBase')
|
|
IDerived = InterfaceClass('IDerived', (IBase,))
|
|
|
|
with C3Setting(ro.C3.STRICT_IRO, True):
|
|
base = self._makeOne(IBase)
|
|
after = base + IDerived
|
|
|
|
self.assertEqual(after.__iro__, (IDerived, IBase, Interface))
|
|
self.assertEqual(after.__bases__, (IDerived, IBase))
|
|
self.assertEqual(list(after), [IDerived, IBase])
|
|
|
|
def test___add___overlapping_interface_implementedBy(self):
|
|
# Like test___add___overlapping_interface, but pulling
|
|
# in a realistic example. This one previously produced a
|
|
# C3 error, but the resulting legacy order was (somehow)
|
|
# correct.
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import implementer
|
|
from zope.interface import ro
|
|
from zope.interface.tests.test_ro import C3Setting
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
with C3Setting(ro.C3.STRICT_IRO, True):
|
|
after = implementedBy(Base) + IDerived
|
|
|
|
self.assertEqual(after.__sro__, (after, IDerived, IBase, Interface))
|
|
self.assertEqual(after.__bases__, (IDerived, IBase))
|
|
self.assertEqual(list(after), [IDerived, IBase])
|
|
|
|
|
|
class TestImmutableDeclaration(EmptyDeclarationTests):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import _ImmutableDeclaration
|
|
return _ImmutableDeclaration
|
|
|
|
def _getEmpty(self):
|
|
from zope.interface.declarations import _empty
|
|
return _empty
|
|
|
|
def test_pickle(self):
|
|
import pickle
|
|
copied = pickle.loads(pickle.dumps(self._getEmpty()))
|
|
self.assertIs(copied, self._getEmpty())
|
|
|
|
def test_singleton(self):
|
|
self.assertIs(
|
|
self._getTargetClass()(),
|
|
self._getEmpty()
|
|
)
|
|
|
|
def test__bases__(self):
|
|
self.assertEqual(self._getEmpty().__bases__, ())
|
|
|
|
def test_change__bases__(self):
|
|
empty = self._getEmpty()
|
|
empty.__bases__ = ()
|
|
self.assertEqual(self._getEmpty().__bases__, ())
|
|
|
|
with self.assertRaises(TypeError):
|
|
empty.__bases__ = (1,)
|
|
|
|
def test_dependents(self):
|
|
empty = self._getEmpty()
|
|
deps = empty.dependents
|
|
self.assertEqual({}, deps)
|
|
# Doesn't change the return.
|
|
deps[1] = 2
|
|
self.assertEqual({}, empty.dependents)
|
|
|
|
def test_changed(self):
|
|
# Does nothing, has no visible side-effects
|
|
self._getEmpty().changed(None)
|
|
|
|
def test_extends_always_false(self):
|
|
self.assertFalse(self._getEmpty().extends(self))
|
|
self.assertFalse(self._getEmpty().extends(self, strict=True))
|
|
self.assertFalse(self._getEmpty().extends(self, strict=False))
|
|
|
|
def test_get_always_default(self):
|
|
self.assertIsNone(self._getEmpty().get('name'))
|
|
self.assertEqual(self._getEmpty().get('name', 42), 42)
|
|
|
|
def test_v_attrs(self):
|
|
decl = self._getEmpty()
|
|
self.assertEqual(decl._v_attrs, {})
|
|
|
|
decl._v_attrs['attr'] = 42
|
|
self.assertEqual(decl._v_attrs, {})
|
|
self.assertIsNone(decl.get('attr'))
|
|
|
|
attrs = decl._v_attrs = {}
|
|
attrs['attr'] = 42
|
|
self.assertEqual(decl._v_attrs, {})
|
|
self.assertIsNone(decl.get('attr'))
|
|
|
|
|
|
class TestImplements(NameAndModuleComparisonTestsMixin,
|
|
unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import Implements
|
|
return Implements
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def _makeOneToCompare(self):
|
|
from zope.interface.declarations import implementedBy
|
|
|
|
class A:
|
|
pass
|
|
|
|
return implementedBy(A)
|
|
|
|
def test_ctor_no_bases(self):
|
|
impl = self._makeOne()
|
|
self.assertEqual(impl.inherit, None)
|
|
self.assertEqual(impl.declared, ())
|
|
self.assertEqual(impl.__name__, '?')
|
|
self.assertEqual(list(impl.__bases__), [])
|
|
|
|
def test___repr__(self):
|
|
impl = self._makeOne()
|
|
impl.__name__ = 'Testing'
|
|
self.assertEqual(repr(impl), 'classImplements(Testing)')
|
|
|
|
def test___reduce__(self):
|
|
from zope.interface.declarations import implementedBy
|
|
impl = self._makeOne()
|
|
self.assertEqual(impl.__reduce__(), (implementedBy, (None,)))
|
|
|
|
def test_sort(self):
|
|
from zope.interface.declarations import implementedBy
|
|
from zope.interface.interface import InterfaceClass
|
|
|
|
class A:
|
|
pass
|
|
|
|
class B:
|
|
pass
|
|
|
|
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(implementedBy(A) < implementedBy(B))
|
|
self.assertTrue(implementedBy(A) > IFoo)
|
|
self.assertTrue(implementedBy(A) <= implementedBy(B))
|
|
self.assertTrue(implementedBy(A) >= IFoo)
|
|
self.assertTrue(implementedBy(A) != IFoo)
|
|
|
|
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
|
|
|
|
def __getattr__(self, name):
|
|
raise NotImplementedError()
|
|
|
|
def __eq__(self, other):
|
|
return self._wrapped == other
|
|
|
|
def __ne__(self, other):
|
|
return self._wrapped != other
|
|
|
|
class A:
|
|
pass
|
|
|
|
class B:
|
|
pass
|
|
|
|
implementedByA = implementedBy(A)
|
|
implementedByB = implementedBy(B)
|
|
proxy = Proxy(implementedByA)
|
|
|
|
# The order of arguments to the operators matters,
|
|
# test both
|
|
self.assertTrue(
|
|
implementedByA == implementedByA
|
|
) # pylint:disable=comparison-with-itself
|
|
self.assertTrue(implementedByA != implementedByB)
|
|
self.assertTrue(implementedByB != implementedByA)
|
|
|
|
self.assertTrue(proxy == implementedByA)
|
|
self.assertTrue(implementedByA == proxy)
|
|
self.assertFalse(proxy != implementedByA)
|
|
self.assertFalse(implementedByA != proxy)
|
|
|
|
self.assertTrue(proxy != implementedByB)
|
|
self.assertTrue(implementedByB != proxy)
|
|
|
|
def test_changed_deletes_super_cache(self):
|
|
impl = self._makeOne()
|
|
self.assertIsNone(impl._super_cache)
|
|
self.assertNotIn('_super_cache', impl.__dict__)
|
|
|
|
impl._super_cache = 42
|
|
self.assertIn('_super_cache', impl.__dict__)
|
|
|
|
impl.changed(None)
|
|
self.assertIsNone(impl._super_cache)
|
|
self.assertNotIn('_super_cache', impl.__dict__)
|
|
|
|
def test_changed_does_not_add_super_cache(self):
|
|
impl = self._makeOne()
|
|
self.assertIsNone(impl._super_cache)
|
|
self.assertNotIn('_super_cache', impl.__dict__)
|
|
|
|
impl.changed(None)
|
|
self.assertIsNone(impl._super_cache)
|
|
self.assertNotIn('_super_cache', impl.__dict__)
|
|
|
|
|
|
class Test_implementedByFallback(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import implementedByFallback
|
|
return implementedByFallback
|
|
|
|
_getFallbackClass = _getTargetClass
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test_dictless_wo_existing_Implements_wo_registrations(self):
|
|
class Foo:
|
|
__slots__ = ('__implemented__',)
|
|
foo = Foo()
|
|
foo.__implemented__ = None
|
|
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()
|
|
with _MonkeyDict(declarations,
|
|
'BuiltinImplementationSpecifications') as specs:
|
|
specs[foo] = reg
|
|
self.assertTrue(self._callFUT(foo) is reg)
|
|
|
|
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,)
|
|
self.assertEqual(list(self._callFUT(foo)), [IFoo])
|
|
|
|
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):
|
|
from zope.interface import declarations
|
|
from zope.interface.declarations import Implements
|
|
with _MonkeyDict(declarations,
|
|
'BuiltinImplementationSpecifications') as specs:
|
|
self.assertEqual(list(self._callFUT(tuple)), [])
|
|
self.assertEqual(list(self._callFUT(list)), [])
|
|
self.assertEqual(list(self._callFUT(dict)), [])
|
|
for typ in (tuple, list, dict):
|
|
spec = specs[typ]
|
|
self.assertIsInstance(spec, Implements)
|
|
self.assertEqual(repr(spec),
|
|
'classImplements(%s)'
|
|
% (typ.__name__,))
|
|
|
|
def test_builtins_w_existing_cache(self):
|
|
from zope.interface import declarations
|
|
t_spec, l_spec, d_spec = object(), object(), object()
|
|
with _MonkeyDict(declarations,
|
|
'BuiltinImplementationSpecifications') as specs:
|
|
specs[tuple] = t_spec
|
|
specs[list] = l_spec
|
|
specs[dict] = d_spec
|
|
self.assertTrue(self._callFUT(tuple) is t_spec)
|
|
self.assertTrue(self._callFUT(list) is l_spec)
|
|
self.assertTrue(self._callFUT(dict) is d_spec)
|
|
|
|
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()
|
|
|
|
foo = Foo()
|
|
foo.__name__ = 'foo'
|
|
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.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
|
|
|
|
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):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Base):
|
|
pass
|
|
|
|
self.assertEqual(list(self._callFUT(Derived)), [IDerived, IBase])
|
|
sup = super(Derived, Derived)
|
|
self.assertEqual(list(self._callFUT(sup)), [IBase])
|
|
|
|
def test_super_when_base_implements_interface_diamond(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
class Child1(Base):
|
|
pass
|
|
|
|
class Child2(Base):
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Child1, Child2):
|
|
pass
|
|
|
|
self.assertEqual(list(self._callFUT(Derived)), [IDerived, IBase])
|
|
sup = super(Derived, Derived)
|
|
self.assertEqual(list(self._callFUT(sup)), [IBase])
|
|
|
|
def test_super_when_parent_implements_interface_diamond(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class Base:
|
|
pass
|
|
|
|
class Child1(Base):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Child2(Base):
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Child1, Child2):
|
|
pass
|
|
|
|
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)
|
|
self.assertEqual(list(fut), [IBase])
|
|
self.assertIsNone(fut._dependents)
|
|
|
|
def test_super_when_base_doesnt_implement_interface(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Base):
|
|
pass
|
|
|
|
self.assertEqual(list(self._callFUT(Derived)), [IDerived])
|
|
|
|
sup = super(Derived, Derived)
|
|
self.assertEqual(list(self._callFUT(sup)), [])
|
|
|
|
def test_super_when_base_is_object(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived:
|
|
pass
|
|
|
|
self.assertEqual(list(self._callFUT(Derived)), [IDerived])
|
|
|
|
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
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IM1(Interface):
|
|
pass
|
|
|
|
class IM2(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class IUnrelated(Interface):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IM1)
|
|
class M1(Base):
|
|
pass
|
|
|
|
@implementer(IM2)
|
|
class M2(Base):
|
|
pass
|
|
|
|
@implementer(IDerived, IUnrelated)
|
|
class Derived(M1, M2):
|
|
pass
|
|
|
|
d = Derived
|
|
sd = super(Derived, Derived)
|
|
sm1 = super(M1, Derived)
|
|
sm2 = super(M2, Derived)
|
|
|
|
self.assertEqual(list(self._callFUT(d)),
|
|
[IDerived, IUnrelated, IM1, IBase, IM2])
|
|
self.assertEqual(list(self._callFUT(sd)),
|
|
[IM1, IBase, IM2])
|
|
self.assertEqual(list(self._callFUT(sm1)),
|
|
[IM2, IBase])
|
|
self.assertEqual(list(self._callFUT(sm2)),
|
|
[IBase])
|
|
|
|
|
|
class Test_implementedBy(Test_implementedByFallback,
|
|
OptimizationTestMixin):
|
|
# Repeat tests for C optimizations
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import implementedBy
|
|
return implementedBy
|
|
|
|
|
|
class _ImplementsTestMixin:
|
|
FUT_SETS_PROVIDED_BY = True
|
|
|
|
def _callFUT(self, cls, iface):
|
|
# Declare that *cls* implements *iface*; return *cls*
|
|
raise NotImplementedError
|
|
|
|
def _check_implementer(self, Foo,
|
|
orig_spec=None,
|
|
spec_name=__name__ + '.Foo',
|
|
inherit="not given"):
|
|
from zope.interface.declarations import ClassProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
|
|
returned = self._callFUT(Foo, IFoo)
|
|
|
|
self.assertIs(returned, Foo)
|
|
spec = Foo.__implemented__
|
|
if orig_spec is not None:
|
|
self.assertIs(spec, orig_spec)
|
|
|
|
self.assertEqual(spec.__name__,
|
|
spec_name)
|
|
inherit = Foo if inherit == "not given" else inherit
|
|
self.assertIs(spec.inherit, inherit)
|
|
self.assertIs(Foo.__implemented__, spec)
|
|
if self.FUT_SETS_PROVIDED_BY:
|
|
self.assertIsInstance(Foo.__providedBy__, ClassProvides)
|
|
self.assertIsInstance(Foo.__provides__, ClassProvides)
|
|
self.assertEqual(Foo.__provides__, Foo.__providedBy__)
|
|
|
|
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
|
|
|
|
def _callFUT(self, cls, iface):
|
|
from zope.interface.declarations import classImplementsOnly
|
|
classImplementsOnly(cls, iface)
|
|
return cls
|
|
|
|
def test_w_existing_Implements(self):
|
|
from zope.interface.declarations import Implements
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
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
|
|
self.assertTrue(Foo.__implemented__ is impl)
|
|
self.assertEqual(impl.inherit, None)
|
|
self.assertEqual(impl.declared, (IBar,))
|
|
|
|
def test_class(self):
|
|
from zope.interface.declarations import Implements
|
|
from zope.interface.interface import InterfaceClass
|
|
IBar = InterfaceClass('IBar')
|
|
old_spec = Implements(IBar)
|
|
|
|
class Foo:
|
|
__implemented__ = old_spec
|
|
|
|
self._check_implementer(Foo, old_spec, '?', inherit=None)
|
|
|
|
def test_redundant_with_super_still_implements(self):
|
|
Base, IBase = self._check_implementer(
|
|
type('Foo', (object,), {}),
|
|
inherit=None,
|
|
)
|
|
|
|
class Child(Base):
|
|
pass
|
|
|
|
self._callFUT(Child, IBase)
|
|
self.assertTrue(IBase.implementedBy(Child))
|
|
|
|
|
|
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
|
|
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)
|
|
Base, IBase = self._check_implementer(Base)
|
|
|
|
class Child(Base):
|
|
pass
|
|
|
|
returned = self._callFUT(Child, IBase)
|
|
self.assertIn('__implemented__', returned.__dict__)
|
|
self.assertNotIn('__providedBy__', returned.__dict__)
|
|
self.assertIn('__provides__', returned.__dict__)
|
|
|
|
spec = Child.__implemented__
|
|
self.assertEqual(spec.declared, ())
|
|
self.assertEqual(spec.inherit, Child)
|
|
|
|
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):
|
|
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:
|
|
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)
|
|
|
|
def test_w_existing_Implements(self):
|
|
from zope.interface.declarations import Implements
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
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
|
|
self.assertIs(Foo.__implemented__, impl)
|
|
self.assertEqual(impl.inherit, Foo)
|
|
self.assertEqual(impl.declared,
|
|
self._order_for_two(IFoo, IBar))
|
|
|
|
def test_w_existing_Implements_w_bases(self):
|
|
from zope.interface.declarations import Implements
|
|
from zope.interface.interface import InterfaceClass
|
|
IRoot = InterfaceClass('IRoot')
|
|
ISecondRoot = InterfaceClass('ISecondRoot')
|
|
IExtendsRoot = InterfaceClass('IExtendsRoot', (IRoot,))
|
|
|
|
impl_root = Implements.named('Root', IRoot)
|
|
impl_root.declared = (IRoot,)
|
|
|
|
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)
|
|
# Same spec, now different values
|
|
self.assertIs(ExtendsRoot.__implemented__, impl_extends_root)
|
|
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,)
|
|
)
|
|
|
|
|
|
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
|
|
self.assertIsNone(result)
|
|
return cls
|
|
|
|
def _order_for_two(self, applied_first, applied_second):
|
|
return (applied_second, applied_first)
|
|
|
|
|
|
class Test__implements_advice(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import _implements_advice
|
|
return _implements_advice(*args, **kw)
|
|
|
|
def test_no_existing_implements(self):
|
|
from zope.interface.declarations import Implements
|
|
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
|
|
|
|
|
|
class Test_implementer(Test_classImplements):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import implementer
|
|
return implementer
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def _callFUT(self, cls, *ifaces):
|
|
decorator = self._makeOne(*ifaces)
|
|
return decorator(cls)
|
|
|
|
def test_nonclass_cannot_assign_attr(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
decorator = self._makeOne(IFoo)
|
|
self.assertRaises(TypeError, decorator, object())
|
|
|
|
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.?'
|
|
)
|
|
self.assertIsNone(spec.inherit,)
|
|
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
|
|
# object after they go out of scope. There was briefly a bug
|
|
# in 5.x that caused SpecificationBase._bases (in C) to not be
|
|
# traversed or cleared.
|
|
# https://github.com/zopefoundation/zope.interface/issues/216
|
|
import gc
|
|
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass('IFoo')
|
|
|
|
begin_count = len(gc.get_objects())
|
|
|
|
for _ in range(1900):
|
|
class TestClass:
|
|
pass
|
|
|
|
self._callFUT(TestClass, IFoo)
|
|
|
|
gc.collect()
|
|
|
|
end_count = len(gc.get_objects())
|
|
|
|
# How many new objects might still be around? In all currently
|
|
# tested interpreters, there aren't any, so our counts should
|
|
# match exactly. When the bug existed, in a steady state, the loop
|
|
# would grow by two objects each iteration
|
|
fudge_factor = 0
|
|
self.assertLessEqual(end_count, begin_count + fudge_factor)
|
|
|
|
|
|
class Test_implementer_only(Test_classImplementsOnly):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import implementer_only
|
|
return implementer_only
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def _callFUT(self, cls, iface):
|
|
decorator = self._makeOne(iface)
|
|
return decorator(cls)
|
|
|
|
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)
|
|
|
|
|
|
class ProvidesClassTests(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ProvidesClass
|
|
return ProvidesClass
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*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])
|
|
|
|
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)
|
|
self.assertEqual(args, (Foo, IFoo))
|
|
|
|
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)
|
|
|
|
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)
|
|
|
|
|
|
class ProvidesClassStrictTests(ProvidesClassTests):
|
|
# Tests that require the strict C3 resolution order.
|
|
|
|
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 StrictProvides
|
|
|
|
def test_overlapping_interfaces_corrected(self):
|
|
# Giving Provides(cls, IFace), where IFace is already
|
|
# provided by cls, doesn't produce invalid resolution orders.
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
spec = self._makeOne(Base, IBase)
|
|
self.assertEqual(spec.__sro__, (
|
|
spec,
|
|
implementedBy(Base),
|
|
IBase,
|
|
implementedBy(object),
|
|
Interface
|
|
))
|
|
|
|
|
|
class TestProvidesClassRepr(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ProvidesClass
|
|
return ProvidesClass
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test__repr__(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
assert IFoo.__name__ == 'IFoo'
|
|
assert IFoo.__module__ == __name__
|
|
assert repr(IFoo) == f'<InterfaceClass {__name__}.IFoo>'
|
|
|
|
IBar = InterfaceClass("IBar")
|
|
|
|
inst = self._makeOne(type(self), IFoo, IBar)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(TestProvidesClassRepr, IFoo, IBar)"
|
|
)
|
|
|
|
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
|
|
self.assertEqual(
|
|
repr(provides),
|
|
"directlyProvides("
|
|
"sys.modules['zope.interface.tests.dummy'], "
|
|
"IDummyModule)"
|
|
)
|
|
|
|
def test__repr__module_after_pickle(self):
|
|
# It doesn't matter, these objects can't be pickled.
|
|
import pickle
|
|
|
|
from zope.interface.tests import dummy
|
|
provides = dummy.__provides__ # pylint:disable=no-member
|
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
|
with self.assertRaises(pickle.PicklingError):
|
|
pickle.dumps(provides, proto)
|
|
|
|
def test__repr__directlyProvides_module(self):
|
|
import sys
|
|
|
|
from zope.interface.declarations import alsoProvides
|
|
from zope.interface.declarations import directlyProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
from zope.interface.tests import dummy
|
|
|
|
IFoo = InterfaceClass('IFoo')
|
|
IBar = InterfaceClass('IBar')
|
|
|
|
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
|
|
|
|
self.assertEqual(
|
|
repr(provides),
|
|
"directlyProvides(sys.modules['zope.interface.tests.dummy'], IFoo)"
|
|
)
|
|
|
|
alsoProvides(dummy, IBar)
|
|
provides = dummy.__provides__ # pylint:disable=no-member
|
|
|
|
self.assertEqual(
|
|
repr(provides),
|
|
"directlyProvides("
|
|
"sys.modules['zope.interface.tests.dummy'], "
|
|
"IFoo, IBar)"
|
|
)
|
|
|
|
# If we make this module also provide IFoo and IBar, then the repr
|
|
# lists both names.
|
|
my_module = sys.modules[__name__]
|
|
assert not hasattr(my_module, '__provides__')
|
|
|
|
directlyProvides(my_module, IFoo, IBar)
|
|
self.addCleanup(delattr, my_module, '__provides__')
|
|
self.assertIs(my_module.__provides__, provides)
|
|
self.assertEqual(
|
|
repr(provides),
|
|
"directlyProvides(('zope.interface.tests.dummy', "
|
|
"'zope.interface.tests.test_declarations'), "
|
|
"IFoo, IBar)"
|
|
)
|
|
|
|
def test__repr__module_provides_cached_shared(self):
|
|
from zope.interface.declarations import ModuleType
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
|
|
inst = self._makeOne(ModuleType, IFoo)
|
|
inst._v_module_names += ('some.module',)
|
|
inst._v_module_names += ('another.module',)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(('some.module', 'another.module'), IFoo)"
|
|
)
|
|
|
|
def test__repr__duplicate_names(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo", __module__='mod1')
|
|
IFoo2 = InterfaceClass("IFoo", __module__='mod2')
|
|
IBaz = InterfaceClass("IBaz")
|
|
|
|
inst = self._makeOne(type(self), IFoo, IBaz, IFoo2)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(TestProvidesClassRepr, IFoo, IBaz, mod2.IFoo)"
|
|
)
|
|
|
|
def test__repr__implementedBy_in_interfaces(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
|
|
class IFoo(Interface):
|
|
"Does nothing"
|
|
|
|
class Bar:
|
|
"Does nothing"
|
|
|
|
impl = implementedBy(type(self))
|
|
|
|
inst = self._makeOne(Bar, IFoo, impl)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'directlyProvides('
|
|
'Bar, IFoo, '
|
|
'classImplements(TestProvidesClassRepr))'
|
|
)
|
|
|
|
def test__repr__empty_interfaces(self):
|
|
inst = self._makeOne(type(self))
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'directlyProvides(TestProvidesClassRepr)',
|
|
)
|
|
|
|
def test__repr__non_class(self):
|
|
|
|
def str___dont_call_me():
|
|
self.fail("Should not call str")
|
|
|
|
class Object:
|
|
__bases__ = ()
|
|
__str__ = str___dont_call_me
|
|
|
|
def __repr__(self):
|
|
return '<Object>'
|
|
|
|
inst = self._makeOne(Object())
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'directlyProvides(<Object>)',
|
|
)
|
|
|
|
def test__repr__providedBy_from_class(self):
|
|
from zope.interface.declarations import implementer
|
|
from zope.interface.declarations import providedBy
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
|
|
@implementer(IFoo)
|
|
class Foo:
|
|
pass
|
|
|
|
inst = providedBy(Foo())
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'classImplements(Foo, IFoo)'
|
|
)
|
|
|
|
def test__repr__providedBy_alsoProvides(self):
|
|
from zope.interface.declarations import alsoProvides
|
|
from zope.interface.declarations import implementer
|
|
from zope.interface.declarations import providedBy
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
IBar = InterfaceClass("IBar")
|
|
|
|
@implementer(IFoo)
|
|
class Foo:
|
|
pass
|
|
|
|
foo = Foo()
|
|
alsoProvides(foo, IBar)
|
|
|
|
inst = providedBy(foo)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(Foo, IBar, classImplements(Foo, IFoo))"
|
|
)
|
|
|
|
|
|
class Test_Provides(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import Provides
|
|
return Provides(*args, **kw)
|
|
|
|
def test_no_cached_spec(self):
|
|
from zope.interface import declarations
|
|
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])
|
|
self.assertTrue(cache[(Foo, IFoo)] is spec)
|
|
|
|
def test_w_cached_spec(self):
|
|
from zope.interface import declarations
|
|
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)
|
|
self.assertTrue(spec is prior)
|
|
|
|
|
|
class Test_directlyProvides(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import directlyProvides
|
|
return directlyProvides(*args, **kw)
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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)
|
|
self.assertEqual(list(the_dict['__provides__']), [IFoo])
|
|
|
|
|
|
class Test_alsoProvides(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import alsoProvides
|
|
return alsoProvides(*args, **kw)
|
|
|
|
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
|
|
|
|
def test_w_existing_provides(self):
|
|
from zope.interface.declarations import ProvidesClass
|
|
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.assertIsInstance(
|
|
obj.__provides__, ProvidesClass
|
|
) # pylint:disable=no-member
|
|
self.assertEqual(
|
|
list(obj.__provides__), [IFoo, IBar]
|
|
) # pylint:disable=no-member
|
|
|
|
|
|
class Test_noLongerProvides(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import noLongerProvides
|
|
return noLongerProvides(*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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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)
|
|
|
|
|
|
class ClassProvidesBaseFallbackTests(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import ClassProvidesBaseFallback
|
|
return ClassProvidesBaseFallback
|
|
|
|
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)
|
|
|
|
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__')
|
|
self.assertRaises(AttributeError, getattr, bar, '__provides__')
|
|
|
|
|
|
class ClassProvidesBaseTests(
|
|
OptimizationTestMixin,
|
|
ClassProvidesBaseFallbackTests,
|
|
SubclassableMixin,
|
|
):
|
|
# Repeat tests for C optimizations
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ClassProvidesBase
|
|
return ClassProvidesBase
|
|
|
|
def _getFallbackClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import ClassProvidesBaseFallback
|
|
return ClassProvidesBaseFallback
|
|
|
|
|
|
class ClassProvidesTests(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ClassProvides
|
|
return ClassProvides
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test_w_simple_metaclass(self):
|
|
from zope.interface.declarations import implementer
|
|
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])
|
|
|
|
def test___reduce__(self):
|
|
from zope.interface.declarations import implementer
|
|
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)))
|
|
|
|
|
|
class ClassProvidesStrictTests(ClassProvidesTests):
|
|
# Tests that require the strict C3 resolution order.
|
|
|
|
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 StrictClassProvides
|
|
|
|
def test_overlapping_interfaces_corrected(self):
|
|
# Giving ClassProvides(cls, metaclass, IFace), where IFace is already
|
|
# provided by metacls, doesn't produce invalid resolution orders.
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class metaclass(type):
|
|
pass
|
|
|
|
cls = metaclass(
|
|
'cls',
|
|
(object,),
|
|
{}
|
|
)
|
|
|
|
spec = self._makeOne(cls, metaclass, IBase)
|
|
self.assertEqual(spec.__sro__, (
|
|
spec,
|
|
implementedBy(metaclass),
|
|
IBase,
|
|
implementedBy(type),
|
|
implementedBy(object),
|
|
Interface
|
|
))
|
|
|
|
|
|
class TestClassProvidesRepr(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ClassProvides
|
|
return ClassProvides
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test__repr__empty(self):
|
|
inst = self._makeOne(type(self), type)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(TestClassProvidesRepr)"
|
|
)
|
|
|
|
def test__repr__providing_one(self):
|
|
from zope.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
"Does nothing"
|
|
|
|
inst = self._makeOne(type(self), type, IFoo)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(TestClassProvidesRepr, IFoo)"
|
|
)
|
|
|
|
def test__repr__duplicate_names(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo", __module__='mod1')
|
|
IFoo2 = InterfaceClass("IFoo", __module__='mod2')
|
|
IBaz = InterfaceClass("IBaz")
|
|
|
|
inst = self._makeOne(type(self), type, IFoo, IBaz, IFoo2)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
"directlyProvides(TestClassProvidesRepr, IFoo, IBaz, mod2.IFoo)"
|
|
)
|
|
|
|
def test__repr__implementedBy(self):
|
|
from zope.interface.declarations import implementedBy
|
|
from zope.interface.declarations import implementer
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
|
|
@implementer(IFoo)
|
|
class Foo:
|
|
pass
|
|
|
|
inst = implementedBy(Foo)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'classImplements(Foo, IFoo)'
|
|
)
|
|
|
|
def test__repr__implementedBy_generic_callable(self):
|
|
from zope.interface.declarations import implementedBy
|
|
|
|
# We can't get a __name__ by default, so we get a
|
|
# module name and a question mark
|
|
class Callable:
|
|
def __call__(self):
|
|
return self
|
|
|
|
inst = implementedBy(Callable())
|
|
self.assertEqual(
|
|
repr(inst),
|
|
f'classImplements({__name__}.?)'
|
|
)
|
|
|
|
c = Callable()
|
|
c.__name__ = 'Callable'
|
|
inst = implementedBy(c)
|
|
self.assertEqual(
|
|
repr(inst),
|
|
'classImplements(Callable)'
|
|
)
|
|
|
|
|
|
class Test_directlyProvidedBy(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.declarations import directlyProvidedBy
|
|
return directlyProvidedBy(*args, **kw)
|
|
|
|
def test_wo_declarations_in_class_or_instance(self):
|
|
|
|
class Foo:
|
|
pass
|
|
|
|
foo = Foo()
|
|
self.assertEqual(list(self._callFUT(foo)), [])
|
|
|
|
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)), [])
|
|
|
|
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])
|
|
|
|
def test_w_declarations_in_instance_and_class(self):
|
|
from zope.interface.declarations import directlyProvides
|
|
from zope.interface.declarations import implementer
|
|
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])
|
|
|
|
|
|
class Test_provider(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import provider
|
|
return provider
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
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
|
|
|
|
|
|
class Test_moduleProvides(unittest.TestCase):
|
|
# pylint:disable=exec-used
|
|
|
|
def test_called_from_function(self):
|
|
from zope.interface.declarations import moduleProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
globs = {'__name__': 'zope.interface.tests.foo',
|
|
'moduleProvides': moduleProvides, 'IFoo': IFoo}
|
|
locs = {}
|
|
CODE = "\n".join([
|
|
'def foo():',
|
|
' moduleProvides(IFoo)'
|
|
])
|
|
exec(CODE, globs, locs)
|
|
foo = locs['foo']
|
|
self.assertRaises(TypeError, foo)
|
|
|
|
def test_called_from_class(self):
|
|
from zope.interface.declarations import moduleProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
globs = {'__name__': 'zope.interface.tests.foo',
|
|
'moduleProvides': moduleProvides, 'IFoo': IFoo}
|
|
locs = {}
|
|
CODE = "\n".join([
|
|
'class Foo(object):',
|
|
' moduleProvides(IFoo)',
|
|
])
|
|
with self.assertRaises(TypeError):
|
|
exec(CODE, globs, locs)
|
|
|
|
def test_called_once_from_module_scope(self):
|
|
from zope.interface.declarations import moduleProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
globs = {'__name__': 'zope.interface.tests.foo',
|
|
'moduleProvides': moduleProvides, 'IFoo': IFoo}
|
|
CODE = "\n".join([
|
|
'moduleProvides(IFoo)',
|
|
])
|
|
exec(CODE, globs)
|
|
spec = globs['__provides__']
|
|
self.assertEqual(list(spec), [IFoo])
|
|
|
|
def test_called_twice_from_module_scope(self):
|
|
from zope.interface.declarations import moduleProvides
|
|
from zope.interface.interface import InterfaceClass
|
|
IFoo = InterfaceClass("IFoo")
|
|
globs = {'__name__': 'zope.interface.tests.foo',
|
|
'moduleProvides': moduleProvides, 'IFoo': IFoo}
|
|
|
|
CODE = "\n".join([
|
|
'moduleProvides(IFoo)',
|
|
'moduleProvides(IFoo)',
|
|
])
|
|
with self.assertRaises(TypeError):
|
|
exec(CODE, globs)
|
|
|
|
|
|
class Test_getObjectSpecificationFallback(unittest.TestCase):
|
|
|
|
def _getFallbackClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import getObjectSpecificationFallback
|
|
return getObjectSpecificationFallback
|
|
|
|
_getTargetClass = _getFallbackClass
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
def test_wo_existing_provides_classless(self):
|
|
the_dict = {}
|
|
|
|
class Foo:
|
|
def __getattribute__(self, name):
|
|
# Emulate object w/o any class
|
|
if name == '__class__':
|
|
raise AttributeError(name)
|
|
try:
|
|
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), [])
|
|
|
|
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
|
|
|
|
def test_existing_provides_is_not_spec(self):
|
|
|
|
def foo():
|
|
raise NotImplementedError()
|
|
|
|
foo.__provides__ = object() # not a valid spec
|
|
spec = self._callFUT(foo)
|
|
self.assertEqual(list(spec), [])
|
|
|
|
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)
|
|
self.assertEqual(list(spec), [IFoo])
|
|
|
|
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__'
|
|
)
|
|
|
|
def test_catches_only_AttributeError_on_class(self):
|
|
MissingSomeAttrs.test_raises(
|
|
self,
|
|
self._callFUT,
|
|
expected_missing='__class__',
|
|
__provides__=None,
|
|
)
|
|
|
|
def test_raises_AttrError_w_provides_fails_type_check_AttrError(self):
|
|
# isinstance(ob.__provides__, SpecificationBase) is not
|
|
# protected inside any kind of block.
|
|
|
|
class Foo:
|
|
__provides__ = MissingSomeAttrs(AttributeError)
|
|
|
|
# isinstance() ignores AttributeError on __class__
|
|
self._callFUT(Foo())
|
|
|
|
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:
|
|
__provides__ = MissingSomeAttrs(RuntimeError)
|
|
|
|
with self.assertRaises(RuntimeError) as exc:
|
|
self._callFUT(Foo())
|
|
|
|
self.assertEqual('__class__', exc.exception.args[0])
|
|
|
|
|
|
class Test_getObjectSpecification(Test_getObjectSpecificationFallback,
|
|
OptimizationTestMixin):
|
|
# Repeat tests for C optimizations
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import getObjectSpecification
|
|
return getObjectSpecification
|
|
|
|
|
|
class Test_providedByFallback(unittest.TestCase):
|
|
|
|
def _getFallbackClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import providedByFallback
|
|
return providedByFallback
|
|
|
|
_getTargetClass = _getFallbackClass
|
|
|
|
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), [])
|
|
|
|
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)
|
|
self.assertEqual(list(spec), [])
|
|
|
|
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()
|
|
spec = self._callFUT(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()
|
|
Foo.__provides__ = object()
|
|
spec = self._callFUT(foo)
|
|
self.assertTrue(spec is expected)
|
|
|
|
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()
|
|
spec = self._callFUT(foo)
|
|
self.assertEqual(list(spec), [IFoo])
|
|
|
|
def test_super_when_base_implements_interface(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Base):
|
|
pass
|
|
|
|
derived = Derived()
|
|
self.assertEqual(list(self._callFUT(derived)), [IDerived, IBase])
|
|
|
|
sup = super(Derived, derived)
|
|
fut = self._callFUT(sup)
|
|
self.assertIsNone(fut._dependents)
|
|
self.assertEqual(list(fut), [IBase])
|
|
|
|
def test_super_when_base_doesnt_implement_interface(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived(Base):
|
|
pass
|
|
|
|
derived = Derived()
|
|
self.assertEqual(list(self._callFUT(derived)), [IDerived])
|
|
|
|
sup = super(Derived, derived)
|
|
self.assertEqual(list(self._callFUT(sup)), [])
|
|
|
|
def test_super_when_base_is_object(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IDerived)
|
|
class Derived:
|
|
pass
|
|
|
|
derived = Derived()
|
|
self.assertEqual(list(self._callFUT(derived)), [IDerived])
|
|
|
|
sup = super(Derived, derived)
|
|
fut = self._callFUT(sup)
|
|
self.assertIsNone(fut._dependents)
|
|
self.assertEqual(list(fut), [])
|
|
|
|
def test_super_when_object_directly_provides(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import directlyProvides
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
class Derived(Base):
|
|
pass
|
|
|
|
derived = Derived()
|
|
self.assertEqual(list(self._callFUT(derived)), [IBase])
|
|
|
|
directlyProvides(derived, IDerived)
|
|
self.assertEqual(list(self._callFUT(derived)), [IDerived, IBase])
|
|
|
|
sup = super(Derived, derived)
|
|
fut = self._callFUT(sup)
|
|
self.assertIsNone(fut._dependents)
|
|
self.assertEqual(list(fut), [IBase])
|
|
|
|
def test_super_multi_level_multi_inheritance(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.declarations import implementer
|
|
|
|
class IBase(Interface):
|
|
pass
|
|
|
|
class IM1(Interface):
|
|
pass
|
|
|
|
class IM2(Interface):
|
|
pass
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class IUnrelated(Interface):
|
|
pass
|
|
|
|
@implementer(IBase)
|
|
class Base:
|
|
pass
|
|
|
|
@implementer(IM1)
|
|
class M1(Base):
|
|
pass
|
|
|
|
@implementer(IM2)
|
|
class M2(Base):
|
|
pass
|
|
|
|
@implementer(IDerived, IUnrelated)
|
|
class Derived(M1, M2):
|
|
pass
|
|
|
|
d = Derived()
|
|
sd = super(Derived, d)
|
|
sm1 = super(M1, d)
|
|
sm2 = super(M2, d)
|
|
|
|
self.assertEqual(list(self._callFUT(d)),
|
|
[IDerived, IUnrelated, IM1, IBase, IM2])
|
|
self.assertEqual(list(self._callFUT(sd)),
|
|
[IM1, IBase, IM2])
|
|
self.assertEqual(list(self._callFUT(sm1)),
|
|
[IM2, IBase])
|
|
self.assertEqual(list(self._callFUT(sm2)),
|
|
[IBase])
|
|
|
|
def test_catches_only_AttributeError_on_providedBy(self):
|
|
MissingSomeAttrs.test_raises(self, self._callFUT,
|
|
expected_missing='__providedBy__',
|
|
__class__=object)
|
|
|
|
def test_catches_only_AttributeError_on_class(self):
|
|
# isinstance() tries to get the __class__, which is non-obvious,
|
|
# so it must be protected too.
|
|
MissingSomeAttrs.test_raises(
|
|
self, self._callFUT, expected_missing='__class__')
|
|
|
|
|
|
class Test_providedBy(Test_providedByFallback,
|
|
OptimizationTestMixin):
|
|
# Repeat tests for C optimizations
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import providedBy
|
|
return providedBy
|
|
|
|
|
|
class ObjectSpecificationDescriptorFallbackTests(unittest.TestCase):
|
|
|
|
def _getFallbackClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.declarations import \
|
|
ObjectSpecificationDescriptorFallback
|
|
return ObjectSpecificationDescriptorFallback
|
|
|
|
_getTargetClass = _getFallbackClass
|
|
|
|
def _makeOne(self, *args, **kw):
|
|
return self._getTargetClass()(*args, **kw)
|
|
|
|
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])
|
|
|
|
def test_accessed_via_inst_wo_provides(self):
|
|
from zope.interface.declarations import Provides
|
|
from zope.interface.declarations import implementer
|
|
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()
|
|
self.assertEqual(list(foo.__providedBy__), [IFoo])
|
|
|
|
def test_accessed_via_inst_w_provides(self):
|
|
from zope.interface.declarations import Provides
|
|
from zope.interface.declarations import directlyProvides
|
|
from zope.interface.declarations import implementer
|
|
from zope.interface.interface import InterfaceClass
|
|
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()
|
|
directlyProvides(foo, IBaz)
|
|
self.assertEqual(list(foo.__providedBy__), [IBaz, IFoo])
|
|
|
|
def test_arbitrary_exception_accessing_provides_not_caught(self):
|
|
|
|
class MyException(Exception):
|
|
pass
|
|
|
|
class Foo:
|
|
__providedBy__ = self._makeOne()
|
|
|
|
@property
|
|
def __provides__(self):
|
|
raise MyException
|
|
|
|
foo = Foo()
|
|
with self.assertRaises(MyException):
|
|
getattr(foo, '__providedBy__')
|
|
|
|
def test_AttributeError_accessing_provides_caught(self):
|
|
|
|
class MyException(Exception):
|
|
pass
|
|
|
|
class Foo:
|
|
__providedBy__ = self._makeOne()
|
|
|
|
@property
|
|
def __provides__(self):
|
|
raise AttributeError
|
|
|
|
foo = Foo()
|
|
provided = getattr(foo, '__providedBy__')
|
|
self.assertIsNotNone(provided)
|
|
|
|
def test_None_in__provides__overrides(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
@implementer(IFoo)
|
|
class Foo:
|
|
|
|
@property
|
|
def __provides__(self):
|
|
return None
|
|
|
|
Foo.__providedBy__ = self._makeOne()
|
|
|
|
provided = getattr(Foo(), '__providedBy__')
|
|
self.assertIsNone(provided)
|
|
|
|
|
|
class ObjectSpecificationDescriptorTests(
|
|
ObjectSpecificationDescriptorFallbackTests,
|
|
OptimizationTestMixin,
|
|
SubclassableMixin,
|
|
):
|
|
# Repeat tests for C optimizations
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.declarations import ObjectSpecificationDescriptor
|
|
return ObjectSpecificationDescriptor
|
|
|
|
|
|
# Test _normalizeargs through its callers.
|
|
|
|
|
|
class _Monkey:
|
|
# context-manager for replacing module names in the scope of a test.
|
|
def __init__(self, module, **kw):
|
|
self.module = module
|
|
self.to_restore = {key: getattr(module, key) for key in kw}
|
|
for key, value in kw.items():
|
|
setattr(module, key, value)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
for key, value in self.to_restore.items():
|
|
setattr(self.module, key, value)
|
|
|
|
|
|
class _MonkeyDict:
|
|
# 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)
|
|
self.to_restore = self.target.copy()
|
|
self.target.clear()
|
|
self.target.update(kw)
|
|
|
|
def __enter__(self):
|
|
return self.target
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
self.target.clear()
|
|
self.target.update(self.to_restore)
|