mmpSearch/venv/lib/python3.12/site-packages/zope/interface/tests/test_declarations.py

2621 lines
77 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.interface import InterfaceClass
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
IBar = InterfaceClass('IBar')
IFoo = InterfaceClass('IFoo')
class Foo:
pass
class FooImplementedNone:
__implemented__ = None
class FooNoCall:
__implemented__ = None
def __call__(self):
raise NotImplementedError()
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):
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):
IFoo = InterfaceClass('IFoo')
decl = self._makeOne()
self.assertNotIn(IFoo, decl)
def test___contains__w_base_interface(self):
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertIn(IFoo, decl)
def test___iter___single_base(self):
IFoo = InterfaceClass('IFoo')
decl = self._makeOne(IFoo)
self.assertEqual(list(decl), [IFoo])
def test___iter___multiple_bases(self):
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar')
decl = self._makeOne(IFoo, IBar)
self.assertEqual(list(decl), [IFoo, IBar])
def test___iter___inheritance(self):
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
decl = self._makeOne(IBar)
self.assertEqual(list(decl), [IBar]) # IBar.interfaces() omits bases
def test___iter___w_nested_sequence_overlap(self):
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
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
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
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
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):
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):
IFoo = InterfaceClass('IFoo')
before = self._makeOne(IFoo)
after = before - IFoo
self.assertEqual(list(after), [])
def test___sub___related_interface_by_inheritance(self):
IFoo = InterfaceClass('IFoo')
IBar = InterfaceClass('IBar', (IFoo,))
before = self._makeOne(IBar)
after = before - IBar
self.assertEqual(list(after), [])
def test___add___unrelated_interface(self):
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):
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.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
class A:
pass
class B:
pass
IFoo = InterfaceClass('IFoo')
self.assertEqual(implementedBy(A), implementedBy(A))
self.assertEqual(hash(implementedBy(A)), hash(implementedBy(A)))
self.assertLess(implementedBy(A), None)
self.assertGreater(
None,
implementedBy(A)
)
self.assertLess(implementedBy(A), implementedBy(B))
self.assertGreater(implementedBy(A), IFoo)
self.assertLessEqual(implementedBy(A), implementedBy(B))
self.assertGreaterEqual(implementedBy(A), IFoo)
self.assertNotEqual(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.assertEqual(
implementedByA,
implementedByA
)
self.assertNotEqual(implementedByA, implementedByB)
self.assertNotEqual(implementedByB, implementedByA)
self.assertEqual(proxy, implementedByA)
self.assertEqual(implementedByA, proxy)
self.assertEqual(proxy, implementedByA)
self.assertEqual(implementedByA, proxy)
self.assertNotEqual(proxy, implementedByB)
self.assertNotEqual(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.assertIs(self._callFUT(foo), 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.assertIs(self._callFUT(foo), impl)
def test_dictless_w_existing_not_Implements(self):
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.assertIs(self._callFUT(Foo), 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.assertIs(self._callFUT(tuple), t_spec)
self.assertIs(self._callFUT(list), l_spec)
self.assertIs(self._callFUT(dict), 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
from zope.interface.tests.test_declarations import FooNoCall
foo = FooNoCall()
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
from zope.interface.tests.test_declarations import FooImplementedNone
spec = self._callFUT(FooImplementedNone)
self.assertEqual(
spec.__name__,
'zope.interface.tests.test_declarations.FooImplementedNone')
self.assertIs(spec.inherit, FooImplementedNone)
self.assertIs(FooImplementedNone.__implemented__, spec)
self.assertIsInstance(
FooImplementedNone.__providedBy__, ClassProvides
) # pylint:disable=no-member
self.assertIsInstance(
FooImplementedNone.__provides__, ClassProvides
) # pylint:disable=no-member
self.assertEqual(
FooImplementedNone.__provides__, FooImplementedNone.__providedBy__
) # pylint:disable=no-member
def test_w_existing_Implements(self):
from zope.interface.declarations import Implements
impl = Implements()
class Foo:
__implemented__ = impl
self.assertIs(self._callFUT(Foo), 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
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
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, None)
self.assertEqual(impl.declared, (IBar,))
def test_class(self):
from zope.interface.declarations import Implements
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
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
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
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):
IFoo = InterfaceClass('IFoo')
decorator = self._makeOne(IFoo)
self.assertRaises(TypeError, decorator, object())
def test_nonclass_can_assign_attr(self):
IFoo = InterfaceClass('IFoo')
from zope.interface.tests.test_declarations import Foo
foo = Foo()
decorator = self._makeOne(IFoo)
returned = decorator(foo)
self.assertIs(returned, 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
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):
IFoo = InterfaceClass('IFoo')
decorator = self._makeOne(IFoo)
def _function():
raise NotImplementedError()
self.assertRaises(ValueError, decorator, _function)
def test_method(self):
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):
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
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):
IFoo = InterfaceClass("IFoo")
class Foo:
pass
spec = self._makeOne(Foo, IFoo)
Foo.__provides__ = spec
self.assertIs(Foo.__provides__, spec)
def test___get___instance(self):
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):
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.tests import dummy
from zope.interface.tests.test_declarations import IBar
from zope.interface.tests.test_declarations import IFoo
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.
from zope.interface.tests import test_declarations as my_module
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
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):
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
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
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
IFoo = InterfaceClass("IFoo")
cache = {}
class Foo:
pass
with _Monkey(declarations, InstanceDeclarations=cache):
spec = self._callFUT(Foo, IFoo)
self.assertEqual(list(spec), [IFoo])
self.assertIs(cache[(Foo, IFoo)], spec)
def test_w_cached_spec(self):
from zope.interface import declarations
IFoo = InterfaceClass("IFoo")
prior = object()
class Foo:
pass
cache = {(Foo, IFoo): prior}
with _Monkey(declarations, InstanceDeclarations=cache):
spec = self._callFUT(Foo, IFoo)
self.assertIs(spec, 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
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
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
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
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
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):
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
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
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
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):
IFoo = InterfaceClass("IFoo")
class Foo:
pass
cpbp = Foo.__provides__ = self._makeOne(Foo, IFoo)
self.assertIs(Foo.__provides__, cpbp)
def test_w_same_class_via_instance(self):
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):
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
IFoo = InterfaceClass("IFoo")
IBar = InterfaceClass("IBar")
@implementer(IFoo)
class Foo:
pass
cp = Foo.__provides__ = self._makeOne(Foo, type(Foo), IBar)
self.assertIs(Foo.__provides__, cp)
self.assertEqual(list(Foo().__provides__), [IFoo])
def test___reduce__(self):
from zope.interface.declarations import implementer
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):
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.assertIs(spec, 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.assertIs(spec, expected)
def test_w_providedBy_invalid_spec_w_provides_same_provides_on_class(self):
from zope.interface.declarations import implementer
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
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
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
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)