182 lines
7.0 KiB
Python
182 lines
7.0 KiB
Python
##############################################################################
|
|
# 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 array
|
|
import unittest
|
|
try:
|
|
import collections.abc as abc
|
|
except ImportError:
|
|
import collections as abc
|
|
from collections import deque
|
|
from collections import OrderedDict
|
|
|
|
|
|
try:
|
|
from types import MappingProxyType
|
|
except ImportError:
|
|
MappingProxyType = object()
|
|
|
|
from zope.interface import Invalid
|
|
|
|
|
|
# Note that importing z.i.c.collections does work on import.
|
|
from zope.interface.common import collections
|
|
|
|
|
|
from zope.interface._compat import PYPY
|
|
from zope.interface._compat import PYTHON2 as PY2
|
|
|
|
from . import add_abc_interface_tests
|
|
from . import VerifyClassMixin
|
|
from . import VerifyObjectMixin
|
|
|
|
class TestVerifyClass(VerifyClassMixin, unittest.TestCase):
|
|
|
|
# Here we test some known builtin classes that are defined to implement
|
|
# various collection interfaces as a quick sanity test.
|
|
def test_frozenset(self):
|
|
self.assertIsInstance(frozenset(), abc.Set)
|
|
self.assertTrue(self.verify(collections.ISet, frozenset))
|
|
|
|
def test_list(self):
|
|
self.assertIsInstance(list(), abc.MutableSequence)
|
|
self.assertTrue(self.verify(collections.IMutableSequence, list))
|
|
|
|
# Here we test some derived classes.
|
|
def test_UserList(self):
|
|
self.assertTrue(self.verify(collections.IMutableSequence,
|
|
collections.UserList))
|
|
|
|
def test_UserDict(self):
|
|
self.assertTrue(self.verify(collections.IMutableMapping,
|
|
collections.UserDict))
|
|
|
|
def test_UserString(self):
|
|
self.assertTrue(self.verify(collections.ISequence,
|
|
collections.UserString))
|
|
|
|
def test_non_iterable_UserDict(self):
|
|
try:
|
|
from UserDict import UserDict as NonIterableUserDict # pylint:disable=import-error
|
|
except ImportError:
|
|
# Python 3
|
|
self.skipTest("No UserDict.NonIterableUserDict on Python 3")
|
|
|
|
with self.assertRaises(Invalid):
|
|
self.verify(collections.IMutableMapping, NonIterableUserDict)
|
|
|
|
# Now we go through the registry, which should have several things,
|
|
# mostly builtins, but if we've imported other libraries already,
|
|
# it could contain things from outside of there too. We aren't concerned
|
|
# 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 = {
|
|
# 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``.
|
|
memoryview,
|
|
# 'pkg_resources._vendor.pyparsing.ParseResults' is registered as a
|
|
# MutableMapping but is missing methods like ``popitem`` and ``setdefault``.
|
|
# It's imported due to namespace packages.
|
|
'ParseResults',
|
|
# sqlite3.Row claims ISequence but also misses ``index`` and ``count``.
|
|
# It's imported because...? Coverage imports it, but why do we have it without
|
|
# coverage?
|
|
'Row',
|
|
# In Python 3.10 ``array.array`` appears as ``IMutableSequence`` but it
|
|
# does not provide a ``clear()`` method and it cannot be instantiated
|
|
# using ``array.array()``.
|
|
array.array,
|
|
}
|
|
|
|
if PYPY:
|
|
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
|
|
# it doesn't match.
|
|
deque,
|
|
# Likewise for index
|
|
range,
|
|
})
|
|
if PY2:
|
|
# pylint:disable=undefined-variable,no-member
|
|
# There are a lot more types that are fundamentally unverifiable on Python 2.
|
|
UNVERIFIABLE.update({
|
|
# Missing several key methods like __getitem__
|
|
basestring,
|
|
# Missing __iter__ and __contains__, hard to construct.
|
|
buffer,
|
|
# Missing ``__contains__``, ``count`` and ``index``.
|
|
xrange,
|
|
# These two are missing Set.isdisjoint()
|
|
type({}.viewitems()),
|
|
type({}.viewkeys()),
|
|
})
|
|
NON_STRICT_RO = {
|
|
}
|
|
else:
|
|
UNVERIFIABLE_RO = {
|
|
# ``array.array`` fails the ``test_auto_ro_*`` tests with and
|
|
# without strict RO but only on Windows (AppVeyor) on Python 3.10.0
|
|
# (in older versions ``array.array`` does not appear as
|
|
# ``IMutableSequence``).
|
|
array.array,
|
|
}
|
|
|
|
add_abc_interface_tests(TestVerifyClass, collections.ISet.__module__)
|
|
|
|
|
|
class TestVerifyObject(VerifyObjectMixin,
|
|
TestVerifyClass):
|
|
CONSTRUCTORS = {
|
|
collections.IValuesView: {}.values,
|
|
collections.IItemsView: {}.items,
|
|
collections.IKeysView: {}.keys,
|
|
memoryview: lambda: memoryview(b'abc'),
|
|
range: lambda: range(10),
|
|
MappingProxyType: lambda: MappingProxyType({}),
|
|
collections.UserString: lambda: collections.UserString('abc'),
|
|
type(iter(bytearray())): lambda: iter(bytearray()),
|
|
type(iter(b'abc')): lambda: iter(b'abc'),
|
|
'coroutine': unittest.SkipTest,
|
|
type(iter({}.keys())): lambda: iter({}.keys()),
|
|
type(iter({}.items())): lambda: iter({}.items()),
|
|
type(iter({}.values())): lambda: iter({}.values()),
|
|
type((i for i in range(1))): lambda: (i for i in range(3)),
|
|
type(iter([])): lambda: iter([]),
|
|
type(reversed([])): lambda: reversed([]),
|
|
'longrange_iterator': unittest.SkipTest,
|
|
'range_iterator': lambda: iter(range(3)),
|
|
'rangeiterator': lambda: iter(range(3)),
|
|
type(iter(set())): lambda: iter(set()),
|
|
type(iter('')): lambda: iter(''),
|
|
'async_generator': unittest.SkipTest,
|
|
type(iter(tuple())): lambda: iter(tuple()),
|
|
}
|
|
|
|
if PY2:
|
|
# pylint:disable=undefined-variable,no-member
|
|
CONSTRUCTORS.update({
|
|
collections.IValuesView: {}.viewvalues,
|
|
})
|
|
else:
|
|
UNVERIFIABLE_RO = {
|
|
# ``array.array`` fails the ``test_auto_ro_*`` tests with and
|
|
# without strict RO but only on Windows (AppVeyor) on Python 3.10.0
|
|
# (in older versions ``array.array`` does not appear as
|
|
# ``IMutableSequence``).
|
|
array.array,
|
|
}
|