Add numbers ABC interfaces.
This commit is contained in:
parent
653e24f536
commit
5cda166377
|
@ -31,3 +31,8 @@ zope.interface.common.collections
|
|||
=================================
|
||||
|
||||
.. automodule:: zope.interface.common.collections
|
||||
|
||||
zope.interface.common.numbers
|
||||
=============================
|
||||
|
||||
.. automodule:: zope.interface.common.numbers
|
||||
|
|
|
@ -139,7 +139,6 @@ class ISized(ABCInterface):
|
|||
|
||||
# ICallable is not defined because there's no standard signature.
|
||||
|
||||
|
||||
class ICollection(ISized,
|
||||
IIterable,
|
||||
IContainer):
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
##############################################################################
|
||||
# Copyright (c) 2020 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.
|
||||
##############################################################################
|
||||
"""
|
||||
Interface definitions paralleling the abstract base classes defined in
|
||||
:mod:`numbers`.
|
||||
|
||||
After this module is imported, the standard library types will declare
|
||||
that they implement the appropriate interface.
|
||||
|
||||
.. versionadded:: 5.0.0
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import numbers as abc
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import optional
|
||||
|
||||
from zope.interface._compat import PYTHON2 as PY2
|
||||
|
||||
# pylint:disable=inherit-non-class,
|
||||
# pylint:disable=no-self-argument,no-method-argument
|
||||
# pylint:disable=unexpected-special-method-signature
|
||||
# pylint:disable=no-value-for-parameter
|
||||
|
||||
|
||||
class INumber(ABCInterface):
|
||||
abc = abc.Number
|
||||
|
||||
|
||||
class IComplex(INumber):
|
||||
abc = abc.Complex
|
||||
|
||||
@optional
|
||||
def __complex__():
|
||||
"""
|
||||
Rarely implemented, even in builtin types.
|
||||
"""
|
||||
if PY2:
|
||||
@optional
|
||||
def __eq__(other):
|
||||
"""
|
||||
The interpreter may supply one through complicated rules.
|
||||
"""
|
||||
|
||||
__ne__ = __eq__
|
||||
|
||||
class IReal(IComplex):
|
||||
abc = abc.Real
|
||||
|
||||
@optional
|
||||
def __complex__():
|
||||
"""
|
||||
Rarely implemented, even in builtin types.
|
||||
"""
|
||||
|
||||
__floor__ = __ceil__ = __complex__
|
||||
|
||||
if PY2:
|
||||
@optional
|
||||
def __le__(other):
|
||||
"""
|
||||
The interpreter may supply one through complicated rules.
|
||||
"""
|
||||
|
||||
__lt__ = __le__
|
||||
|
||||
|
||||
class IRational(IReal):
|
||||
abc = abc.Rational
|
||||
|
||||
|
||||
class IIntegral(IRational):
|
||||
abc = abc.Integral
|
|
@ -1,2 +1,58 @@
|
|||
##############################################################################
|
||||
# Copyright (c) 2020 Zope Foundation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This file is necessary to make this directory a package.
|
||||
# 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.
|
||||
##############################################################################
|
||||
|
||||
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import ABCInterfaceClass
|
||||
|
||||
|
||||
def iter_abc_interfaces(predicate=lambda iface: True):
|
||||
# Iterate ``(iface, classes)``, where ``iface`` is a descendent of
|
||||
# the ABCInterfaceClass passing the *predicate* and ``classes`` is
|
||||
# an iterable of classes registered to conform to that interface.
|
||||
#
|
||||
# Note that some builtin classes are registered for two distinct
|
||||
# parts of the ABC/interface tree. For example, bytearray is both ByteString
|
||||
# and MutableSequence.
|
||||
seen = set()
|
||||
stack = list(ABCInterface.dependents) # subclasses, but also implementedBy objects
|
||||
while stack:
|
||||
iface = stack.pop(0)
|
||||
if iface in seen or not isinstance(iface, ABCInterfaceClass):
|
||||
continue
|
||||
seen.add(iface)
|
||||
stack.extend(list(iface.dependents))
|
||||
if not predicate(iface):
|
||||
continue
|
||||
|
||||
registered = list(iface.getRegisteredConformers())
|
||||
if registered:
|
||||
yield iface, registered
|
||||
|
||||
|
||||
def add_abc_interface_tests(cls, module):
|
||||
def predicate(iface):
|
||||
return iface.__module__ == module
|
||||
|
||||
for iface, registered_classes in iter_abc_interfaces(predicate):
|
||||
for stdlib_class in registered_classes:
|
||||
|
||||
def test(self, stdlib_class=stdlib_class, iface=iface):
|
||||
if stdlib_class in self.UNVERIFIABLE or stdlib_class.__name__ in self.UNVERIFIABLE:
|
||||
self.skipTest("Unable to verify %s" % stdlib_class)
|
||||
|
||||
self.assertTrue(self.verify(iface, stdlib_class))
|
||||
|
||||
name = 'test_auto_' + stdlib_class.__name__ + '_' + iface.__name__
|
||||
test.__name__ = name
|
||||
assert not hasattr(cls, name)
|
||||
setattr(cls, name, test)
|
||||
|
|
|
@ -25,8 +25,7 @@ except ImportError:
|
|||
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.interface.verify import verifyObject
|
||||
from zope.interface.common import ABCInterface
|
||||
from zope.interface.common import ABCInterfaceClass
|
||||
|
||||
# Note that importing z.i.c.collections does work on import.
|
||||
from zope.interface.common import collections
|
||||
|
||||
|
@ -34,23 +33,7 @@ from zope.interface.common import collections
|
|||
from zope.interface._compat import PYPY
|
||||
from zope.interface._compat import PYTHON2 as PY2
|
||||
|
||||
def walk_abc_interfaces():
|
||||
# Note that some builtin classes are registered for two distinct
|
||||
# parts of the ABC/interface tree. For example, bytearray is both ByteString
|
||||
# and MutableSequence.
|
||||
seen = set()
|
||||
stack = list(ABCInterface.dependents) # subclasses, but also implementedBy objects
|
||||
while stack:
|
||||
iface = stack.pop(0)
|
||||
if iface in seen or not isinstance(iface, ABCInterfaceClass):
|
||||
continue
|
||||
seen.add(iface)
|
||||
stack.extend(list(iface.dependents))
|
||||
|
||||
registered = list(iface.getRegisteredConformers())
|
||||
if registered:
|
||||
yield iface, registered
|
||||
|
||||
from . import add_abc_interface_tests
|
||||
|
||||
class TestVerifyClass(unittest.TestCase):
|
||||
|
||||
|
@ -81,7 +64,7 @@ class TestVerifyClass(unittest.TestCase):
|
|||
# about third-party code here, just standard library types. We start with a
|
||||
# blacklist of things to exclude, but if that gets out of hand we can figure
|
||||
# out a better whitelisting.
|
||||
_UNVERIFIABLE = {
|
||||
UNVERIFIABLE = {
|
||||
# This is declared to be an ISequence, but is missing lots of methods,
|
||||
# including some that aren't part of a language protocol, such as
|
||||
# ``index`` and ``count``.
|
||||
|
@ -97,7 +80,7 @@ class TestVerifyClass(unittest.TestCase):
|
|||
}
|
||||
|
||||
if PYPY:
|
||||
_UNVERIFIABLE.update({
|
||||
UNVERIFIABLE.update({
|
||||
# collections.deque.pop() doesn't support the index= argument to
|
||||
# MutableSequence.pop(). We can't verify this on CPython because we can't
|
||||
# get the signature, but on PyPy we /can/ get the signature, and of course
|
||||
|
@ -109,7 +92,7 @@ class TestVerifyClass(unittest.TestCase):
|
|||
if PY2:
|
||||
# pylint:disable=undefined-variable,no-member
|
||||
# There are a lot more types that are fundamentally unverifiable on Python 2.
|
||||
_UNVERIFIABLE.update({
|
||||
UNVERIFIABLE.update({
|
||||
# Missing several key methods like __getitem__
|
||||
basestring,
|
||||
# Missing __iter__ and __contains__, hard to construct.
|
||||
|
@ -123,22 +106,8 @@ class TestVerifyClass(unittest.TestCase):
|
|||
str,
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def gen_tests(cls):
|
||||
for iface, registered_classes in walk_abc_interfaces():
|
||||
for stdlib_class in registered_classes:
|
||||
if stdlib_class in cls._UNVERIFIABLE or stdlib_class.__name__ in cls._UNVERIFIABLE:
|
||||
continue
|
||||
add_abc_interface_tests(TestVerifyClass, collections.ISet.__module__)
|
||||
|
||||
def test(self, stdlib_class=stdlib_class, iface=iface):
|
||||
self.assertTrue(self.verify(iface, stdlib_class))
|
||||
|
||||
name = 'test_auto_' + stdlib_class.__name__ + '_' + iface.__name__
|
||||
test.__name__ = name
|
||||
assert not hasattr(cls, name)
|
||||
setattr(cls, name, test)
|
||||
|
||||
TestVerifyClass.gen_tests()
|
||||
|
||||
|
||||
class TestVerifyObject(TestVerifyClass):
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
##############################################################################
|
||||
# Copyright (c) 2020 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.
|
||||
##############################################################################
|
||||
|
||||
|
||||
import unittest
|
||||
import numbers as abc
|
||||
|
||||
from zope.interface.verify import verifyClass
|
||||
from zope.interface.verify import verifyObject
|
||||
|
||||
# Note that importing z.i.c.numbers does work on import.
|
||||
from zope.interface.common import numbers
|
||||
|
||||
from . import add_abc_interface_tests
|
||||
|
||||
|
||||
class TestVerifyClass(unittest.TestCase):
|
||||
verifier = staticmethod(verifyClass)
|
||||
UNVERIFIABLE = ()
|
||||
|
||||
def _adjust_object_before_verify(self, iface, x):
|
||||
return x
|
||||
|
||||
def verify(self, iface, klass, **kwargs):
|
||||
return self.verifier(iface,
|
||||
self._adjust_object_before_verify(iface, klass),
|
||||
**kwargs)
|
||||
|
||||
def test_int(self):
|
||||
self.assertIsInstance(int(), abc.Integral)
|
||||
self.assertTrue(self.verify(numbers.IIntegral, int))
|
||||
|
||||
def test_float(self):
|
||||
self.assertIsInstance(float(), abc.Real)
|
||||
self.assertTrue(self.verify(numbers.IReal, float))
|
||||
|
||||
add_abc_interface_tests(TestVerifyClass, numbers.INumber.__module__)
|
||||
|
||||
|
||||
class TestVerifyObject(TestVerifyClass):
|
||||
verifier = staticmethod(verifyObject)
|
||||
|
||||
def _adjust_object_before_verify(self, iface, x):
|
||||
return x()
|
Loading…
Reference in New Issue