Add warning to change note about string changes breaking doctests.

Also tweak documentation to DRY for verifyObject/verifyClass.
This commit is contained in:
Jason Madden 2020-02-08 06:21:17 -06:00
parent e8a4da9d5e
commit 83f4f55699
No known key found for this signature in database
GPG Key ID: 349F84431A08B99E
5 changed files with 69 additions and 27 deletions

View File

@ -100,11 +100,13 @@
and ``Method``. These contain the name of the defining interface
and the attribute. For methods, it also includes the signature.
- Change the error strings returned by ``verifyObject`` and
- Change the error strings raised by ``verifyObject`` and
``verifyClass``. They now include more human-readable information
and exclude extraneous lines and spaces. See `issue 170
<https://github.com/zopefoundation/zope.interface/issues/170>`_.
.. caution:: This will break consumers (such as doctests) that
depended on the exact error messages.
4.7.1 (2019-11-11)
==================

View File

@ -2,6 +2,8 @@
Interfaces
==========
.. currentmodule:: zope.interface
Interfaces are objects that specify (document) the external behavior
of objects that "provide" them. An interface specifies behavior
through:
@ -296,6 +298,7 @@ be used for classes, but in 3.6.0 and higher it can:
Note that class decorators using the ``@implementer(IFoo)`` syntax are only
supported in Python 2.6 and later.
.. autofunction:: implementer
Declaring provided interfaces
-----------------------------
@ -412,6 +415,8 @@ We can find out what interfaces are directly provided by an object:
>>> list(zope.interface.directlyProvidedBy(newfoo))
[]
.. autofunction:: provider
Inherited declarations
----------------------
@ -466,6 +471,8 @@ be used for this purpose:
>>> list(zope.interface.implementedBy(C))
[<InterfaceClass builtins.IFoo>]
.. autofunction:: classImplements
We can use ``classImplementsOnly`` to exclude inherited interfaces:
.. doctest::
@ -477,6 +484,7 @@ We can use ``classImplementsOnly`` to exclude inherited interfaces:
>>> list(zope.interface.implementedBy(C))
[<InterfaceClass builtins.ISpecial>]
.. autofunction:: classImplementsOnly
Declaration Objects
@ -791,7 +799,7 @@ exceptions as its argument:
... except Invalid as e:
... str(e)
'[RangeError(Range(2, 1))]'
And the list will be filled with the individual exceptions:
.. doctest::

View File

@ -3,30 +3,16 @@
=====================================
The ``zope.interface.verify`` module provides functions that test whether a
given interface is implemented by a class or provided by an object, resp.
Verifying classes
=================
This is covered by unit tests defined in ``zope.interface.tests.test_verify``.
given interface is implemented by a class or provided by an object.
.. currentmodule:: zope.interface.verify
Verifying objects
=================
An object provides an interface if
.. autofunction:: verifyObject
- either its class declares that it implements the interfaces, or the object
declares that it directly provides the interface;
- the object defines all the methods required by the interface;
- all the methods have the correct signature;
- the object defines all non-method attributes required by the interface.
This doctest currently covers only the latter item.
.. autoexception:: zope.interface.Invalid
Testing for attributes
----------------------
@ -208,3 +194,25 @@ variable keyword arguments, the implementation must also accept them.
... def needs_varargs(self, **kwargs): pass
>>> verify_foo()
The object <Foo...> violates its contract in IFoo.needs_varargs(*args): implementation doesn't support variable arguments.
Verifying Classes
=================
The function `verifyClass` is used to check that a class implements
an interface properly, meaning that its instances properly provide the
interface. Most of the same things that `verifyObject` checks can be
checked for classes.
.. autofunction:: verifyClass
.. doctest::
>>> from zope.interface.verify import verifyClass
>>> def verify_foo_class():
... try:
... return verifyClass(IFoo, Foo)
... except BrokenMethodImplementation as e:
... print(e)
>>> verify_foo_class()
The object <class 'Foo'> violates its contract in IFoo.needs_varargs(*args): implementation doesn't support variable arguments.

View File

@ -580,6 +580,10 @@ class IInterfaceDeclaration(Interface):
Instances of ``C`` implement ``I1``, ``I2``, and whatever interfaces
instances of ``A`` and ``B`` implement.
.. deprecated:: 5.0
This only works for Python 2. The `implementer` decorator
is preferred for all versions.
"""
def implementsOnly(*interfaces):
@ -612,6 +616,10 @@ class IInterfaceDeclaration(Interface):
Instances of ``C`` implement ``I1``, ``I2``, regardless of what
instances of ``A`` and ``B`` implement.
.. deprecated:: 5.0
This only works for Python 2. The `implementer_only` decorator
is preferred for all versions.
"""
def classProvides(*interfaces):
@ -642,7 +650,12 @@ class IInterfaceDeclaration(Interface):
directlyProvides(theclass, I1)
after the class has been created.
.. deprecated:: 5.0
This only works for Python 2. The `provider` decorator
is preferred for all versions.
"""
def provider(*interfaces):
"""A class decorator version of `classProvides`"""

View File

@ -36,20 +36,27 @@ MethodTypes = (MethodType, )
def _verify(iface, candidate, tentative=False, vtype=None):
"""Verify that *candidate* might correctly implement *iface*.
"""
Verify that *candidate* might correctly provide *iface*.
This involves:
- Making sure the candidate defines all the necessary methods
- Making sure the candidate claims that it provides the
interface using ``iface.providedBy`` (unless *tentative* is `True`,
in which case this step is skipped). This means that the candidate's class
declares that it `implements <zope.interface.implementer>` the interface,
or the candidate itself declares that it `provides <zope.interface.provider>`
the interface
- Making sure the methods have the correct signature
- Making sure the candidate defines all the necessary methods
- Making sure the candidate asserts that it implements the interface
- Making sure the methods have the correct signature (to the
extent possible)
Note that this isn't the same as verifying that the class does
implement the interface.
- Making sure the candidate defines all the necessary attributes
If *tentative* is true (not the default), suppress the "is implemented by" test.
:raises zope.interface.Invalid: If any of the previous
conditions does not hold.
"""
if vtype == 'c':
@ -126,11 +133,15 @@ def _verify(iface, candidate, tentative=False, vtype=None):
return True
def verifyClass(iface, candidate, tentative=False):
"""
Verify that the *candidate* might correctly provide *iface*.
"""
return _verify(iface, candidate, tentative, vtype='c')
def verifyObject(iface, candidate, tentative=False):
return _verify(iface, candidate, tentative, vtype='o')
verifyObject.__doc__ = _verify.__doc__
_MSG_TOO_MANY = 'implementation requires too many arguments'
_KNOWN_PYPY2_FALSE_POSITIVES = frozenset((