Feedback from review: whitespace, doc clarification, and a unit test showing the precedence of __conform__ vs __adapt__.
This commit is contained in:
parent
10eadd6305
commit
b1807049d4
|
@ -904,7 +904,8 @@ If an object already implements the interface, then it will be returned:
|
|||
itself compliant, or knows how to wrap itself suitably.
|
||||
|
||||
This is handled with ``__conform__``. If an object implements
|
||||
``__conform__``, then it will be used:
|
||||
``__conform__``, then it will be used to give the object the chance to
|
||||
decide if it knows about the interface.
|
||||
|
||||
.. doctest::
|
||||
|
||||
|
@ -916,7 +917,25 @@ This is handled with ``__conform__``. If an object implements
|
|||
>>> I(C())
|
||||
0
|
||||
|
||||
Adapter hooks (see ``__adapt__``) will also be used, if present:
|
||||
If ``__conform__`` returns ``None`` (because the object is unaware of
|
||||
the interface), then the rest of the adaptation process will continue.
|
||||
Here, we demonstrate that if the object already provides the
|
||||
interface, it is returned.
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> @zope.interface.implementer(I)
|
||||
... class C(object):
|
||||
... def __conform__(self, proto):
|
||||
... return None
|
||||
|
||||
>>> c = C()
|
||||
>>> I(c) is c
|
||||
True
|
||||
|
||||
|
||||
Adapter hooks (see ``__adapt__``) will also be used, if present (after
|
||||
a ``__conform__`` method, if any, has been tried):
|
||||
|
||||
.. doctest::
|
||||
|
||||
|
@ -951,10 +970,11 @@ the requirement:
|
|||
object.
|
||||
|
||||
This method is normally not called directly. It is called by the
|
||||
:pep:`246` adapt framework and by the interface ``__call__`` operator.
|
||||
:pep:`246` adapt framework and by the interface ``__call__`` operator
|
||||
once ``__conform__`` (if any) has failed.
|
||||
|
||||
The ``adapt`` method is responsible for adapting an object to the
|
||||
reciever.
|
||||
receiver.
|
||||
|
||||
The default version returns ``None`` (because by default no interface
|
||||
"knows how to suitably wrap the object"):
|
||||
|
@ -1016,13 +1036,15 @@ functionality for particular interfaces.
|
|||
|
||||
>>> @zope.interface.implementer(ICustomAdapt)
|
||||
... class CustomAdapt(object):
|
||||
... pass
|
||||
... pass
|
||||
>>> ICustomAdapt('a string')
|
||||
'a string'
|
||||
>>> ICustomAdapt(CustomAdapt())
|
||||
<CustomAdapt object at ...>
|
||||
|
||||
.. seealso:: :func:`zope.interface.interfacemethod`
|
||||
.. seealso:: :func:`zope.interface.interfacemethod`, which explains
|
||||
how to override functions in interface definitions and why, prior
|
||||
to Python 3.6, the zero-argument version of `super` cannot be used.
|
||||
|
||||
.. [#create] The main reason we subclass ``Interface`` is to cause the
|
||||
Python class statement to create an interface, rather
|
||||
|
|
|
@ -259,5 +259,5 @@ class ABCInterfaceClass(InterfaceClass):
|
|||
return set(itertools.chain(registered, self.__extra_classes))
|
||||
|
||||
|
||||
ABCInterface = ABCInterfaceClass.__new__(ABCInterfaceClass, 'ABCInterfaceClass', (), {})
|
||||
ABCInterface = ABCInterfaceClass.__new__(ABCInterfaceClass, 'ABCInterface', (), {})
|
||||
InterfaceClass.__init__(ABCInterface, 'ABCInterface', (Interface,), {})
|
||||
|
|
|
@ -662,7 +662,10 @@ def interfacemethod(func):
|
|||
This is a decorator that functions like `staticmethod` et al.
|
||||
|
||||
The primary use of this decorator is to allow interface definitions to
|
||||
define the ``__adapt__`` method.
|
||||
define the ``__adapt__`` method, but other interface methods can be
|
||||
overridden this way too.
|
||||
|
||||
.. seealso:: `zope.interface.interfaces.IInterfaceDeclaration.interfacemethod`
|
||||
"""
|
||||
f_locals = sys._getframe(1).f_locals
|
||||
methods = f_locals.setdefault(INTERFACE_METHODS, {})
|
||||
|
|
|
@ -490,7 +490,7 @@ class IInterfaceDeclaration(Interface):
|
|||
This is a way of executing :meth:`IElement.setTaggedValue` from
|
||||
the definition of the interface. For example::
|
||||
|
||||
class IFoo(Interface):
|
||||
class IFoo(Interface):
|
||||
taggedValue('key', 'value')
|
||||
|
||||
.. seealso:: `zope.interface.taggedValue`
|
||||
|
@ -505,15 +505,15 @@ class IInterfaceDeclaration(Interface):
|
|||
|
||||
For example::
|
||||
|
||||
def check_range(ob):
|
||||
if ob.max < ob.min:
|
||||
range ValueError
|
||||
def check_range(ob):
|
||||
if ob.max < ob.min:
|
||||
raise ValueError("max value is less than min value")
|
||||
|
||||
class IRange(Interface):
|
||||
min = Attribute("The min value")
|
||||
max = Attribute("The max value")
|
||||
class IRange(Interface):
|
||||
min = Attribute("The min value")
|
||||
max = Attribute("The max value")
|
||||
|
||||
invariant(check_range)
|
||||
invariant(check_range)
|
||||
|
||||
.. seealso:: `zope.interface.invariant`
|
||||
"""
|
||||
|
@ -530,13 +530,13 @@ class IInterfaceDeclaration(Interface):
|
|||
|
||||
For example::
|
||||
|
||||
class IRange(Interface):
|
||||
@interfacemethod
|
||||
def __adapt__(self, obj):
|
||||
if isinstance(obj, range):
|
||||
# Return the builtin ``range`` as-is
|
||||
return obj
|
||||
return super(type(IRange), self).__adapt__(obj)
|
||||
class IRange(Interface):
|
||||
@interfacemethod
|
||||
def __adapt__(self, obj):
|
||||
if isinstance(obj, range):
|
||||
# Return the builtin ``range`` as-is
|
||||
return obj
|
||||
return super(type(IRange), self).__adapt__(obj)
|
||||
|
||||
You can use ``super`` to call the parent class functionality. Note that
|
||||
the zero-argument version (``super().__adapt__``) works on Python 3.6 and above, but
|
||||
|
|
|
@ -2177,9 +2177,46 @@ class InterfaceTests(unittest.TestCase):
|
|||
pass
|
||||
|
||||
self.assertEqual(42, I(object()))
|
||||
# __adapt__ supercedes providedBy() if defined.
|
||||
# __adapt__ can ignore the fact that the object provides
|
||||
# the interface if it chooses.
|
||||
self.assertEqual(42, I(O()))
|
||||
|
||||
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 interfacemethod
|
||||
from zope.interface import implementer
|
||||
|
||||
class IAdapt(Interface):
|
||||
@interfacemethod
|
||||
def __adapt__(self, obj):
|
||||
return 42
|
||||
|
||||
class ISimple(Interface):
|
||||
"""Nothing special."""
|
||||
|
||||
@implementer(IAdapt)
|
||||
class Conform24(object):
|
||||
def __conform__(self, iface):
|
||||
return 24
|
||||
|
||||
@implementer(IAdapt)
|
||||
class ConformNone(object):
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue