summaryrefslogtreecommitdiff
path: root/src/zope/interface/tests/test_declarations.py
diff options
context:
space:
mode:
authorJason Madden <jamadden@gmail.com>2021-03-25 10:30:47 -0500
committerJason Madden <jamadden@gmail.com>2021-03-25 10:30:47 -0500
commitce8f66f8bf4ebffca7cdf95dbb8c5add02251e91 (patch)
tree005840e6e690f96d690d189ea3c196317818fae1 /src/zope/interface/tests/test_declarations.py
parente6d3805c6e155a89a34d89601477881aec9b7df1 (diff)
downloadzope-interface-issue236.tar.gz
Update repr() and str() of some common objects.issue236
Only InterfaceClass got a str, so it now has a distinction. Other objects only got updated reprs. Note: This may potentially break some doctests. In many cases, the ``repr()`` is now something that can be evaluated to produce an equal object. For example, what was previously printed as ``<implementedBy builtins.list>`` is now shown as ``classImplements(list, IMutableSequence, IIterable)``. Fixes #236 Here's a before with ZOPE_INTERFACE_LOG_CHANGED_IRO=1 in BTrees: ``` Object <implementedBy builtins.list> has different legacy and C3 MROs: Legacy RO (len=11) C3 RO (len=11; inconsistent=no) ================================================================================================================================================== <implementedBy builtins.list> <implementedBy builtins.list> <ABCInterfaceClass zope.interface.common.collections.IMutableSequence> <ABCInterfaceClass zope.interface.common.collections.IMutableSequence> <ABCInterfaceClass zope.interface.common.collections.ISequence> <ABCInterfaceClass zope.interface.common.collections.ISequence> <ABCInterfaceClass zope.interface.common.collections.IReversible> <ABCInterfaceClass zope.interface.common.collections.IReversible> <ABCInterfaceClass zope.interface.common.collections.ICollection> <ABCInterfaceClass zope.interface.common.collections.ICollection> <ABCInterfaceClass zope.interface.common.collections.ISized> <ABCInterfaceClass zope.interface.common.collections.ISized> + <ABCInterfaceClass zope.interface.common.collections.IIterable> <ABCInterfaceClass zope.interface.common.collections.IContainer> <ABCInterfaceClass zope.interface.common.collections.IContainer> - <ABCInterfaceClass zope.interface.common.collections.IIterable> <ABCInterfaceClass zope.interface.common.ABCInterface> <ABCInterfaceClass zope.interface.common.ABCInterface> + <implementedBy builtins.object> <InterfaceClass zope.interface.Interface> <InterfaceClass zope.interface.Interface> - <implementedBy builtins.object> Object <ABCInterfaceClass zope.interface.common.mapping.IFullMapping> has different legacy and C3 MROs: Legacy RO (len=18) C3 RO (len=18; inconsistent=no) ================================================================================================================================================ <ABCInterfaceClass zope.interface.common.mapping.IFullMapping> <ABCInterfaceClass zope.interface.common.mapping.IFullMapping> <ABCInterfaceClass zope.interface.common.collections.IMutableMapping> <ABCInterfaceClass zope.interface.common.collections.IMutableMapping> <ABCInterfaceClass zope.interface.common.collections.IMapping> <ABCInterfaceClass zope.interface.common.collections.IMapping> <ABCInterfaceClass zope.interface.common.collections.ICollection> <ABCInterfaceClass zope.interface.common.collections.ICollection> - <ABCInterfaceClass zope.interface.common.collections.IIterable> <InterfaceClass zope.interface.common.mapping.IExtendedReadMapping> <InterfaceClass zope.interface.common.mapping.IExtendedReadMapping> <InterfaceClass zope.interface.common.mapping.IIterableMapping> <InterfaceClass zope.interface.common.mapping.IIterableMapping> <InterfaceClass zope.interface.common.mapping.IExtendedWriteMapping> <InterfaceClass zope.interface.common.mapping.IExtendedWriteMapping> <InterfaceClass zope.interface.common.mapping.IClonableMapping> <InterfaceClass zope.interface.common.mapping.IClonableMapping> <InterfaceClass zope.interface.common.mapping.IMapping> <InterfaceClass zope.interface.common.mapping.IMapping> <InterfaceClass zope.interface.common.mapping.IWriteMapping> <InterfaceClass zope.interface.common.mapping.IWriteMapping> <InterfaceClass zope.interface.common.mapping.IEnumerableMapping> <InterfaceClass zope.interface.common.mapping.IEnumerableMapping> <ABCInterfaceClass zope.interface.common.collections.ISized> <ABCInterfaceClass zope.interface.common.collections.ISized> + <ABCInterfaceClass zope.interface.common.collections.IIterable> <InterfaceClass zope.interface.common.mapping.IReadMapping> <InterfaceClass zope.interface.common.mapping.IReadMapping> <ABCInterfaceClass zope.interface.common.collections.IContainer> <ABCInterfaceClass zope.interface.common.collections.IContainer> <ABCInterfaceClass zope.interface.common.ABCInterface> <ABCInterfaceClass zope.interface.common.ABCInterface> <InterfaceClass zope.interface.common.mapping.IItemMapping> <InterfaceClass zope.interface.common.mapping.IItemMapping> <InterfaceClass zope.interface.Interface> <InterfaceClass zope.interface.Interface> Object <InterfaceClass BTrees.Interfaces.ISet> has different legacy and C3 MROs: Legacy RO (len=7) C3 RO (len=7; inconsistent=no) ==================================================================================================== <InterfaceClass BTrees.Interfaces.ISet> <InterfaceClass BTrees.Interfaces.ISet> <InterfaceClass BTrees.Interfaces.IKeySequence> <InterfaceClass BTrees.Interfaces.IKeySequence> - <InterfaceClass BTrees.Interfaces.ISized> <InterfaceClass BTrees.Interfaces.ISetMutable> <InterfaceClass BTrees.Interfaces.ISetMutable> <InterfaceClass BTrees.Interfaces.IKeyed> <InterfaceClass BTrees.Interfaces.IKeyed> <InterfaceClass BTrees.Interfaces.ICollection> <InterfaceClass BTrees.Interfaces.ICollection> + <InterfaceClass BTrees.Interfaces.ISized> <InterfaceClass zope.interface.Interface> <InterfaceClass zope.interface.Interface> ``` And here's after: ``` Object classImplements(list, IMutableSequence, IIterable) has different legacy and C3 MROs: Legacy RO (len=11) C3 RO (len=11; inconsistent=no) ========================================================================================================== classImplements(list, IMutableSequence, IIterable) classImplements(list, IMutableSequence, IIterable) zope.interface.common.collections.IMutableSequence zope.interface.common.collections.IMutableSequence zope.interface.common.collections.ISequence zope.interface.common.collections.ISequence zope.interface.common.collections.IReversible zope.interface.common.collections.IReversible zope.interface.common.collections.ICollection zope.interface.common.collections.ICollection zope.interface.common.collections.ISized zope.interface.common.collections.ISized + zope.interface.common.collections.IIterable zope.interface.common.collections.IContainer zope.interface.common.collections.IContainer - zope.interface.common.collections.IIterable zope.interface.common.ABCInterface zope.interface.common.ABCInterface + classImplements(object) zope.interface.Interface zope.interface.Interface - classImplements(object) Object <ABCInterfaceClass zope.interface.common.mapping.IFullMapping> has different legacy and C3 MROs: Legacy RO (len=18) C3 RO (len=18; inconsistent=no) ============================================================================================================ zope.interface.common.mapping.IFullMapping zope.interface.common.mapping.IFullMapping zope.interface.common.collections.IMutableMapping zope.interface.common.collections.IMutableMapping zope.interface.common.collections.IMapping zope.interface.common.collections.IMapping zope.interface.common.collections.ICollection zope.interface.common.collections.ICollection - zope.interface.common.collections.IIterable zope.interface.common.mapping.IExtendedReadMapping zope.interface.common.mapping.IExtendedReadMapping zope.interface.common.mapping.IIterableMapping zope.interface.common.mapping.IIterableMapping zope.interface.common.mapping.IExtendedWriteMapping zope.interface.common.mapping.IExtendedWriteMapping zope.interface.common.mapping.IClonableMapping zope.interface.common.mapping.IClonableMapping zope.interface.common.mapping.IMapping zope.interface.common.mapping.IMapping zope.interface.common.mapping.IWriteMapping zope.interface.common.mapping.IWriteMapping zope.interface.common.mapping.IEnumerableMapping zope.interface.common.mapping.IEnumerableMapping zope.interface.common.collections.ISized zope.interface.common.collections.ISized + zope.interface.common.collections.IIterable zope.interface.common.mapping.IReadMapping zope.interface.common.mapping.IReadMapping zope.interface.common.collections.IContainer zope.interface.common.collections.IContainer zope.interface.common.ABCInterface zope.interface.common.ABCInterface zope.interface.common.mapping.IItemMapping zope.interface.common.mapping.IItemMapping zope.interface.Interface zope.interface.Interface Object <InterfaceClass BTrees.Interfaces.ISet> has different legacy and C3 MROs: Legacy RO (len=7) C3 RO (len=7; inconsistent=no) ================================================================== BTrees.Interfaces.ISet BTrees.Interfaces.ISet BTrees.Interfaces.IKeySequence BTrees.Interfaces.IKeySequence - BTrees.Interfaces.ISized BTrees.Interfaces.ISetMutable BTrees.Interfaces.ISetMutable BTrees.Interfaces.IKeyed BTrees.Interfaces.IKeyed BTrees.Interfaces.ICollection BTrees.Interfaces.ICollection + BTrees.Interfaces.ISized zope.interface.Interface zope.interface.Interface ```
Diffstat (limited to 'src/zope/interface/tests/test_declarations.py')
-rw-r--r--src/zope/interface/tests/test_declarations.py307
1 files changed, 271 insertions, 36 deletions
diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py
index 0c21b8c..8efe2d8 100644
--- a/src/zope/interface/tests/test_declarations.py
+++ b/src/zope/interface/tests/test_declarations.py
@@ -384,7 +384,7 @@ class TestImplements(NameAndModuleComparisonTestsMixin,
def test___repr__(self):
impl = self._makeOne()
impl.__name__ = 'Testing'
- self.assertEqual(repr(impl), '<implementedBy Testing>')
+ self.assertEqual(repr(impl), 'classImplements(Testing)')
def test___reduce__(self):
from zope.interface.declarations import implementedBy
@@ -544,7 +544,6 @@ class Test_implementedByFallback(unittest.TestCase):
def test_builtins_added_to_cache(self):
from zope.interface import declarations
from zope.interface.declarations import Implements
- from zope.interface._compat import _BUILTINS
with _MonkeyDict(declarations,
'BuiltinImplementationSpecifications') as specs:
self.assertEqual(list(self._callFUT(tuple)), [])
@@ -554,8 +553,8 @@ class Test_implementedByFallback(unittest.TestCase):
spec = specs[typ]
self.assertIsInstance(spec, Implements)
self.assertEqual(repr(spec),
- '<implementedBy %s.%s>'
- % (_BUILTINS, typ.__name__))
+ 'classImplements(%s)'
+ % (typ.__name__,))
def test_builtins_w_existing_cache(self):
from zope.interface import declarations
@@ -1304,25 +1303,6 @@ class ProvidesClassTests(unittest.TestCase):
return foo.__provides__
self.assertRaises(AttributeError, _test)
- def test__repr__(self):
- from zope.interface.interface import InterfaceClass
- IFoo = InterfaceClass("IFoo")
- assert IFoo.__name__ == 'IFoo'
- assert IFoo.__module__ == __name__
- assert repr(IFoo) == '<InterfaceClass %s.IFoo>' % (__name__,)
-
- IBar = InterfaceClass("IBar")
-
- inst = self._makeOne(type(self), IFoo, IBar)
- self.assertEqual(
- repr(inst),
- "<zope.interface.Provides "
- "for instances of <class '%(mod)s.ProvidesClassTests'> "
- "providing (<InterfaceClass %(mod)s.IFoo>, <InterfaceClass %(mod)s.IBar>)>" % {
- 'mod': __name__,
- }
- )
-
class ProvidesClassStrictTests(ProvidesClassTests):
# Tests that require the strict C3 resolution order.
@@ -1334,9 +1314,6 @@ class ProvidesClassStrictTests(ProvidesClassTests):
return ProvidesClass._do_calculate_ro(self, base_mros=base_mros, strict=True)
return StrictProvides
- def test__repr__(self):
- self.skipTest("Not useful for the subclass.")
-
def test_overlapping_interfaces_corrected(self):
# Giving Provides(cls, IFace), where IFace is already
# provided by cls, doesn't produce invalid resolution orders.
@@ -1361,6 +1338,195 @@ class ProvidesClassStrictTests(ProvidesClassTests):
))
+class TestProvidesClassRepr(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from zope.interface.declarations import ProvidesClass
+ return ProvidesClass
+
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
+
+ def test__repr__(self):
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo")
+ assert IFoo.__name__ == 'IFoo'
+ assert IFoo.__module__ == __name__
+ assert repr(IFoo) == '<InterfaceClass %s.IFoo>' % (__name__,)
+
+ 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.tests import dummy
+ from zope.interface.declarations import directlyProvides
+ from zope.interface.declarations import alsoProvides
+ from zope.interface.interface import InterfaceClass
+
+ IFoo = InterfaceClass('IFoo')
+ IBar = InterfaceClass('IBar')
+
+ orig_provides = dummy.__provides__ # pylint:disable=no-member
+ del dummy.__provides__ # pylint:disable=no-member
+ self.addCleanup(setattr, dummy, '__provides__', orig_provides)
+
+ directlyProvides(dummy, IFoo)
+ provides = dummy.__provides__ # pylint:disable=no-member
+
+ self.assertEqual(
+ repr(provides),
+ "directlyProvides(sys.modules['zope.interface.tests.dummy'], IFoo)"
+ )
+
+ alsoProvides(dummy, IBar)
+ provides = dummy.__provides__ # pylint:disable=no-member
+
+ self.assertEqual(
+ repr(provides),
+ "directlyProvides(sys.modules['zope.interface.tests.dummy'], IFoo, IBar)"
+ )
+
+ # If we make this module also provide IFoo and IBar, then the repr
+ # lists both names.
+ my_module = sys.modules[__name__]
+ assert not hasattr(my_module, '__provides__')
+
+ directlyProvides(my_module, IFoo, IBar)
+ self.addCleanup(delattr, my_module, '__provides__')
+ self.assertIs(my_module.__provides__, provides)
+ self.assertEqual(
+ repr(provides),
+ "directlyProvides(('zope.interface.tests.dummy', "
+ "'zope.interface.tests.test_declarations'), "
+ "IFoo, IBar)"
+ )
+
+ def test__repr__module_provides_cached_shared(self):
+ from zope.interface.interface import InterfaceClass
+ 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):
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo", __module__='mod1')
+ IFoo2 = InterfaceClass("IFoo", __module__='mod2')
+ IBaz = InterfaceClass("IBaz")
+
+ inst = self._makeOne(type(self), IFoo, IBaz, IFoo2)
+ self.assertEqual(
+ repr(inst),
+ "directlyProvides(TestProvidesClassRepr, IFoo, IBaz, mod2.IFoo)"
+ )
+
+ def test__repr__implementedBy_in_interfaces(self):
+ from zope.interface import Interface
+ from zope.interface import implementedBy
+ class IFoo(Interface):
+ "Does nothing"
+
+ class Bar(object):
+ "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):
+ class Object(object):
+ __bases__ = ()
+ __str__ = lambda _: self.fail("Should not call str")
+
+ def __repr__(self):
+ return '<Object>'
+ inst = self._makeOne(Object())
+ self.assertEqual(
+ repr(inst),
+ 'directlyProvides(<Object>)',
+ )
+
+ def test__repr__providedBy_from_class(self):
+ from zope.interface.declarations import implementer
+ from zope.interface.declarations import providedBy
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo")
+
+ @implementer(IFoo)
+ class Foo(object):
+ pass
+
+ inst = providedBy(Foo())
+ self.assertEqual(
+ repr(inst),
+ 'classImplements(Foo, IFoo)'
+ )
+
+ def test__repr__providedBy_alsoProvides(self):
+ from zope.interface.declarations import implementer
+ from zope.interface.declarations import providedBy
+ from zope.interface.declarations import alsoProvides
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo")
+ IBar = InterfaceClass("IBar")
+
+ @implementer(IFoo)
+ class Foo(object):
+ 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):
@@ -1631,13 +1797,6 @@ class ClassProvidesTests(unittest.TestCase):
self.assertEqual(cp.__reduce__(),
(type(cp), (Foo, type(Foo), IBar)))
- def test__repr__(self):
- inst = self._makeOne(type(self), type)
- self.assertEqual(
- repr(inst),
- "<zope.interface.declarations.ClassProvides for %r>" % type(self)
- )
-
class ClassProvidesStrictTests(ClassProvidesTests):
# Tests that require the strict C3 resolution order.
@@ -1649,9 +1808,6 @@ class ClassProvidesStrictTests(ClassProvidesTests):
return ClassProvides._do_calculate_ro(self, base_mros=base_mros, strict=True)
return StrictClassProvides
- def test__repr__(self):
- self.skipTest("Not useful for the subclass.")
-
def test_overlapping_interfaces_corrected(self):
# Giving ClassProvides(cls, metaclass, IFace), where IFace is already
# provided by metacls, doesn't produce invalid resolution orders.
@@ -1682,6 +1838,85 @@ class ClassProvidesStrictTests(ClassProvidesTests):
Interface
))
+
+class TestClassProvidesRepr(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from zope.interface.declarations import ClassProvides
+ return ClassProvides
+
+ def _makeOne(self, *args, **kw):
+ return self._getTargetClass()(*args, **kw)
+
+ def test__repr__empty(self):
+ inst = self._makeOne(type(self), type)
+ self.assertEqual(
+ repr(inst),
+ "directlyProvides(TestClassProvidesRepr)"
+ )
+
+ def test__repr__providing_one(self):
+ from zope.interface import Interface
+ class IFoo(Interface):
+ "Does nothing"
+
+ inst = self._makeOne(type(self), type, IFoo)
+ self.assertEqual(
+ repr(inst),
+ "directlyProvides(TestClassProvidesRepr, IFoo)"
+ )
+
+ def test__repr__duplicate_names(self):
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo", __module__='mod1')
+ IFoo2 = InterfaceClass("IFoo", __module__='mod2')
+ IBaz = InterfaceClass("IBaz")
+
+ inst = self._makeOne(type(self), type, IFoo, IBaz, IFoo2)
+ self.assertEqual(
+ repr(inst),
+ "directlyProvides(TestClassProvidesRepr, IFoo, IBaz, mod2.IFoo)"
+ )
+
+ def test__repr__implementedBy(self):
+ from zope.interface.declarations import implementer
+ from zope.interface.declarations import implementedBy
+ from zope.interface.interface import InterfaceClass
+ IFoo = InterfaceClass("IFoo")
+
+ @implementer(IFoo)
+ class Foo(object):
+ 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(object):
+ def __call__(self):
+ return self
+
+ inst = implementedBy(Callable())
+ self.assertEqual(
+ repr(inst),
+ 'classImplements(%s.?)' % (__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):