2872 lines
91 KiB
Python
2872 lines
91 KiB
Python
##############################################################################
|
|
#
|
|
# Copyright (c) 2001, 2002 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 Interface implementation
|
|
"""
|
|
# Things we let slide because it's a test
|
|
# pylint:disable=protected-access
|
|
# pylint:disable=blacklisted-name
|
|
# pylint:disable=attribute-defined-outside-init
|
|
# pylint:disable=too-many-public-methods
|
|
# pylint:disable=too-many-lines
|
|
# pylint:disable=abstract-method
|
|
# pylint:disable=redefined-builtin
|
|
# pylint:disable=signature-differs
|
|
# pylint:disable=arguments-differ
|
|
# Things you get inheriting from Interface
|
|
# pylint:disable=inherit-non-class
|
|
# pylint:disable=no-self-argument
|
|
# pylint:disable=no-method-argument
|
|
# Things you get using methods of an Interface 'subclass'
|
|
# pylint:disable=no-value-for-parameter
|
|
import unittest
|
|
|
|
from zope.interface.tests import CleanUp
|
|
from zope.interface.tests import MissingSomeAttrs
|
|
from zope.interface.tests import OptimizationTestMixin
|
|
from zope.interface.tests import SubclassableMixin
|
|
|
|
|
|
_marker = object()
|
|
|
|
|
|
class Test_invariant(unittest.TestCase):
|
|
|
|
def test_w_single(self):
|
|
from zope.interface.interface import TAGGED_DATA
|
|
from zope.interface.interface import invariant
|
|
|
|
def _check(*args, **kw):
|
|
raise NotImplementedError()
|
|
|
|
class Foo:
|
|
invariant(_check)
|
|
|
|
self.assertEqual(getattr(Foo, TAGGED_DATA, None),
|
|
{'invariants': [_check]})
|
|
|
|
def test_w_multiple(self):
|
|
from zope.interface.interface import TAGGED_DATA
|
|
from zope.interface.interface import invariant
|
|
|
|
def _check(*args, **kw):
|
|
raise NotImplementedError()
|
|
|
|
def _another_check(*args, **kw):
|
|
raise NotImplementedError()
|
|
|
|
class Foo:
|
|
invariant(_check)
|
|
invariant(_another_check)
|
|
|
|
self.assertEqual(getattr(Foo, TAGGED_DATA, None),
|
|
{'invariants': [_check, _another_check]})
|
|
|
|
|
|
class Test_taggedValue(unittest.TestCase):
|
|
|
|
def test_w_single(self):
|
|
from zope.interface.interface import TAGGED_DATA
|
|
from zope.interface.interface import taggedValue
|
|
|
|
class Foo:
|
|
taggedValue('bar', ['baz'])
|
|
|
|
self.assertEqual(getattr(Foo, TAGGED_DATA, None),
|
|
{'bar': ['baz']})
|
|
|
|
def test_w_multiple(self):
|
|
from zope.interface.interface import TAGGED_DATA
|
|
from zope.interface.interface import taggedValue
|
|
|
|
class Foo:
|
|
taggedValue('bar', ['baz'])
|
|
taggedValue('qux', 'spam')
|
|
|
|
self.assertEqual(getattr(Foo, TAGGED_DATA, None),
|
|
{'bar': ['baz'], 'qux': 'spam'})
|
|
|
|
def test_w_multiple_overwriting(self):
|
|
from zope.interface.interface import TAGGED_DATA
|
|
from zope.interface.interface import taggedValue
|
|
|
|
class Foo:
|
|
taggedValue('bar', ['baz'])
|
|
taggedValue('qux', 'spam')
|
|
taggedValue('bar', 'frob')
|
|
|
|
self.assertEqual(getattr(Foo, TAGGED_DATA, None),
|
|
{'bar': 'frob', 'qux': 'spam'})
|
|
|
|
|
|
class ElementTests(unittest.TestCase):
|
|
|
|
DEFAULT_NAME = 'AnElement'
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import Element
|
|
return Element
|
|
|
|
def _makeOne(self, name=None):
|
|
if name is None:
|
|
name = self.DEFAULT_NAME
|
|
return self._getTargetClass()(name)
|
|
|
|
def test_ctor_defaults(self):
|
|
element = self._makeOne()
|
|
self.assertEqual(element.__name__, self.DEFAULT_NAME)
|
|
self.assertEqual(element.getName(), self.DEFAULT_NAME)
|
|
self.assertEqual(element.__doc__, '')
|
|
self.assertEqual(element.getDoc(), '')
|
|
self.assertEqual(list(element.getTaggedValueTags()), [])
|
|
|
|
def test_ctor_no_doc_space_in_name(self):
|
|
element = self._makeOne('An Element')
|
|
self.assertEqual(element.__name__, None)
|
|
self.assertEqual(element.__doc__, 'An Element')
|
|
|
|
def test_getTaggedValue_miss(self):
|
|
element = self._makeOne()
|
|
self.assertRaises(KeyError, element.getTaggedValue, 'nonesuch')
|
|
|
|
def test_getDirectTaggedValueTags(self):
|
|
element = self._makeOne()
|
|
self.assertEqual([], list(element.getDirectTaggedValueTags()))
|
|
|
|
element.setTaggedValue('foo', 'bar')
|
|
self.assertEqual(['foo'], list(element.getDirectTaggedValueTags()))
|
|
|
|
def test_queryTaggedValue_miss(self):
|
|
element = self._makeOne()
|
|
self.assertEqual(element.queryTaggedValue('nonesuch'), None)
|
|
|
|
def test_queryTaggedValue_miss_w_default(self):
|
|
element = self._makeOne()
|
|
self.assertEqual(element.queryTaggedValue('nonesuch', 'bar'), 'bar')
|
|
|
|
def test_getDirectTaggedValue_miss(self):
|
|
element = self._makeOne()
|
|
self.assertRaises(KeyError, element.getDirectTaggedValue, 'nonesuch')
|
|
|
|
def test_queryDirectTaggedValue_miss(self):
|
|
element = self._makeOne()
|
|
self.assertEqual(element.queryDirectTaggedValue('nonesuch'), None)
|
|
|
|
def test_queryDirectTaggedValue_miss_w_default(self):
|
|
element = self._makeOne()
|
|
self.assertEqual(
|
|
element.queryDirectTaggedValue('nonesuch', 'bar'), 'bar'
|
|
)
|
|
|
|
def test_setTaggedValue(self):
|
|
element = self._makeOne()
|
|
element.setTaggedValue('foo', 'bar')
|
|
self.assertEqual(list(element.getTaggedValueTags()), ['foo'])
|
|
self.assertEqual(element.getTaggedValue('foo'), 'bar')
|
|
self.assertEqual(element.queryTaggedValue('foo'), 'bar')
|
|
|
|
def test_verifies(self):
|
|
from zope.interface.interfaces import IElement
|
|
from zope.interface.verify import verifyObject
|
|
|
|
element = self._makeOne()
|
|
verifyObject(IElement, element)
|
|
|
|
|
|
class GenericSpecificationBaseTests(unittest.TestCase):
|
|
# Tests that work with both implementations
|
|
def _getFallbackClass(self):
|
|
from zope.interface.interface import SpecificationBasePy
|
|
return SpecificationBasePy
|
|
|
|
_getTargetClass = _getFallbackClass
|
|
|
|
def _makeOne(self):
|
|
return self._getTargetClass()()
|
|
|
|
def test_providedBy_miss(self):
|
|
from zope.interface import interface
|
|
from zope.interface.declarations import _empty
|
|
sb = self._makeOne()
|
|
|
|
def _providedBy(obj):
|
|
return _empty
|
|
|
|
with _Monkey(interface, providedBy=_providedBy):
|
|
self.assertFalse(sb.providedBy(object()))
|
|
|
|
def test_implementedBy_miss(self):
|
|
from zope.interface import interface
|
|
from zope.interface.declarations import _empty
|
|
sb = self._makeOne()
|
|
|
|
def _implementedBy(obj):
|
|
return _empty
|
|
|
|
with _Monkey(interface, implementedBy=_implementedBy):
|
|
self.assertFalse(sb.implementedBy(object()))
|
|
|
|
|
|
class SpecificationBaseTests(
|
|
GenericSpecificationBaseTests,
|
|
OptimizationTestMixin,
|
|
SubclassableMixin,
|
|
):
|
|
# Tests that use the C implementation
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import SpecificationBase
|
|
return SpecificationBase
|
|
|
|
|
|
class SpecificationBasePyTests(GenericSpecificationBaseTests):
|
|
# Tests that only work with the Python implementation
|
|
|
|
def test___call___miss(self):
|
|
sb = self._makeOne()
|
|
sb._implied = {} # not defined by SpecificationBasePy
|
|
self.assertFalse(sb.isOrExtends(object()))
|
|
|
|
def test___call___hit(self):
|
|
sb = self._makeOne()
|
|
testing = object()
|
|
sb._implied = {testing: {}} # not defined by SpecificationBasePy
|
|
self.assertTrue(sb(testing))
|
|
|
|
def test_isOrExtends_miss(self):
|
|
sb = self._makeOne()
|
|
sb._implied = {} # not defined by SpecificationBasePy
|
|
self.assertFalse(sb.isOrExtends(object()))
|
|
|
|
def test_isOrExtends_hit(self):
|
|
sb = self._makeOne()
|
|
testing = object()
|
|
sb._implied = {testing: {}} # not defined by SpecificationBasePy
|
|
self.assertTrue(sb(testing))
|
|
|
|
def test_implementedBy_hit(self):
|
|
from zope.interface import interface
|
|
sb = self._makeOne()
|
|
|
|
class _Decl:
|
|
_implied = {sb: {}}
|
|
|
|
def _implementedBy(obj):
|
|
return _Decl()
|
|
|
|
with _Monkey(interface, implementedBy=_implementedBy):
|
|
self.assertTrue(sb.implementedBy(object()))
|
|
|
|
def test_providedBy_hit(self):
|
|
from zope.interface import interface
|
|
sb = self._makeOne()
|
|
|
|
class _Decl:
|
|
_implied = {sb: {}}
|
|
|
|
def _providedBy(obj):
|
|
return _Decl()
|
|
|
|
with _Monkey(interface, providedBy=_providedBy):
|
|
self.assertTrue(sb.providedBy(object()))
|
|
|
|
|
|
class NameAndModuleComparisonTestsMixin(CleanUp):
|
|
|
|
def _makeOneToCompare(self):
|
|
return self._makeOne('a', 'b')
|
|
|
|
def __check_NotImplemented_comparison(self, name):
|
|
# Without the correct attributes of __name__ and __module__,
|
|
# comparison switches to the reverse direction.
|
|
|
|
import operator
|
|
ib = self._makeOneToCompare()
|
|
op = getattr(operator, name)
|
|
meth = getattr(ib, '__%s__' % name)
|
|
|
|
# If either the __name__ or __module__ attribute
|
|
# is missing from the other object, then we return
|
|
# NotImplemented.
|
|
class RaisesErrorOnMissing:
|
|
Exc = AttributeError
|
|
|
|
def __getattribute__(self, name):
|
|
try:
|
|
return object.__getattribute__(self, name)
|
|
except AttributeError:
|
|
exc = RaisesErrorOnMissing.Exc
|
|
raise exc(name)
|
|
|
|
class RaisesErrorOnModule(RaisesErrorOnMissing):
|
|
def __init__(self):
|
|
self.__name__ = 'foo'
|
|
|
|
@property
|
|
def __module__(self):
|
|
raise AttributeError
|
|
|
|
class RaisesErrorOnName(RaisesErrorOnMissing):
|
|
def __init__(self):
|
|
self.__module__ = 'foo'
|
|
|
|
self.assertEqual(RaisesErrorOnModule().__name__, 'foo')
|
|
self.assertEqual(RaisesErrorOnName().__module__, 'foo')
|
|
with self.assertRaises(AttributeError):
|
|
getattr(RaisesErrorOnModule(), '__module__')
|
|
with self.assertRaises(AttributeError):
|
|
getattr(RaisesErrorOnName(), '__name__')
|
|
|
|
for cls in RaisesErrorOnModule, RaisesErrorOnName:
|
|
self.assertIs(meth(cls()), NotImplemented)
|
|
|
|
# If the other object has a comparison function, returning
|
|
# NotImplemented means Python calls it.
|
|
|
|
class AllowsAnyComparison(RaisesErrorOnMissing):
|
|
def __eq__(self, other):
|
|
return True
|
|
__lt__ = __eq__
|
|
__le__ = __eq__
|
|
__gt__ = __eq__
|
|
__ge__ = __eq__
|
|
__ne__ = __eq__
|
|
|
|
self.assertTrue(op(ib, AllowsAnyComparison()))
|
|
self.assertIs(meth(AllowsAnyComparison()), NotImplemented)
|
|
|
|
# If it doesn't have the comparison, Python raises a TypeError.
|
|
class AllowsNoComparison:
|
|
__eq__ = None
|
|
__lt__ = __eq__
|
|
__le__ = __eq__
|
|
__gt__ = __eq__
|
|
__ge__ = __eq__
|
|
__ne__ = __eq__
|
|
|
|
self.assertIs(meth(AllowsNoComparison()), NotImplemented)
|
|
with self.assertRaises(TypeError):
|
|
op(ib, AllowsNoComparison())
|
|
|
|
# Errors besides AttributeError are passed
|
|
class MyException(Exception):
|
|
pass
|
|
|
|
RaisesErrorOnMissing.Exc = MyException
|
|
|
|
with self.assertRaises(MyException):
|
|
getattr(RaisesErrorOnModule(), '__module__')
|
|
with self.assertRaises(MyException):
|
|
getattr(RaisesErrorOnName(), '__name__')
|
|
|
|
for cls in RaisesErrorOnModule, RaisesErrorOnName:
|
|
with self.assertRaises(MyException):
|
|
op(ib, cls())
|
|
with self.assertRaises(MyException):
|
|
meth(cls())
|
|
|
|
def test__lt__NotImplemented(self):
|
|
self.__check_NotImplemented_comparison('lt')
|
|
|
|
def test__le__NotImplemented(self):
|
|
self.__check_NotImplemented_comparison('le')
|
|
|
|
def test__gt__NotImplemented(self):
|
|
self.__check_NotImplemented_comparison('gt')
|
|
|
|
def test__ge__NotImplemented(self):
|
|
self.__check_NotImplemented_comparison('ge')
|
|
|
|
|
|
class InterfaceBaseTestsMixin(NameAndModuleComparisonTestsMixin):
|
|
# Tests for both C and Python implementation
|
|
|
|
def _getTargetClass(self):
|
|
raise NotImplementedError
|
|
|
|
def _getFallbackClass(self):
|
|
# pylint:disable=no-name-in-module
|
|
from zope.interface.interface import InterfaceBasePy
|
|
return InterfaceBasePy
|
|
|
|
def _makeOne(self, object_should_provide=False, name=None, module=None):
|
|
|
|
class IB(self._getTargetClass()):
|
|
def _call_conform(self, conform):
|
|
return conform(self)
|
|
|
|
def providedBy(self, obj):
|
|
return object_should_provide
|
|
|
|
return IB(name, module)
|
|
|
|
def test___call___w___conform___returning_value(self):
|
|
ib = self._makeOne(False)
|
|
conformed = object()
|
|
|
|
class _Adapted:
|
|
def __conform__(self, iface):
|
|
return conformed
|
|
|
|
self.assertIs(ib(_Adapted()), conformed)
|
|
|
|
def test___call___wo___conform___ob_no_provides_w_alternate(self):
|
|
ib = self._makeOne(False)
|
|
__traceback_info__ = ib, self._getTargetClass()
|
|
adapted = object()
|
|
alternate = object()
|
|
self.assertIs(ib(adapted, alternate), alternate)
|
|
|
|
def test___call___w___conform___ob_no_provides_wo_alternate(self):
|
|
ib = self._makeOne(False)
|
|
with self.assertRaises(TypeError) as exc:
|
|
ib(object())
|
|
|
|
self.assertIn('Could not adapt', str(exc.exception))
|
|
|
|
def test___call___w_no_conform_catches_only_AttributeError(self):
|
|
MissingSomeAttrs.test_raises(
|
|
self, self._makeOne(), expected_missing='__conform__'
|
|
)
|
|
|
|
|
|
class InterfaceBaseTests(
|
|
InterfaceBaseTestsMixin,
|
|
OptimizationTestMixin,
|
|
SubclassableMixin,
|
|
unittest.TestCase,
|
|
):
|
|
# Tests that work with the C implementation
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import InterfaceBase
|
|
return InterfaceBase
|
|
|
|
|
|
class InterfaceBasePyTests(InterfaceBaseTestsMixin, unittest.TestCase):
|
|
# Tests that only work with the Python implementation
|
|
|
|
_getTargetClass = InterfaceBaseTestsMixin._getFallbackClass
|
|
|
|
def test___call___w___conform___miss_ob_provides(self):
|
|
ib = self._makeOne(True)
|
|
|
|
class _Adapted:
|
|
def __conform__(self, iface):
|
|
return None
|
|
|
|
adapted = _Adapted()
|
|
self.assertIs(ib(adapted), adapted)
|
|
|
|
def test___adapt___ob_provides(self):
|
|
ib = self._makeOne(True)
|
|
adapted = object()
|
|
self.assertIs(ib.__adapt__(adapted), adapted)
|
|
|
|
def test___adapt___ob_no_provides_uses_hooks(self):
|
|
from zope.interface import interface
|
|
ib = self._makeOne(False)
|
|
adapted = object()
|
|
_missed = []
|
|
|
|
def _hook_miss(iface, obj):
|
|
_missed.append((iface, obj))
|
|
|
|
def _hook_hit(iface, obj):
|
|
return obj
|
|
|
|
with _Monkey(interface, adapter_hooks=[_hook_miss, _hook_hit]):
|
|
self.assertIs(ib.__adapt__(adapted), adapted)
|
|
self.assertEqual(_missed, [(ib, adapted)])
|
|
|
|
|
|
class SpecificationTests(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import Specification
|
|
return Specification
|
|
|
|
def _makeOne(self, bases=_marker):
|
|
if bases is _marker:
|
|
return self._getTargetClass()()
|
|
return self._getTargetClass()(bases)
|
|
|
|
def test_ctor(self):
|
|
from zope.interface.interface import Interface
|
|
spec = self._makeOne()
|
|
self.assertEqual(spec.__bases__, ())
|
|
self.assertEqual(len(spec._implied), 2)
|
|
self.assertTrue(spec in spec._implied)
|
|
self.assertTrue(Interface in spec._implied)
|
|
self.assertEqual(len(spec.dependents), 0)
|
|
|
|
def test_subscribe_first_time(self):
|
|
spec = self._makeOne()
|
|
dep = DummyDependent()
|
|
spec.subscribe(dep)
|
|
self.assertEqual(len(spec.dependents), 1)
|
|
self.assertEqual(spec.dependents[dep], 1)
|
|
|
|
def test_subscribe_again(self):
|
|
spec = self._makeOne()
|
|
dep = DummyDependent()
|
|
spec.subscribe(dep)
|
|
spec.subscribe(dep)
|
|
self.assertEqual(spec.dependents[dep], 2)
|
|
|
|
def test_unsubscribe_miss(self):
|
|
spec = self._makeOne()
|
|
dep = DummyDependent()
|
|
self.assertRaises(KeyError, spec.unsubscribe, dep)
|
|
|
|
def test_unsubscribe(self):
|
|
spec = self._makeOne()
|
|
dep = DummyDependent()
|
|
spec.subscribe(dep)
|
|
spec.subscribe(dep)
|
|
spec.unsubscribe(dep)
|
|
self.assertEqual(spec.dependents[dep], 1)
|
|
spec.unsubscribe(dep)
|
|
self.assertFalse(dep in spec.dependents)
|
|
|
|
def test___setBases_subscribes_bases_and_notifies_dependents(self):
|
|
from zope.interface.interface import Interface
|
|
spec = self._makeOne()
|
|
dep = DummyDependent()
|
|
spec.subscribe(dep)
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
class IBar(Interface):
|
|
pass
|
|
|
|
spec.__bases__ = (IFoo,)
|
|
self.assertEqual(dep._changed, [spec])
|
|
self.assertEqual(IFoo.dependents[spec], 1)
|
|
spec.__bases__ = (IBar,)
|
|
self.assertEqual(IFoo.dependents.get(spec), None)
|
|
self.assertEqual(IBar.dependents[spec], 1)
|
|
|
|
def test_changed_clears_volatiles_and_implied(self):
|
|
from zope.interface.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
spec = self._makeOne()
|
|
spec._v_attrs = 'Foo'
|
|
spec._implied[IFoo] = ()
|
|
spec.changed(spec)
|
|
self.assertIsNone(spec._v_attrs)
|
|
self.assertFalse(IFoo in spec._implied)
|
|
|
|
def test_interfaces_skips_already_seen(self):
|
|
from zope.interface.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
spec = self._makeOne([IFoo, IFoo])
|
|
self.assertEqual(list(spec.interfaces()), [IFoo])
|
|
|
|
def test_extends_strict_wo_self(self):
|
|
from zope.interface.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
spec = self._makeOne(IFoo)
|
|
self.assertFalse(spec.extends(IFoo, strict=True))
|
|
|
|
def test_extends_strict_w_self(self):
|
|
spec = self._makeOne()
|
|
self.assertFalse(spec.extends(spec, strict=True))
|
|
|
|
def test_extends_non_strict_w_self(self):
|
|
spec = self._makeOne()
|
|
self.assertTrue(spec.extends(spec, strict=False))
|
|
|
|
def test_get_hit_w__v_attrs(self):
|
|
spec = self._makeOne()
|
|
foo = object()
|
|
spec._v_attrs = {'foo': foo}
|
|
self.assertTrue(spec.get('foo') is foo)
|
|
|
|
def test_get_hit_from_base_wo__v_attrs(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
foo = Attribute('foo')
|
|
|
|
class IBar(Interface):
|
|
bar = Attribute('bar')
|
|
|
|
spec = self._makeOne([IFoo, IBar])
|
|
self.assertTrue(spec.get('foo') is IFoo.get('foo'))
|
|
self.assertTrue(spec.get('bar') is IBar.get('bar'))
|
|
|
|
def test_multiple_inheritance_no_interfaces(self):
|
|
# If we extend an object that implements interfaces,
|
|
# plus one that doesn't, we do not interject `Interface`
|
|
# early in the resolution order. It stays at the end,
|
|
# like it should.
|
|
# See https://github.com/zopefoundation/zope.interface/issues/8
|
|
from zope.interface.declarations import implementedBy
|
|
from zope.interface.declarations import implementer
|
|
from zope.interface.interface import Interface
|
|
|
|
class IDefaultViewName(Interface):
|
|
pass
|
|
|
|
class Context:
|
|
pass
|
|
|
|
class RDBModel(Context):
|
|
pass
|
|
|
|
class IOther(Interface):
|
|
pass
|
|
|
|
@implementer(IOther)
|
|
class OtherBase:
|
|
pass
|
|
|
|
class Model(OtherBase, Context):
|
|
pass
|
|
|
|
self.assertEqual(
|
|
implementedBy(Model).__sro__,
|
|
(
|
|
implementedBy(Model),
|
|
implementedBy(OtherBase),
|
|
IOther,
|
|
implementedBy(Context),
|
|
implementedBy(object),
|
|
Interface, # This used to be wrong, it used to be 2 too high.
|
|
)
|
|
)
|
|
|
|
|
|
class InterfaceClassTests(unittest.TestCase):
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
return InterfaceClass
|
|
|
|
def _makeOne(self, name='ITest', bases=(), attrs=None, __doc__=None,
|
|
__module__=None):
|
|
return self._getTargetClass()(name, bases, attrs, __doc__, __module__)
|
|
|
|
def test_ctor_defaults(self):
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting')
|
|
self.assertEqual(inst.__name__, 'ITesting')
|
|
self.assertEqual(inst.__doc__, '')
|
|
self.assertEqual(inst.__bases__, ())
|
|
self.assertEqual(inst.getBases(), ())
|
|
|
|
def test_ctor_bad_bases(self):
|
|
klass = self._getTargetClass()
|
|
self.assertRaises(TypeError, klass, 'ITesting', (object(),))
|
|
|
|
def test_ctor_w_attrs_attrib_methods(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting', attrs=ATTRS)
|
|
self.assertEqual(inst.__name__, 'ITesting')
|
|
self.assertEqual(inst.__doc__, '')
|
|
self.assertEqual(inst.__bases__, ())
|
|
self.assertEqual(inst.names(), ATTRS.keys())
|
|
|
|
def test_ctor_attrs_w___locals__(self):
|
|
ATTRS = {'__locals__': {}}
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting', attrs=ATTRS)
|
|
self.assertEqual(inst.__name__, 'ITesting')
|
|
self.assertEqual(inst.__doc__, '')
|
|
self.assertEqual(inst.__bases__, ())
|
|
self.assertEqual(list(inst.names()), [])
|
|
|
|
def test_ctor_attrs_w___annotations__(self):
|
|
ATTRS = {'__annotations__': {}}
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting', attrs=ATTRS)
|
|
self.assertEqual(inst.__name__, 'ITesting')
|
|
self.assertEqual(inst.__doc__, '')
|
|
self.assertEqual(inst.__bases__, ())
|
|
self.assertEqual(list(inst.names()), [])
|
|
|
|
def test_ctor_attrs_w__decorator_non_return(self):
|
|
from zope.interface.interface import _decorator_non_return
|
|
ATTRS = {'dropme': _decorator_non_return}
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting', attrs=ATTRS)
|
|
self.assertEqual(inst.__name__, 'ITesting')
|
|
self.assertEqual(inst.__doc__, '')
|
|
self.assertEqual(inst.__bases__, ())
|
|
self.assertEqual(list(inst.names()), [])
|
|
|
|
def test_ctor_attrs_w_invalid_attr_type(self):
|
|
from zope.interface.exceptions import InvalidInterface
|
|
ATTRS = {'invalid': object()}
|
|
klass = self._getTargetClass()
|
|
self.assertRaises(InvalidInterface, klass, 'ITesting', attrs=ATTRS)
|
|
|
|
def test_ctor_w_explicit___doc__(self):
|
|
ATTRS = {'__doc__': 'ATTR'}
|
|
klass = self._getTargetClass()
|
|
inst = klass('ITesting', attrs=ATTRS, __doc__='EXPLICIT')
|
|
self.assertEqual(inst.__doc__, 'EXPLICIT')
|
|
|
|
def test_interfaces(self):
|
|
iface = self._makeOne()
|
|
self.assertEqual(list(iface.interfaces()), [iface])
|
|
|
|
def test_getBases(self):
|
|
iface = self._makeOne()
|
|
sub = self._makeOne('ISub', bases=(iface,))
|
|
self.assertEqual(sub.getBases(), (iface,))
|
|
|
|
def test_isEqualOrExtendedBy_identity(self):
|
|
iface = self._makeOne()
|
|
self.assertTrue(iface.isEqualOrExtendedBy(iface))
|
|
|
|
def test_isEqualOrExtendedBy_subiface(self):
|
|
iface = self._makeOne()
|
|
sub = self._makeOne('ISub', bases=(iface,))
|
|
self.assertTrue(iface.isEqualOrExtendedBy(sub))
|
|
self.assertFalse(sub.isEqualOrExtendedBy(iface))
|
|
|
|
def test_isEqualOrExtendedBy_unrelated(self):
|
|
one = self._makeOne('One')
|
|
another = self._makeOne('Another')
|
|
self.assertFalse(one.isEqualOrExtendedBy(another))
|
|
self.assertFalse(another.isEqualOrExtendedBy(one))
|
|
|
|
def test_names_w_all_False_ignores_bases(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(sorted(derived.names(all=False)), ['baz'])
|
|
|
|
def test_names_w_all_True_no_bases(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
one = self._makeOne(attrs=ATTRS)
|
|
self.assertEqual(sorted(one.names(all=True)), ['bar', 'foo'])
|
|
|
|
def test_names_w_all_True_w_bases_simple(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(
|
|
sorted(derived.names(all=True)), ['bar', 'baz', 'foo']
|
|
)
|
|
|
|
def test_names_w_all_True_bases_w_same_names(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
def _foo():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'foo': fromFunction(_foo),
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(sorted(
|
|
derived.names(all=True)), ['bar', 'baz', 'foo']
|
|
)
|
|
|
|
def test___iter__(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
def _foo():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'foo': fromFunction(_foo),
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(sorted(derived), ['bar', 'baz', 'foo'])
|
|
|
|
def test_namesAndDescriptions_w_all_False_ignores_bases(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(
|
|
sorted(derived.namesAndDescriptions(all=False)), [
|
|
('baz', DERIVED_ATTRS['baz']),
|
|
]
|
|
)
|
|
|
|
def test_namesAndDescriptions_w_all_True_no_bases(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
one = self._makeOne(attrs=ATTRS)
|
|
self.assertEqual(
|
|
sorted(one.namesAndDescriptions(all=False)), [
|
|
('bar', ATTRS['bar']),
|
|
('foo', ATTRS['foo']),
|
|
]
|
|
)
|
|
|
|
def test_namesAndDescriptions_w_all_True_simple(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(
|
|
sorted(derived.namesAndDescriptions(all=True)), [
|
|
('bar', BASE_ATTRS['bar']),
|
|
('baz', DERIVED_ATTRS['baz']),
|
|
('foo', BASE_ATTRS['foo']),
|
|
]
|
|
)
|
|
|
|
def test_namesAndDescriptions_w_all_True_bases_w_same_names(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
def _foo():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'foo': fromFunction(_foo),
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(
|
|
sorted(derived.namesAndDescriptions(all=True)), [
|
|
('bar', BASE_ATTRS['bar']),
|
|
('baz', DERIVED_ATTRS['baz']),
|
|
('foo', DERIVED_ATTRS['foo']),
|
|
]
|
|
)
|
|
|
|
def test_getDescriptionFor_miss(self):
|
|
one = self._makeOne()
|
|
self.assertRaises(KeyError, one.getDescriptionFor, 'nonesuch')
|
|
|
|
def test_getDescriptionFor_hit(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
one = self._makeOne(attrs=ATTRS)
|
|
self.assertEqual(one.getDescriptionFor('foo'), ATTRS['foo'])
|
|
self.assertEqual(one.getDescriptionFor('bar'), ATTRS['bar'])
|
|
|
|
def test___getitem___miss(self):
|
|
one = self._makeOne()
|
|
|
|
def _test():
|
|
return one['nonesuch']
|
|
|
|
self.assertRaises(KeyError, _test)
|
|
|
|
def test___getitem___hit(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
one = self._makeOne(attrs=ATTRS)
|
|
self.assertEqual(one['foo'], ATTRS['foo'])
|
|
self.assertEqual(one['bar'], ATTRS['bar'])
|
|
|
|
def test___contains___miss(self):
|
|
one = self._makeOne()
|
|
self.assertFalse('nonesuch' in one)
|
|
|
|
def test___contains___hit(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
one = self._makeOne(attrs=ATTRS)
|
|
self.assertTrue('foo' in one)
|
|
self.assertTrue('bar' in one)
|
|
|
|
def test_direct_miss(self):
|
|
one = self._makeOne()
|
|
self.assertEqual(one.direct('nonesuch'), None)
|
|
|
|
def test_direct_hit_local_miss_bases(self):
|
|
from zope.interface.interface import Attribute
|
|
from zope.interface.interface import fromFunction
|
|
|
|
def _bar():
|
|
"""DOCSTRING"""
|
|
|
|
def _foo():
|
|
"""DOCSTRING"""
|
|
|
|
BASE_ATTRS = {
|
|
'foo': Attribute('Foo', ''),
|
|
'bar': fromFunction(_bar),
|
|
}
|
|
DERIVED_ATTRS = {
|
|
'foo': fromFunction(_foo),
|
|
'baz': Attribute('Baz', ''),
|
|
}
|
|
base = self._makeOne('IBase', attrs=BASE_ATTRS)
|
|
derived = self._makeOne('IDerived', bases=(base,), attrs=DERIVED_ATTRS)
|
|
self.assertEqual(derived.direct('foo'), DERIVED_ATTRS['foo'])
|
|
self.assertEqual(derived.direct('baz'), DERIVED_ATTRS['baz'])
|
|
self.assertEqual(derived.direct('bar'), None)
|
|
|
|
def test_queryDescriptionFor_miss(self):
|
|
iface = self._makeOne()
|
|
self.assertEqual(iface.queryDescriptionFor('nonesuch'), None)
|
|
|
|
def test_queryDescriptionFor_hit(self):
|
|
from zope.interface import Attribute
|
|
ATTRS = {'attr': Attribute('Title', 'Description')}
|
|
iface = self._makeOne(attrs=ATTRS)
|
|
self.assertEqual(iface.queryDescriptionFor('attr'), ATTRS['attr'])
|
|
|
|
def test_validateInvariants_pass(self):
|
|
_called_with = []
|
|
|
|
def _passable(*args, **kw):
|
|
_called_with.append((args, kw))
|
|
return True
|
|
|
|
iface = self._makeOne()
|
|
obj = object()
|
|
iface.setTaggedValue('invariants', [_passable])
|
|
self.assertEqual(iface.validateInvariants(obj), None)
|
|
self.assertEqual(_called_with, [((obj,), {})])
|
|
|
|
def test_validateInvariants_fail_wo_errors_passed(self):
|
|
from zope.interface.exceptions import Invalid
|
|
_passable_called_with = []
|
|
|
|
def _passable(*args, **kw):
|
|
_passable_called_with.append((args, kw))
|
|
return True
|
|
|
|
_fail_called_with = []
|
|
|
|
def _fail(*args, **kw):
|
|
_fail_called_with.append((args, kw))
|
|
raise Invalid
|
|
|
|
iface = self._makeOne()
|
|
obj = object()
|
|
iface.setTaggedValue('invariants', [_passable, _fail])
|
|
self.assertRaises(Invalid, iface.validateInvariants, obj)
|
|
self.assertEqual(_passable_called_with, [((obj,), {})])
|
|
self.assertEqual(_fail_called_with, [((obj,), {})])
|
|
|
|
def test_validateInvariants_fail_w_errors_passed(self):
|
|
from zope.interface.exceptions import Invalid
|
|
_errors = []
|
|
_fail_called_with = []
|
|
|
|
def _fail(*args, **kw):
|
|
_fail_called_with.append((args, kw))
|
|
raise Invalid
|
|
|
|
iface = self._makeOne()
|
|
obj = object()
|
|
iface.setTaggedValue('invariants', [_fail])
|
|
self.assertRaises(Invalid, iface.validateInvariants, obj, _errors)
|
|
self.assertEqual(_fail_called_with, [((obj,), {})])
|
|
self.assertEqual(len(_errors), 1)
|
|
self.assertTrue(isinstance(_errors[0], Invalid))
|
|
|
|
def test_validateInvariants_fail_in_base_wo_errors_passed(self):
|
|
from zope.interface.exceptions import Invalid
|
|
_passable_called_with = []
|
|
|
|
def _passable(*args, **kw):
|
|
_passable_called_with.append((args, kw))
|
|
return True
|
|
|
|
_fail_called_with = []
|
|
|
|
def _fail(*args, **kw):
|
|
_fail_called_with.append((args, kw))
|
|
raise Invalid
|
|
|
|
base = self._makeOne('IBase')
|
|
derived = self._makeOne('IDerived', (base,))
|
|
obj = object()
|
|
base.setTaggedValue('invariants', [_fail])
|
|
derived.setTaggedValue('invariants', [_passable])
|
|
self.assertRaises(Invalid, derived.validateInvariants, obj)
|
|
self.assertEqual(_passable_called_with, [((obj,), {})])
|
|
self.assertEqual(_fail_called_with, [((obj,), {})])
|
|
|
|
def test_validateInvariants_fail_in_base_w_errors_passed(self):
|
|
from zope.interface.exceptions import Invalid
|
|
_errors = []
|
|
_passable_called_with = []
|
|
|
|
def _passable(*args, **kw):
|
|
_passable_called_with.append((args, kw))
|
|
return True
|
|
|
|
_fail_called_with = []
|
|
|
|
def _fail(*args, **kw):
|
|
_fail_called_with.append((args, kw))
|
|
raise Invalid
|
|
|
|
base = self._makeOne('IBase')
|
|
derived = self._makeOne('IDerived', (base,))
|
|
obj = object()
|
|
base.setTaggedValue('invariants', [_fail])
|
|
derived.setTaggedValue('invariants', [_passable])
|
|
self.assertRaises(Invalid, derived.validateInvariants, obj, _errors)
|
|
self.assertEqual(_passable_called_with, [((obj,), {})])
|
|
self.assertEqual(_fail_called_with, [((obj,), {})])
|
|
self.assertEqual(len(_errors), 1)
|
|
self.assertTrue(isinstance(_errors[0], Invalid))
|
|
|
|
def test_validateInvariants_inherited_not_called_multiple_times(self):
|
|
_passable_called_with = []
|
|
|
|
def _passable(*args, **kw):
|
|
_passable_called_with.append((args, kw))
|
|
return True
|
|
|
|
obj = object()
|
|
base = self._makeOne('IBase')
|
|
base.setTaggedValue('invariants', [_passable])
|
|
derived = self._makeOne('IDerived', (base,))
|
|
derived.validateInvariants(obj)
|
|
self.assertEqual(1, len(_passable_called_with))
|
|
|
|
def test___reduce__(self):
|
|
iface = self._makeOne('PickleMe')
|
|
self.assertEqual(iface.__reduce__(), 'PickleMe')
|
|
|
|
def test___hash___normal(self):
|
|
iface = self._makeOne('HashMe')
|
|
self.assertEqual(
|
|
hash(iface),
|
|
hash(('HashMe', 'zope.interface.tests.test_interface'))
|
|
)
|
|
|
|
def test___hash___missing_required_attrs(self):
|
|
|
|
class Derived(self._getTargetClass()):
|
|
def __init__(self): # pylint:disable=super-init-not-called
|
|
pass # Don't call base class.
|
|
|
|
derived = Derived()
|
|
with self.assertRaises(AttributeError):
|
|
hash(derived)
|
|
|
|
def test_comparison_with_None(self):
|
|
# pylint:disable=singleton-comparison,misplaced-comparison-constant
|
|
iface = self._makeOne()
|
|
self.assertTrue(iface < None) # noqa E711
|
|
self.assertTrue(iface <= None) # noqa E711
|
|
self.assertFalse(iface == None) # noqa E711
|
|
self.assertTrue(iface != None) # noqa E711
|
|
self.assertFalse(iface >= None) # noqa E711
|
|
self.assertFalse(iface > None) # noqa E711
|
|
|
|
self.assertFalse(None < iface) # noqa E711
|
|
self.assertFalse(None <= iface) # noqa E711
|
|
self.assertFalse(None == iface) # noqa E711
|
|
self.assertTrue(None != iface) # noqa E711
|
|
self.assertTrue(None >= iface) # noqa E711
|
|
self.assertTrue(None > iface) # noqa E711
|
|
|
|
def test_comparison_with_same_instance(self):
|
|
# pylint:disable=comparison-with-itself
|
|
iface = self._makeOne()
|
|
|
|
self.assertFalse(iface < iface)
|
|
self.assertTrue(iface <= iface)
|
|
self.assertTrue(iface == iface)
|
|
self.assertFalse(iface != iface)
|
|
self.assertTrue(iface >= iface)
|
|
self.assertFalse(iface > iface)
|
|
|
|
def test_comparison_with_same_named_instance_in_other_module(self):
|
|
|
|
one = self._makeOne('IName', __module__='zope.interface.tests.one')
|
|
other = self._makeOne('IName', __module__='zope.interface.tests.other')
|
|
|
|
self.assertTrue(one < other)
|
|
self.assertFalse(other < one)
|
|
self.assertTrue(one <= other)
|
|
self.assertFalse(other <= one)
|
|
self.assertFalse(one == other)
|
|
self.assertFalse(other == one)
|
|
self.assertTrue(one != other)
|
|
self.assertTrue(other != one)
|
|
self.assertFalse(one >= other)
|
|
self.assertTrue(other >= one)
|
|
self.assertFalse(one > other)
|
|
self.assertTrue(other > one)
|
|
|
|
def test_assignment_to__class__(self):
|
|
# https://github.com/zopefoundation/zope.interface/issues/6
|
|
class MyException(Exception):
|
|
pass
|
|
|
|
class MyInterfaceClass(self._getTargetClass()):
|
|
def __call__(self, target):
|
|
raise MyException(target)
|
|
|
|
IFoo = self._makeOne('IName')
|
|
self.assertIsInstance(IFoo, self._getTargetClass())
|
|
self.assertIs(type(IFoo), self._getTargetClass())
|
|
|
|
with self.assertRaises(TypeError):
|
|
IFoo(1)
|
|
|
|
IFoo.__class__ = MyInterfaceClass
|
|
self.assertIsInstance(IFoo, MyInterfaceClass)
|
|
self.assertIs(type(IFoo), MyInterfaceClass)
|
|
|
|
with self.assertRaises(MyException):
|
|
IFoo(1)
|
|
|
|
def test_assignment_to__class__2(self):
|
|
# https://github.com/zopefoundation/zope.interface/issues/6
|
|
# This is essentially a transcription of the
|
|
# test presented in the bug report.
|
|
from zope.interface import Interface
|
|
|
|
class MyInterfaceClass(self._getTargetClass()):
|
|
def __call__(self, *args):
|
|
return args
|
|
|
|
IFoo = MyInterfaceClass('IFoo', (Interface,))
|
|
self.assertEqual(IFoo(1), (1,))
|
|
|
|
class IBar(IFoo):
|
|
pass
|
|
|
|
self.assertEqual(IBar(1), (1,))
|
|
|
|
class ISpam(Interface):
|
|
pass
|
|
|
|
with self.assertRaises(TypeError):
|
|
ISpam()
|
|
|
|
ISpam.__class__ = MyInterfaceClass
|
|
self.assertEqual(ISpam(1), (1,))
|
|
|
|
def test__module__is_readonly(self):
|
|
inst = self._makeOne()
|
|
with self.assertRaises(AttributeError):
|
|
inst.__module__ = 'different.module'
|
|
|
|
|
|
class InterfaceTests(unittest.TestCase):
|
|
|
|
def test_attributes_link_to_interface(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class I1(Interface):
|
|
attr = Attribute("My attr")
|
|
|
|
self.assertTrue(I1['attr'].interface is I1)
|
|
|
|
def test_methods_link_to_interface(self):
|
|
from zope.interface import Interface
|
|
|
|
class I1(Interface):
|
|
def method(foo, bar, bingo):
|
|
"A method"
|
|
|
|
self.assertTrue(I1['method'].interface is I1)
|
|
|
|
def test_classImplements_simple(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import providedBy
|
|
|
|
class ICurrent(Interface):
|
|
def method1(a, b):
|
|
"""docstring"""
|
|
|
|
def method2(a, b):
|
|
"""docstring"""
|
|
|
|
class IOther(Interface):
|
|
pass
|
|
|
|
class Current:
|
|
__implemented__ = ICurrent
|
|
|
|
def method1(self, a, b):
|
|
raise NotImplementedError()
|
|
|
|
def method2(self, a, b):
|
|
raise NotImplementedError()
|
|
|
|
current = Current()
|
|
|
|
self.assertTrue(ICurrent.implementedBy(Current))
|
|
self.assertFalse(IOther.implementedBy(Current))
|
|
self.assertEqual(ICurrent, ICurrent)
|
|
self.assertTrue(ICurrent in implementedBy(Current))
|
|
self.assertFalse(IOther in implementedBy(Current))
|
|
self.assertTrue(ICurrent in providedBy(current))
|
|
self.assertFalse(IOther in providedBy(current))
|
|
|
|
def test_classImplements_base_not_derived(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import providedBy
|
|
|
|
class IBase(Interface):
|
|
def method():
|
|
"""docstring"""
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class Current():
|
|
__implemented__ = IBase
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
current = Current()
|
|
|
|
self.assertTrue(IBase.implementedBy(Current))
|
|
self.assertFalse(IDerived.implementedBy(Current))
|
|
self.assertTrue(IBase in implementedBy(Current))
|
|
self.assertFalse(IDerived in implementedBy(Current))
|
|
self.assertTrue(IBase in providedBy(current))
|
|
self.assertFalse(IDerived in providedBy(current))
|
|
|
|
def test_classImplements_base_and_derived(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import providedBy
|
|
|
|
class IBase(Interface):
|
|
def method():
|
|
"""docstring"""
|
|
|
|
class IDerived(IBase):
|
|
pass
|
|
|
|
class Current:
|
|
__implemented__ = IDerived
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
current = Current()
|
|
|
|
self.assertTrue(IBase.implementedBy(Current))
|
|
self.assertTrue(IDerived.implementedBy(Current))
|
|
self.assertFalse(IBase in implementedBy(Current))
|
|
self.assertTrue(IBase in implementedBy(Current).flattened())
|
|
self.assertTrue(IDerived in implementedBy(Current))
|
|
self.assertFalse(IBase in providedBy(current))
|
|
self.assertTrue(IBase in providedBy(current).flattened())
|
|
self.assertTrue(IDerived in providedBy(current))
|
|
|
|
def test_classImplements_multiple(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import providedBy
|
|
|
|
class ILeft(Interface):
|
|
def method():
|
|
"""docstring"""
|
|
|
|
class IRight(ILeft):
|
|
pass
|
|
|
|
class Left:
|
|
__implemented__ = ILeft
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
class Right:
|
|
__implemented__ = IRight
|
|
|
|
class Ambi(Left, Right):
|
|
pass
|
|
|
|
ambi = Ambi()
|
|
|
|
self.assertTrue(ILeft.implementedBy(Ambi))
|
|
self.assertTrue(IRight.implementedBy(Ambi))
|
|
self.assertTrue(ILeft in implementedBy(Ambi))
|
|
self.assertTrue(IRight in implementedBy(Ambi))
|
|
self.assertTrue(ILeft in providedBy(ambi))
|
|
self.assertTrue(IRight in providedBy(ambi))
|
|
|
|
def test_classImplements_multiple_w_explict_implements(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementedBy
|
|
from zope.interface import providedBy
|
|
|
|
class ILeft(Interface):
|
|
|
|
def method():
|
|
"""docstring"""
|
|
|
|
class IRight(ILeft):
|
|
pass
|
|
|
|
class IOther(Interface):
|
|
pass
|
|
|
|
class Left():
|
|
__implemented__ = ILeft
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
class Right:
|
|
__implemented__ = IRight
|
|
|
|
class Other:
|
|
__implemented__ = IOther
|
|
|
|
class Mixed(Left, Right):
|
|
__implemented__ = Left.__implemented__, Other.__implemented__
|
|
|
|
mixed = Mixed()
|
|
|
|
self.assertTrue(ILeft.implementedBy(Mixed))
|
|
self.assertFalse(IRight.implementedBy(Mixed))
|
|
self.assertTrue(IOther.implementedBy(Mixed))
|
|
self.assertTrue(ILeft in implementedBy(Mixed))
|
|
self.assertFalse(IRight in implementedBy(Mixed))
|
|
self.assertTrue(IOther in implementedBy(Mixed))
|
|
self.assertTrue(ILeft in providedBy(mixed))
|
|
self.assertFalse(IRight in providedBy(mixed))
|
|
self.assertTrue(IOther in providedBy(mixed))
|
|
|
|
def testInterfaceExtendsInterface(self):
|
|
from zope.interface import Interface
|
|
|
|
new = Interface.__class__
|
|
FunInterface = new('FunInterface')
|
|
BarInterface = new('BarInterface', (FunInterface,))
|
|
BobInterface = new('BobInterface')
|
|
BazInterface = new('BazInterface', (BobInterface, BarInterface,))
|
|
|
|
self.assertTrue(BazInterface.extends(BobInterface))
|
|
self.assertTrue(BazInterface.extends(BarInterface))
|
|
self.assertTrue(BazInterface.extends(FunInterface))
|
|
self.assertFalse(BobInterface.extends(FunInterface))
|
|
self.assertFalse(BobInterface.extends(BarInterface))
|
|
self.assertTrue(BarInterface.extends(FunInterface))
|
|
self.assertFalse(BarInterface.extends(BazInterface))
|
|
|
|
def test_verifyClass(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.verify import verifyClass
|
|
|
|
class ICheckMe(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"A method"
|
|
|
|
class CheckMe:
|
|
__implemented__ = ICheckMe
|
|
attr = 'value'
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
self.assertTrue(verifyClass(ICheckMe, CheckMe))
|
|
|
|
def test_verifyObject(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.verify import verifyObject
|
|
|
|
class ICheckMe(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"A method"
|
|
|
|
class CheckMe:
|
|
__implemented__ = ICheckMe
|
|
attr = 'value'
|
|
|
|
def method(self):
|
|
raise NotImplementedError()
|
|
|
|
check_me = CheckMe()
|
|
|
|
self.assertTrue(verifyObject(ICheckMe, check_me))
|
|
|
|
def test_interface_object_provides_Interface(self):
|
|
from zope.interface import Interface
|
|
|
|
class AnInterface(Interface):
|
|
pass
|
|
|
|
self.assertTrue(Interface.providedBy(AnInterface))
|
|
|
|
def test_names_simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"""docstring"""
|
|
|
|
self.assertEqual(sorted(ISimple.names()), ['attr', 'method'])
|
|
|
|
def test_names_derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"""docstring"""
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"""docstring"""
|
|
|
|
def method2():
|
|
"""docstring"""
|
|
|
|
self.assertEqual(sorted(IDerived.names()),
|
|
['attr2', 'method', 'method2'])
|
|
self.assertEqual(sorted(IDerived.names(all=True)),
|
|
['attr', 'attr2', 'method', 'method2'])
|
|
|
|
def test_namesAndDescriptions_simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
name_values = sorted(ISimple.namesAndDescriptions())
|
|
|
|
self.assertEqual(len(name_values), 2)
|
|
self.assertEqual(name_values[0][0], 'attr')
|
|
self.assertTrue(isinstance(name_values[0][1], Attribute))
|
|
self.assertEqual(name_values[0][1].__name__, 'attr')
|
|
self.assertEqual(name_values[0][1].__doc__, 'My attr')
|
|
self.assertEqual(name_values[1][0], 'method')
|
|
self.assertTrue(isinstance(name_values[1][1], Method))
|
|
self.assertEqual(name_values[1][1].__name__, 'method')
|
|
self.assertEqual(name_values[1][1].__doc__, 'My method')
|
|
|
|
def test_namesAndDescriptions_derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"My method, overridden"
|
|
|
|
def method2():
|
|
"My method2"
|
|
|
|
name_values = sorted(IDerived.namesAndDescriptions())
|
|
|
|
self.assertEqual(len(name_values), 3)
|
|
self.assertEqual(name_values[0][0], 'attr2')
|
|
self.assertTrue(isinstance(name_values[0][1], Attribute))
|
|
self.assertEqual(name_values[0][1].__name__, 'attr2')
|
|
self.assertEqual(name_values[0][1].__doc__, 'My attr2')
|
|
self.assertEqual(name_values[1][0], 'method')
|
|
self.assertTrue(isinstance(name_values[1][1], Method))
|
|
self.assertEqual(name_values[1][1].__name__, 'method')
|
|
self.assertEqual(name_values[1][1].__doc__, 'My method, overridden')
|
|
self.assertEqual(name_values[2][0], 'method2')
|
|
self.assertTrue(isinstance(name_values[2][1], Method))
|
|
self.assertEqual(name_values[2][1].__name__, 'method2')
|
|
self.assertEqual(name_values[2][1].__doc__, 'My method2')
|
|
|
|
name_values = sorted(IDerived.namesAndDescriptions(all=True))
|
|
|
|
self.assertEqual(len(name_values), 4)
|
|
self.assertEqual(name_values[0][0], 'attr')
|
|
self.assertTrue(isinstance(name_values[0][1], Attribute))
|
|
self.assertEqual(name_values[0][1].__name__, 'attr')
|
|
self.assertEqual(name_values[0][1].__doc__, 'My attr')
|
|
self.assertEqual(name_values[1][0], 'attr2')
|
|
self.assertTrue(isinstance(name_values[1][1], Attribute))
|
|
self.assertEqual(name_values[1][1].__name__, 'attr2')
|
|
self.assertEqual(name_values[1][1].__doc__, 'My attr2')
|
|
self.assertEqual(name_values[2][0], 'method')
|
|
self.assertTrue(isinstance(name_values[2][1], Method))
|
|
self.assertEqual(name_values[2][1].__name__, 'method')
|
|
self.assertEqual(name_values[2][1].__doc__, 'My method, overridden')
|
|
self.assertEqual(name_values[3][0], 'method2')
|
|
self.assertTrue(isinstance(name_values[3][1], Method))
|
|
self.assertEqual(name_values[3][1].__name__, 'method2')
|
|
self.assertEqual(name_values[3][1].__doc__, 'My method2')
|
|
|
|
def test_getDescriptionFor_nonesuch_no_default(self):
|
|
from zope.interface import Interface
|
|
|
|
class IEmpty(Interface):
|
|
pass
|
|
|
|
self.assertRaises(KeyError, IEmpty.getDescriptionFor, 'nonesuch')
|
|
|
|
def test_getDescriptionFor_simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
a_desc = ISimple.getDescriptionFor('attr')
|
|
self.assertTrue(isinstance(a_desc, Attribute))
|
|
self.assertEqual(a_desc.__name__, 'attr')
|
|
self.assertEqual(a_desc.__doc__, 'My attr')
|
|
|
|
m_desc = ISimple.getDescriptionFor('method')
|
|
self.assertTrue(isinstance(m_desc, Method))
|
|
self.assertEqual(m_desc.__name__, 'method')
|
|
self.assertEqual(m_desc.__doc__, 'My method')
|
|
|
|
def test_getDescriptionFor_derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"My method, overridden"
|
|
|
|
def method2():
|
|
"My method2"
|
|
|
|
a_desc = IDerived.getDescriptionFor('attr')
|
|
self.assertTrue(isinstance(a_desc, Attribute))
|
|
self.assertEqual(a_desc.__name__, 'attr')
|
|
self.assertEqual(a_desc.__doc__, 'My attr')
|
|
|
|
m_desc = IDerived.getDescriptionFor('method')
|
|
self.assertTrue(isinstance(m_desc, Method))
|
|
self.assertEqual(m_desc.__name__, 'method')
|
|
self.assertEqual(m_desc.__doc__, 'My method, overridden')
|
|
|
|
a2_desc = IDerived.getDescriptionFor('attr2')
|
|
self.assertTrue(isinstance(a2_desc, Attribute))
|
|
self.assertEqual(a2_desc.__name__, 'attr2')
|
|
self.assertEqual(a2_desc.__doc__, 'My attr2')
|
|
|
|
m2_desc = IDerived.getDescriptionFor('method2')
|
|
self.assertTrue(isinstance(m2_desc, Method))
|
|
self.assertEqual(m2_desc.__name__, 'method2')
|
|
self.assertEqual(m2_desc.__doc__, 'My method2')
|
|
|
|
def test___getitem__nonesuch(self):
|
|
from zope.interface import Interface
|
|
|
|
class IEmpty(Interface):
|
|
pass
|
|
|
|
self.assertRaises(KeyError, IEmpty.__getitem__, 'nonesuch')
|
|
|
|
def test___getitem__simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
a_desc = ISimple['attr']
|
|
self.assertTrue(isinstance(a_desc, Attribute))
|
|
self.assertEqual(a_desc.__name__, 'attr')
|
|
self.assertEqual(a_desc.__doc__, 'My attr')
|
|
|
|
m_desc = ISimple['method']
|
|
self.assertTrue(isinstance(m_desc, Method))
|
|
self.assertEqual(m_desc.__name__, 'method')
|
|
self.assertEqual(m_desc.__doc__, 'My method')
|
|
|
|
def test___getitem___derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import Method
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"My method, overridden"
|
|
|
|
def method2():
|
|
"My method2"
|
|
|
|
a_desc = IDerived['attr']
|
|
self.assertTrue(isinstance(a_desc, Attribute))
|
|
self.assertEqual(a_desc.__name__, 'attr')
|
|
self.assertEqual(a_desc.__doc__, 'My attr')
|
|
|
|
m_desc = IDerived['method']
|
|
self.assertTrue(isinstance(m_desc, Method))
|
|
self.assertEqual(m_desc.__name__, 'method')
|
|
self.assertEqual(m_desc.__doc__, 'My method, overridden')
|
|
|
|
a2_desc = IDerived['attr2']
|
|
self.assertTrue(isinstance(a2_desc, Attribute))
|
|
self.assertEqual(a2_desc.__name__, 'attr2')
|
|
self.assertEqual(a2_desc.__doc__, 'My attr2')
|
|
|
|
m2_desc = IDerived['method2']
|
|
self.assertTrue(isinstance(m2_desc, Method))
|
|
self.assertEqual(m2_desc.__name__, 'method2')
|
|
self.assertEqual(m2_desc.__doc__, 'My method2')
|
|
|
|
def test___contains__nonesuch(self):
|
|
from zope.interface import Interface
|
|
|
|
class IEmpty(Interface):
|
|
pass
|
|
|
|
self.assertFalse('nonesuch' in IEmpty)
|
|
|
|
def test___contains__simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
self.assertTrue('attr' in ISimple)
|
|
self.assertTrue('method' in ISimple)
|
|
|
|
def test___contains__derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"My method, overridden"
|
|
|
|
def method2():
|
|
"My method2"
|
|
|
|
self.assertTrue('attr' in IDerived)
|
|
self.assertTrue('method' in IDerived)
|
|
self.assertTrue('attr2' in IDerived)
|
|
self.assertTrue('method2' in IDerived)
|
|
|
|
def test___iter__empty(self):
|
|
from zope.interface import Interface
|
|
|
|
class IEmpty(Interface):
|
|
pass
|
|
|
|
self.assertEqual(list(IEmpty), [])
|
|
|
|
def test___iter__simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class ISimple(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
self.assertEqual(sorted(list(ISimple)), ['attr', 'method'])
|
|
|
|
def test___iter__derived(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class IBase(Interface):
|
|
attr = Attribute('My attr')
|
|
|
|
def method():
|
|
"My method"
|
|
|
|
class IDerived(IBase):
|
|
attr2 = Attribute('My attr2')
|
|
|
|
def method():
|
|
"My method, overridden"
|
|
|
|
def method2():
|
|
"My method2"
|
|
|
|
self.assertEqual(sorted(list(IDerived)),
|
|
['attr', 'attr2', 'method', 'method2'])
|
|
|
|
def test_function_attributes_become_tagged_values(self):
|
|
from zope.interface import Interface
|
|
|
|
class ITagMe(Interface):
|
|
def method():
|
|
"""docstring"""
|
|
method.optional = 1
|
|
|
|
method = ITagMe['method']
|
|
self.assertEqual(method.getTaggedValue('optional'), 1)
|
|
|
|
def test___doc___non_element(self):
|
|
from zope.interface import Interface
|
|
|
|
class IHaveADocString(Interface):
|
|
"xxx"
|
|
|
|
self.assertEqual(IHaveADocString.__doc__, "xxx")
|
|
self.assertEqual(list(IHaveADocString), [])
|
|
|
|
def test___doc___as_element(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class IHaveADocString(Interface):
|
|
"xxx"
|
|
__doc__ = Attribute('the doc')
|
|
|
|
self.assertEqual(IHaveADocString.__doc__, "")
|
|
self.assertEqual(list(IHaveADocString), ['__doc__'])
|
|
|
|
def _errorsEqual(self, has_invariant, error_len, error_msgs, iface):
|
|
from zope.interface.exceptions import Invalid
|
|
self.assertRaises(Invalid, iface.validateInvariants, has_invariant)
|
|
e = []
|
|
try:
|
|
iface.validateInvariants(has_invariant, e)
|
|
self.fail("validateInvariants should always raise")
|
|
except Invalid as error:
|
|
self.assertEqual(error.args[0], e)
|
|
|
|
self.assertEqual(len(e), error_len)
|
|
msgs = [error.args[0] for error in e]
|
|
msgs.sort()
|
|
for msg in msgs:
|
|
self.assertEqual(msg, error_msgs.pop(0))
|
|
|
|
def test_invariant_simple(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface import directlyProvides
|
|
from zope.interface import invariant
|
|
|
|
class IInvariant(Interface):
|
|
foo = Attribute('foo')
|
|
bar = Attribute('bar; must eval to Boolean True if foo does')
|
|
invariant(_ifFooThenBar)
|
|
|
|
class HasInvariant:
|
|
pass
|
|
|
|
# set up
|
|
has_invariant = HasInvariant()
|
|
directlyProvides(has_invariant, IInvariant)
|
|
|
|
# the tests
|
|
self.assertEqual(IInvariant.getTaggedValue('invariants'),
|
|
[_ifFooThenBar])
|
|
self.assertEqual(IInvariant.validateInvariants(has_invariant), None)
|
|
has_invariant.bar = 27
|
|
self.assertEqual(IInvariant.validateInvariants(has_invariant), None)
|
|
has_invariant.foo = 42
|
|
self.assertEqual(IInvariant.validateInvariants(has_invariant), None)
|
|
del has_invariant.bar
|
|
self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'],
|
|
IInvariant)
|
|
|
|
def test_invariant_nested(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface import directlyProvides
|
|
from zope.interface import invariant
|
|
|
|
class IInvariant(Interface):
|
|
foo = Attribute('foo')
|
|
bar = Attribute('bar; must eval to Boolean True if foo does')
|
|
invariant(_ifFooThenBar)
|
|
|
|
class ISubInvariant(IInvariant):
|
|
invariant(_barGreaterThanFoo)
|
|
|
|
class HasInvariant:
|
|
pass
|
|
|
|
# nested interfaces with invariants:
|
|
self.assertEqual(ISubInvariant.getTaggedValue('invariants'),
|
|
[_barGreaterThanFoo])
|
|
has_invariant = HasInvariant()
|
|
directlyProvides(has_invariant, ISubInvariant)
|
|
has_invariant.foo = 42
|
|
# even though the interface has changed, we should still only have one
|
|
# error.
|
|
self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'],
|
|
ISubInvariant)
|
|
# however, if we set foo to 0 (Boolean False) and bar to a negative
|
|
# number then we'll get the new error
|
|
has_invariant.foo = 2
|
|
has_invariant.bar = 1
|
|
self._errorsEqual(has_invariant, 1,
|
|
['Please, Boo MUST be greater than Foo!'],
|
|
ISubInvariant)
|
|
# and if we set foo to a positive number and boo to 0, we'll
|
|
# get both errors!
|
|
has_invariant.foo = 1
|
|
has_invariant.bar = 0
|
|
self._errorsEqual(has_invariant, 2,
|
|
['If Foo, then Bar!',
|
|
'Please, Boo MUST be greater than Foo!'],
|
|
ISubInvariant)
|
|
# for a happy ending, we'll make the invariants happy
|
|
has_invariant.foo = 1
|
|
has_invariant.bar = 2
|
|
self.assertEqual(IInvariant.validateInvariants(has_invariant), None)
|
|
|
|
def test_invariant_mutandis(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface import directlyProvides
|
|
from zope.interface import invariant
|
|
|
|
class IInvariant(Interface):
|
|
foo = Attribute('foo')
|
|
bar = Attribute('bar; must eval to Boolean True if foo does')
|
|
invariant(_ifFooThenBar)
|
|
|
|
class HasInvariant:
|
|
pass
|
|
|
|
# now we'll do two invariants on the same interface,
|
|
# just to make sure that a small
|
|
# multi-invariant interface is at least minimally tested.
|
|
has_invariant = HasInvariant()
|
|
directlyProvides(has_invariant, IInvariant)
|
|
has_invariant.foo = 42
|
|
|
|
# if you really need to mutate, then this would be the way to do it.
|
|
# Probably a bad idea, though. :-)
|
|
old_invariants = IInvariant.getTaggedValue('invariants')
|
|
invariants = old_invariants[:]
|
|
invariants.append(_barGreaterThanFoo)
|
|
IInvariant.setTaggedValue('invariants', invariants)
|
|
|
|
# even though the interface has changed, we should still only have one
|
|
# error.
|
|
self._errorsEqual(has_invariant, 1, ['If Foo, then Bar!'],
|
|
IInvariant)
|
|
# however, if we set foo to 0 (Boolean False) and bar to a negative
|
|
# number then we'll get the new error
|
|
has_invariant.foo = 2
|
|
has_invariant.bar = 1
|
|
self._errorsEqual(
|
|
has_invariant,
|
|
1,
|
|
['Please, Boo MUST be greater than Foo!'],
|
|
IInvariant
|
|
)
|
|
# and if we set foo to a positive number and boo to 0, we'll
|
|
# get both errors!
|
|
has_invariant.foo = 1
|
|
has_invariant.bar = 0
|
|
self._errorsEqual(has_invariant, 2,
|
|
['If Foo, then Bar!',
|
|
'Please, Boo MUST be greater than Foo!'],
|
|
IInvariant)
|
|
# for another happy ending, we'll make the invariants happy again
|
|
has_invariant.foo = 1
|
|
has_invariant.bar = 2
|
|
self.assertEqual(IInvariant.validateInvariants(has_invariant), None)
|
|
# clean up
|
|
IInvariant.setTaggedValue('invariants', old_invariants)
|
|
|
|
def test___doc___element(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class IDocstring(Interface):
|
|
"xxx"
|
|
|
|
self.assertEqual(IDocstring.__doc__, "xxx")
|
|
self.assertEqual(list(IDocstring), [])
|
|
|
|
class IDocstringAndAttribute(Interface):
|
|
"xxx"
|
|
|
|
__doc__ = Attribute('the doc')
|
|
|
|
self.assertEqual(IDocstringAndAttribute.__doc__, "")
|
|
self.assertEqual(list(IDocstringAndAttribute), ['__doc__'])
|
|
|
|
def test_invariant_as_decorator(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
from zope.interface import invariant
|
|
from zope.interface.exceptions import Invalid
|
|
|
|
class IRange(Interface):
|
|
min = Attribute("Lower bound")
|
|
max = Attribute("Upper bound")
|
|
|
|
@invariant
|
|
def range_invariant(ob):
|
|
if ob.max < ob.min:
|
|
raise Invalid('max < min')
|
|
|
|
@implementer(IRange)
|
|
class Range:
|
|
|
|
def __init__(self, min, max):
|
|
self.min, self.max = min, max
|
|
|
|
IRange.validateInvariants(Range(1, 2))
|
|
IRange.validateInvariants(Range(1, 1))
|
|
try:
|
|
IRange.validateInvariants(Range(2, 1))
|
|
except Invalid as e:
|
|
self.assertEqual(str(e), 'max < min')
|
|
|
|
def test_taggedValue(self):
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
from zope.interface import taggedValue
|
|
|
|
class ITagged(Interface):
|
|
foo = Attribute('foo')
|
|
bar = Attribute('bar; must eval to Boolean True if foo does')
|
|
taggedValue('qux', 'Spam')
|
|
|
|
class IDerived(ITagged):
|
|
taggedValue('qux', 'Spam Spam')
|
|
taggedValue('foo', 'bar')
|
|
|
|
class IDerived2(IDerived):
|
|
pass
|
|
|
|
self.assertEqual(ITagged.getTaggedValue('qux'), 'Spam')
|
|
self.assertRaises(KeyError, ITagged.getTaggedValue, 'foo')
|
|
self.assertEqual(list(ITagged.getTaggedValueTags()), ['qux'])
|
|
|
|
self.assertEqual(IDerived2.getTaggedValue('qux'), 'Spam Spam')
|
|
self.assertEqual(IDerived2.getTaggedValue('foo'), 'bar')
|
|
self.assertEqual(set(IDerived2.getTaggedValueTags()), {'qux', 'foo'})
|
|
|
|
def _make_taggedValue_tree(self, base):
|
|
from zope.interface import Attribute
|
|
from zope.interface import taggedValue
|
|
|
|
class F(base):
|
|
taggedValue('tag', 'F')
|
|
tag = Attribute('F')
|
|
|
|
class E(base):
|
|
taggedValue('tag', 'E')
|
|
tag = Attribute('E')
|
|
|
|
class D(base):
|
|
taggedValue('tag', 'D')
|
|
tag = Attribute('D')
|
|
|
|
class C(D, F):
|
|
taggedValue('tag', 'C')
|
|
tag = Attribute('C')
|
|
|
|
class B(D, E):
|
|
pass
|
|
|
|
class A(B, C):
|
|
pass
|
|
|
|
return A
|
|
|
|
def test_getTaggedValue_follows__iro__(self):
|
|
# And not just looks at __bases__.
|
|
# https://github.com/zopefoundation/zope.interface/issues/190
|
|
from zope.interface import Interface
|
|
|
|
# First, confirm that looking at a true class
|
|
# hierarchy follows the __mro__.
|
|
class_A = self._make_taggedValue_tree(object)
|
|
self.assertEqual(class_A.tag.__name__, 'C')
|
|
|
|
# Now check that Interface does, both for attributes...
|
|
iface_A = self._make_taggedValue_tree(Interface)
|
|
self.assertEqual(iface_A['tag'].__name__, 'C')
|
|
# ... and for tagged values.
|
|
self.assertEqual(iface_A.getTaggedValue('tag'), 'C')
|
|
self.assertEqual(iface_A.queryTaggedValue('tag'), 'C')
|
|
# Of course setting something lower overrides it.
|
|
assert iface_A.__bases__[0].__name__ == 'B'
|
|
iface_A.__bases__[0].setTaggedValue('tag', 'B')
|
|
self.assertEqual(iface_A.getTaggedValue('tag'), 'B')
|
|
|
|
def test_getDirectTaggedValue_ignores__iro__(self):
|
|
# https://github.com/zopefoundation/zope.interface/issues/190
|
|
from zope.interface import Interface
|
|
|
|
A = self._make_taggedValue_tree(Interface)
|
|
self.assertIsNone(A.queryDirectTaggedValue('tag'))
|
|
self.assertEqual([], list(A.getDirectTaggedValueTags()))
|
|
|
|
with self.assertRaises(KeyError):
|
|
A.getDirectTaggedValue('tag')
|
|
|
|
A.setTaggedValue('tag', 'A')
|
|
self.assertEqual(A.queryDirectTaggedValue('tag'), 'A')
|
|
self.assertEqual(A.getDirectTaggedValue('tag'), 'A')
|
|
self.assertEqual(['tag'], list(A.getDirectTaggedValueTags()))
|
|
|
|
assert A.__bases__[1].__name__ == 'C'
|
|
C = A.__bases__[1]
|
|
self.assertEqual(C.queryDirectTaggedValue('tag'), 'C')
|
|
self.assertEqual(C.getDirectTaggedValue('tag'), 'C')
|
|
self.assertEqual(['tag'], list(C.getDirectTaggedValueTags()))
|
|
|
|
def test_description_cache_management(self):
|
|
# See https://bugs.launchpad.net/zope.interface/+bug/185974
|
|
# There was a bug where the cache used by Specification.get() was not
|
|
# cleared when the bases were changed.
|
|
from zope.interface import Attribute
|
|
from zope.interface import Interface
|
|
|
|
class I1(Interface):
|
|
a = Attribute('a')
|
|
|
|
class I2(I1):
|
|
pass
|
|
|
|
class I3(I2):
|
|
pass
|
|
|
|
self.assertTrue(I3.get('a') is I1.get('a'))
|
|
|
|
I2.__bases__ = (Interface,)
|
|
self.assertTrue(I3.get('a') is None)
|
|
|
|
def test___call___defers_to___conform___(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
@implementer(IFoo)
|
|
class C:
|
|
def __conform__(self, proto):
|
|
return 0
|
|
|
|
self.assertEqual(IFoo(C()), 0)
|
|
|
|
def test___call___object_implements(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
@implementer(IFoo)
|
|
class C:
|
|
pass
|
|
|
|
c = C()
|
|
self.assertTrue(IFoo(c) is c)
|
|
|
|
def test___call___miss_wo_alternate(self):
|
|
from zope.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
class C:
|
|
pass
|
|
|
|
c = C()
|
|
self.assertRaises(TypeError, IFoo, c)
|
|
|
|
def test___call___miss_w_alternate(self):
|
|
from zope.interface import Interface
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
class C:
|
|
pass
|
|
|
|
c = C()
|
|
self.assertTrue(IFoo(c, self) is self)
|
|
|
|
def test___call___w_adapter_hook(self):
|
|
from zope.interface import Interface
|
|
from zope.interface.interface import adapter_hooks
|
|
|
|
def _miss(iface, obj):
|
|
pass
|
|
|
|
def _hit(iface, obj):
|
|
return self
|
|
|
|
class IFoo(Interface):
|
|
pass
|
|
|
|
class C:
|
|
pass
|
|
|
|
c = C()
|
|
|
|
old_adapter_hooks = adapter_hooks[:]
|
|
adapter_hooks[:] = [_miss, _hit]
|
|
try:
|
|
self.assertTrue(IFoo(c) is self)
|
|
finally:
|
|
adapter_hooks[:] = old_adapter_hooks
|
|
|
|
def test___call___w_overridden_adapt(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
from zope.interface import interfacemethod
|
|
|
|
class IFoo(Interface):
|
|
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
return 42
|
|
|
|
@implementer(IFoo)
|
|
class Obj:
|
|
pass
|
|
|
|
self.assertEqual(42, IFoo(object()))
|
|
# __adapt__ can ignore the fact that the object provides
|
|
# the interface if it chooses.
|
|
self.assertEqual(42, IFoo(Obj()))
|
|
|
|
def test___call___w_overridden_adapt_and_conform(self):
|
|
# Conform is first, taking precedence over __adapt__,
|
|
# *if* it returns non-None
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
from zope.interface import interfacemethod
|
|
|
|
class IAdapt(Interface):
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
return 42
|
|
|
|
class ISimple(Interface):
|
|
"""Nothing special."""
|
|
|
|
@implementer(IAdapt)
|
|
class Conform24:
|
|
def __conform__(self, iface):
|
|
return 24
|
|
|
|
@implementer(IAdapt)
|
|
class ConformNone:
|
|
def __conform__(self, iface):
|
|
return None
|
|
|
|
self.assertEqual(42, IAdapt(object()))
|
|
|
|
self.assertEqual(24, ISimple(Conform24()))
|
|
self.assertEqual(24, IAdapt(Conform24()))
|
|
|
|
with self.assertRaises(TypeError):
|
|
ISimple(ConformNone())
|
|
|
|
self.assertEqual(42, IAdapt(ConformNone()))
|
|
|
|
def test___call___w_overridden_adapt_call_super(self):
|
|
import sys
|
|
|
|
from zope.interface import Interface
|
|
from zope.interface import implementer
|
|
from zope.interface import interfacemethod
|
|
|
|
class IFoo(Interface):
|
|
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
if not self.providedBy(obj):
|
|
return 42
|
|
return super().__adapt__(obj)
|
|
|
|
@implementer(IFoo)
|
|
class Obj:
|
|
pass
|
|
|
|
self.assertEqual(42, IFoo(object()))
|
|
obj = Obj()
|
|
self.assertIs(obj, IFoo(obj))
|
|
|
|
def test___adapt___as_method_and_implementation(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import interfacemethod
|
|
|
|
class IFoo(Interface):
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
return 42
|
|
|
|
def __adapt__(to_adapt): # noqa F811
|
|
"This is a protocol"
|
|
|
|
self.assertEqual(42, IFoo(object()))
|
|
self.assertEqual(IFoo['__adapt__'].getSignatureString(), '(to_adapt)')
|
|
|
|
def test___adapt__inheritance_and_type(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import interfacemethod
|
|
|
|
class IRoot(Interface):
|
|
"""Root"""
|
|
|
|
class IWithAdapt(IRoot):
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
return 42
|
|
|
|
class IOther(IRoot):
|
|
"""Second branch"""
|
|
|
|
class IUnrelated(Interface):
|
|
"""Unrelated"""
|
|
|
|
class IDerivedAdapt(IUnrelated, IWithAdapt, IOther):
|
|
"""Inherits an adapt"""
|
|
# Order of "inheritance" matters here.
|
|
|
|
class IDerived2Adapt(IDerivedAdapt):
|
|
"""Overrides an inherited custom adapt."""
|
|
@interfacemethod
|
|
def __adapt__(self, obj):
|
|
return 24
|
|
|
|
self.assertEqual(42, IDerivedAdapt(object()))
|
|
for iface in IRoot, IWithAdapt, IOther, IUnrelated, IDerivedAdapt:
|
|
self.assertEqual(__name__, iface.__module__)
|
|
|
|
for iface in IRoot, IOther, IUnrelated:
|
|
self.assertEqual(type(IRoot), type(Interface))
|
|
|
|
# But things that implemented __adapt__ got a new type
|
|
self.assertNotEqual(type(Interface), type(IWithAdapt))
|
|
self.assertEqual(type(IWithAdapt), type(IDerivedAdapt))
|
|
self.assertIsInstance(IWithAdapt, type(Interface))
|
|
|
|
self.assertEqual(24, IDerived2Adapt(object()))
|
|
self.assertNotEqual(type(IDerived2Adapt), type(IDerivedAdapt))
|
|
self.assertIsInstance(IDerived2Adapt, type(IDerivedAdapt))
|
|
|
|
def test_interfacemethod_is_general(self):
|
|
from zope.interface import Interface
|
|
from zope.interface import interfacemethod
|
|
|
|
class IFoo(Interface):
|
|
|
|
@interfacemethod
|
|
def __call__(self, obj):
|
|
"""Replace an existing method"""
|
|
return 42
|
|
|
|
@interfacemethod
|
|
def this_is_new(self):
|
|
return 42
|
|
|
|
self.assertEqual(IFoo(self), 42)
|
|
self.assertEqual(IFoo.this_is_new(), 42)
|
|
|
|
|
|
class AttributeTests(ElementTests):
|
|
|
|
DEFAULT_NAME = 'TestAttribute'
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import Attribute
|
|
return Attribute
|
|
|
|
def test__repr__w_interface(self):
|
|
method = self._makeOne()
|
|
method.interface = type(self)
|
|
r = repr(method)
|
|
self.assertTrue(
|
|
r.startswith('<zope.interface.interface.Attribute object at'), r
|
|
)
|
|
self.assertTrue(
|
|
r.endswith(' ' + __name__ + '.AttributeTests.TestAttribute>'), r
|
|
)
|
|
|
|
def test__repr__wo_interface(self):
|
|
method = self._makeOne()
|
|
r = repr(method)
|
|
self.assertTrue(
|
|
r.startswith('<zope.interface.interface.Attribute object at'), r
|
|
)
|
|
self.assertTrue(r.endswith(' TestAttribute>'), r)
|
|
|
|
def test__str__w_interface(self):
|
|
method = self._makeOne()
|
|
method.interface = type(self)
|
|
r = str(method)
|
|
self.assertEqual(r, __name__ + '.AttributeTests.TestAttribute')
|
|
|
|
def test__str__wo_interface(self):
|
|
method = self._makeOne()
|
|
r = str(method)
|
|
self.assertEqual(r, 'TestAttribute')
|
|
|
|
|
|
class MethodTests(AttributeTests):
|
|
|
|
DEFAULT_NAME = 'TestMethod'
|
|
|
|
def _getTargetClass(self):
|
|
from zope.interface.interface import Method
|
|
return Method
|
|
|
|
def test_optional_as_property(self):
|
|
method = self._makeOne()
|
|
self.assertEqual(method.optional, {})
|
|
method.optional = {'foo': 'bar'}
|
|
self.assertEqual(method.optional, {'foo': 'bar'})
|
|
del method.optional
|
|
self.assertEqual(method.optional, {})
|
|
|
|
def test___call___raises_BrokenImplementation(self):
|
|
from zope.interface.exceptions import BrokenImplementation
|
|
method = self._makeOne()
|
|
try:
|
|
method()
|
|
except BrokenImplementation as e:
|
|
self.assertEqual(e.interface, None)
|
|
self.assertEqual(e.name, self.DEFAULT_NAME)
|
|
else:
|
|
self.fail('__call__ should raise BrokenImplementation')
|
|
|
|
def test_getSignatureInfo_bare(self):
|
|
method = self._makeOne()
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_getSignatureString_bare(self):
|
|
method = self._makeOne()
|
|
self.assertEqual(method.getSignatureString(), '()')
|
|
|
|
def test_getSignatureString_w_only_required(self):
|
|
method = self._makeOne()
|
|
method.positional = method.required = ['foo']
|
|
self.assertEqual(method.getSignatureString(), '(foo)')
|
|
|
|
def test_getSignatureString_w_optional(self):
|
|
method = self._makeOne()
|
|
method.positional = method.required = ['foo']
|
|
method.optional = {'foo': 'bar'}
|
|
self.assertEqual(method.getSignatureString(), "(foo='bar')")
|
|
|
|
def test_getSignatureString_w_varargs(self):
|
|
method = self._makeOne()
|
|
method.varargs = 'args'
|
|
self.assertEqual(method.getSignatureString(), "(*args)")
|
|
|
|
def test_getSignatureString_w_kwargs(self):
|
|
method = self._makeOne()
|
|
method.kwargs = 'kw'
|
|
self.assertEqual(method.getSignatureString(), "(**kw)")
|
|
|
|
def test__repr__w_interface(self):
|
|
method = self._makeOne()
|
|
method.kwargs = 'kw'
|
|
method.interface = type(self)
|
|
r = repr(method)
|
|
self.assertTrue(
|
|
r.startswith('<zope.interface.interface.Method object at'), r
|
|
)
|
|
self.assertTrue(
|
|
r.endswith(' ' + __name__ + '.MethodTests.TestMethod(**kw)>'), r
|
|
)
|
|
|
|
def test__repr__wo_interface(self):
|
|
method = self._makeOne()
|
|
method.kwargs = 'kw'
|
|
r = repr(method)
|
|
self.assertTrue(
|
|
r.startswith('<zope.interface.interface.Method object at'), r
|
|
)
|
|
self.assertTrue(r.endswith(' TestMethod(**kw)>'), r)
|
|
|
|
def test__str__w_interface(self):
|
|
method = self._makeOne()
|
|
method.kwargs = 'kw'
|
|
method.interface = type(self)
|
|
r = str(method)
|
|
self.assertEqual(r, __name__ + '.MethodTests.TestMethod(**kw)')
|
|
|
|
def test__str__wo_interface(self):
|
|
method = self._makeOne()
|
|
method.kwargs = 'kw'
|
|
r = str(method)
|
|
self.assertEqual(r, 'TestMethod(**kw)')
|
|
|
|
|
|
class Test_fromFunction(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.interface import fromFunction
|
|
return fromFunction(*args, **kw)
|
|
|
|
def test_bare(self):
|
|
|
|
def _func():
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
self.assertEqual(method.getName(), '_func')
|
|
self.assertEqual(method.getDoc(), 'DOCSTRING')
|
|
self.assertEqual(method.interface, None)
|
|
self.assertEqual(list(method.getTaggedValueTags()), [])
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_w_interface(self):
|
|
from zope.interface.interface import InterfaceClass
|
|
|
|
class IFoo(InterfaceClass):
|
|
pass
|
|
|
|
def _func():
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func, interface=IFoo)
|
|
self.assertEqual(method.interface, IFoo)
|
|
|
|
def test_w_name(self):
|
|
|
|
def _func():
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func, name='anotherName')
|
|
self.assertEqual(method.getName(), 'anotherName')
|
|
|
|
def test_w_only_required(self):
|
|
|
|
def _func(foo):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), ['foo'])
|
|
self.assertEqual(list(info['required']), ['foo'])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_w_optional(self):
|
|
|
|
def _func(foo='bar'):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), ['foo'])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {'foo': 'bar'})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_w_optional_self(self):
|
|
# This is a weird case, trying to cover the following code in
|
|
# FUT::
|
|
#
|
|
# nr = na-len(defaults)
|
|
# if nr < 0:
|
|
# defaults=defaults[-nr:]
|
|
# nr = 0
|
|
|
|
def _func(self='bar'):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func, imlevel=1)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_w_varargs(self):
|
|
|
|
def _func(*args):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], 'args')
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_w_kwargs(self):
|
|
|
|
def _func(**kw):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], 'kw')
|
|
|
|
def test_full_spectrum(self):
|
|
|
|
def _func(
|
|
foo, bar='baz', *args, **kw
|
|
): # pylint:disable=keyword-arg-before-vararg
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(_func)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), ['foo', 'bar'])
|
|
self.assertEqual(list(info['required']), ['foo'])
|
|
self.assertEqual(info['optional'], {'bar': 'baz'})
|
|
self.assertEqual(info['varargs'], 'args')
|
|
self.assertEqual(info['kwargs'], 'kw')
|
|
|
|
|
|
class Test_fromMethod(unittest.TestCase):
|
|
|
|
def _callFUT(self, *args, **kw):
|
|
from zope.interface.interface import fromMethod
|
|
return fromMethod(*args, **kw)
|
|
|
|
def test_no_args(self):
|
|
|
|
class Foo:
|
|
def bar(self):
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(Foo.bar)
|
|
self.assertEqual(method.getName(), 'bar')
|
|
self.assertEqual(method.getDoc(), 'DOCSTRING')
|
|
self.assertEqual(method.interface, None)
|
|
self.assertEqual(list(method.getTaggedValueTags()), [])
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
def test_full_spectrum(self):
|
|
|
|
class Foo:
|
|
def bar(
|
|
self, foo, bar='baz', *args, **kw
|
|
): # pylint:disable=keyword-arg-before-vararg
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(Foo.bar)
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), ['foo', 'bar'])
|
|
self.assertEqual(list(info['required']), ['foo'])
|
|
self.assertEqual(info['optional'], {'bar': 'baz'})
|
|
self.assertEqual(info['varargs'], 'args')
|
|
self.assertEqual(info['kwargs'], 'kw')
|
|
|
|
def test_w_non_method(self):
|
|
|
|
def foo():
|
|
"DOCSTRING"
|
|
|
|
method = self._callFUT(foo)
|
|
self.assertEqual(method.getName(), 'foo')
|
|
self.assertEqual(method.getDoc(), 'DOCSTRING')
|
|
self.assertEqual(method.interface, None)
|
|
self.assertEqual(list(method.getTaggedValueTags()), [])
|
|
info = method.getSignatureInfo()
|
|
self.assertEqual(list(info['positional']), [])
|
|
self.assertEqual(list(info['required']), [])
|
|
self.assertEqual(info['optional'], {})
|
|
self.assertEqual(info['varargs'], None)
|
|
self.assertEqual(info['kwargs'], None)
|
|
|
|
|
|
class DummyDependent:
|
|
|
|
def __init__(self):
|
|
self._changed = []
|
|
|
|
def changed(self, originally_changed):
|
|
self._changed.append(originally_changed)
|
|
|
|
|
|
def _barGreaterThanFoo(obj):
|
|
from zope.interface.exceptions import Invalid
|
|
foo = getattr(obj, 'foo', None)
|
|
bar = getattr(obj, 'bar', None)
|
|
if foo is not None and isinstance(foo, type(bar)):
|
|
# type checking should be handled elsewhere (like, say,
|
|
# schema); these invariants should be intra-interface
|
|
# constraints. This is a hacky way to do it, maybe, but you
|
|
# get the idea
|
|
if not bar > foo:
|
|
raise Invalid('Please, Boo MUST be greater than Foo!')
|
|
|
|
|
|
def _ifFooThenBar(obj):
|
|
from zope.interface.exceptions import Invalid
|
|
if getattr(obj, 'foo', None) and not getattr(obj, 'bar', None):
|
|
raise Invalid('If Foo, then Bar!')
|
|
|
|
|
|
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 TestTypeAnnotations(unittest.TestCase):
|
|
"""Test using Interfaces in type annotations."""
|
|
|
|
def test___or__(self):
|
|
from typing import Optional
|
|
from typing import Union
|
|
|
|
from zope.interface import Interface
|
|
|
|
class I1(Interface):
|
|
pass
|
|
|
|
class I2(Interface):
|
|
pass
|
|
|
|
class B:
|
|
a: I1 | None
|
|
b: I1 | I2
|
|
|
|
self.assertEqual(
|
|
B.__annotations__, {'a': Optional[I1], 'b': Union[I1, I2]})
|
|
|
|
def test___ror__(self):
|
|
from typing import Optional
|
|
from typing import Union
|
|
|
|
from zope.interface import Interface
|
|
|
|
class I1(Interface):
|
|
pass
|
|
|
|
class A:
|
|
pass
|
|
|
|
class B:
|
|
a: None | I1
|
|
b: A | I1
|
|
|
|
self.assertEqual(
|
|
B.__annotations__, {'a': Optional[I1], 'b': Union[A, I1]})
|