test_collections.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. ##############################################################################
  2. # Copyright (c) 2020 Zope Foundation and Contributors.
  3. # All Rights Reserved.
  4. #
  5. # This software is subject to the provisions of the Zope Public License,
  6. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  7. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  8. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  9. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  10. # FOR A PARTICULAR PURPOSE.
  11. ##############################################################################
  12. import array
  13. import unittest
  14. try:
  15. import collections.abc as abc
  16. except ImportError:
  17. import collections as abc
  18. from collections import deque
  19. from collections import OrderedDict
  20. try:
  21. from types import MappingProxyType
  22. except ImportError:
  23. MappingProxyType = object()
  24. from zope.interface import Invalid
  25. # Note that importing z.i.c.collections does work on import.
  26. from zope.interface.common import collections
  27. from zope.interface._compat import PYPY
  28. from zope.interface._compat import PYTHON2 as PY2
  29. from . import add_abc_interface_tests
  30. from . import VerifyClassMixin
  31. from . import VerifyObjectMixin
  32. class TestVerifyClass(VerifyClassMixin, unittest.TestCase):
  33. # Here we test some known builtin classes that are defined to implement
  34. # various collection interfaces as a quick sanity test.
  35. def test_frozenset(self):
  36. self.assertIsInstance(frozenset(), abc.Set)
  37. self.assertTrue(self.verify(collections.ISet, frozenset))
  38. def test_list(self):
  39. self.assertIsInstance(list(), abc.MutableSequence)
  40. self.assertTrue(self.verify(collections.IMutableSequence, list))
  41. # Here we test some derived classes.
  42. def test_UserList(self):
  43. self.assertTrue(self.verify(collections.IMutableSequence,
  44. collections.UserList))
  45. def test_UserDict(self):
  46. self.assertTrue(self.verify(collections.IMutableMapping,
  47. collections.UserDict))
  48. def test_UserString(self):
  49. self.assertTrue(self.verify(collections.ISequence,
  50. collections.UserString))
  51. def test_non_iterable_UserDict(self):
  52. try:
  53. from UserDict import UserDict as NonIterableUserDict # pylint:disable=import-error
  54. except ImportError:
  55. # Python 3
  56. self.skipTest("No UserDict.NonIterableUserDict on Python 3")
  57. with self.assertRaises(Invalid):
  58. self.verify(collections.IMutableMapping, NonIterableUserDict)
  59. # Now we go through the registry, which should have several things,
  60. # mostly builtins, but if we've imported other libraries already,
  61. # it could contain things from outside of there too. We aren't concerned
  62. # about third-party code here, just standard library types. We start with a
  63. # blacklist of things to exclude, but if that gets out of hand we can figure
  64. # out a better whitelisting.
  65. UNVERIFIABLE = {
  66. # This is declared to be an ISequence, but is missing lots of methods,
  67. # including some that aren't part of a language protocol, such as
  68. # ``index`` and ``count``.
  69. memoryview,
  70. # 'pkg_resources._vendor.pyparsing.ParseResults' is registered as a
  71. # MutableMapping but is missing methods like ``popitem`` and ``setdefault``.
  72. # It's imported due to namespace packages.
  73. 'ParseResults',
  74. # sqlite3.Row claims ISequence but also misses ``index`` and ``count``.
  75. # It's imported because...? Coverage imports it, but why do we have it without
  76. # coverage?
  77. 'Row',
  78. # In Python 3.10 ``array.array`` appears as ``IMutableSequence`` but it
  79. # does not provide a ``clear()`` method and it cannot be instantiated
  80. # using ``array.array()``.
  81. array.array,
  82. }
  83. if PYPY:
  84. UNVERIFIABLE.update({
  85. # collections.deque.pop() doesn't support the index= argument to
  86. # MutableSequence.pop(). We can't verify this on CPython because we can't
  87. # get the signature, but on PyPy we /can/ get the signature, and of course
  88. # it doesn't match.
  89. deque,
  90. # Likewise for index
  91. range,
  92. })
  93. if PY2:
  94. # pylint:disable=undefined-variable,no-member
  95. # There are a lot more types that are fundamentally unverifiable on Python 2.
  96. UNVERIFIABLE.update({
  97. # Missing several key methods like __getitem__
  98. basestring,
  99. # Missing __iter__ and __contains__, hard to construct.
  100. buffer,
  101. # Missing ``__contains__``, ``count`` and ``index``.
  102. xrange,
  103. # These two are missing Set.isdisjoint()
  104. type({}.viewitems()),
  105. type({}.viewkeys()),
  106. })
  107. NON_STRICT_RO = {
  108. }
  109. else:
  110. UNVERIFIABLE_RO = {
  111. # ``array.array`` fails the ``test_auto_ro_*`` tests with and
  112. # without strict RO but only on Windows (AppVeyor) on Python 3.10.0
  113. # (in older versions ``array.array`` does not appear as
  114. # ``IMutableSequence``).
  115. array.array,
  116. }
  117. add_abc_interface_tests(TestVerifyClass, collections.ISet.__module__)
  118. class TestVerifyObject(VerifyObjectMixin,
  119. TestVerifyClass):
  120. CONSTRUCTORS = {
  121. collections.IValuesView: {}.values,
  122. collections.IItemsView: {}.items,
  123. collections.IKeysView: {}.keys,
  124. memoryview: lambda: memoryview(b'abc'),
  125. range: lambda: range(10),
  126. MappingProxyType: lambda: MappingProxyType({}),
  127. collections.UserString: lambda: collections.UserString('abc'),
  128. type(iter(bytearray())): lambda: iter(bytearray()),
  129. type(iter(b'abc')): lambda: iter(b'abc'),
  130. 'coroutine': unittest.SkipTest,
  131. type(iter({}.keys())): lambda: iter({}.keys()),
  132. type(iter({}.items())): lambda: iter({}.items()),
  133. type(iter({}.values())): lambda: iter({}.values()),
  134. type((i for i in range(1))): lambda: (i for i in range(3)),
  135. type(iter([])): lambda: iter([]),
  136. type(reversed([])): lambda: reversed([]),
  137. 'longrange_iterator': unittest.SkipTest,
  138. 'range_iterator': lambda: iter(range(3)),
  139. 'rangeiterator': lambda: iter(range(3)),
  140. type(iter(set())): lambda: iter(set()),
  141. type(iter('')): lambda: iter(''),
  142. 'async_generator': unittest.SkipTest,
  143. type(iter(tuple())): lambda: iter(tuple()),
  144. }
  145. if PY2:
  146. # pylint:disable=undefined-variable,no-member
  147. CONSTRUCTORS.update({
  148. collections.IValuesView: {}.viewvalues,
  149. })
  150. else:
  151. UNVERIFIABLE_RO = {
  152. # ``array.array`` fails the ``test_auto_ro_*`` tests with and
  153. # without strict RO but only on Windows (AppVeyor) on Python 3.10.0
  154. # (in older versions ``array.array`` does not appear as
  155. # ``IMutableSequence``).
  156. array.array,
  157. }