forked from Rust-related/RustPython
Merge pull request #5180 from dchiquito/3.12-collections
Update `_collections_abc.py` and `test_collections.py` to 3.12.2
This commit is contained in:
74
Lib/_collections_abc.py
vendored
74
Lib/_collections_abc.py
vendored
@@ -6,6 +6,32 @@
|
||||
Unit tests are in test_collections.
|
||||
"""
|
||||
|
||||
############ Maintenance notes #########################################
|
||||
#
|
||||
# ABCs are different from other standard library modules in that they
|
||||
# specify compliance tests. In general, once an ABC has been published,
|
||||
# new methods (either abstract or concrete) cannot be added.
|
||||
#
|
||||
# Though classes that inherit from an ABC would automatically receive a
|
||||
# new mixin method, registered classes would become non-compliant and
|
||||
# violate the contract promised by ``isinstance(someobj, SomeABC)``.
|
||||
#
|
||||
# Though irritating, the correct procedure for adding new abstract or
|
||||
# mixin methods is to create a new ABC as a subclass of the previous
|
||||
# ABC. For example, union(), intersection(), and difference() cannot
|
||||
# be added to Set but could go into a new ABC that extends Set.
|
||||
#
|
||||
# Because they are so hard to change, new ABCs should have their APIs
|
||||
# carefully thought through prior to publication.
|
||||
#
|
||||
# Since ABCMeta only checks for the presence of methods, it is possible
|
||||
# to alter the signature of a method by adding optional arguments
|
||||
# or changing parameters names. This is still a bit dubious but at
|
||||
# least it won't cause isinstance() to return an incorrect result.
|
||||
#
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
import sys
|
||||
|
||||
@@ -23,7 +49,7 @@ __all__ = ["Awaitable", "Coroutine",
|
||||
"Mapping", "MutableMapping",
|
||||
"MappingView", "KeysView", "ItemsView", "ValuesView",
|
||||
"Sequence", "MutableSequence",
|
||||
"ByteString",
|
||||
"ByteString", "Buffer",
|
||||
]
|
||||
|
||||
# This module has been renamed from collections.abc to _collections_abc to
|
||||
@@ -413,6 +439,21 @@ class Collection(Sized, Iterable, Container):
|
||||
return NotImplemented
|
||||
|
||||
|
||||
class Buffer(metaclass=ABCMeta):
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@abstractmethod
|
||||
def __buffer__(self, flags: int, /) -> memoryview:
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def __subclasshook__(cls, C):
|
||||
if cls is Buffer:
|
||||
return _check_methods(C, "__buffer__")
|
||||
return NotImplemented
|
||||
|
||||
|
||||
class _CallableGenericAlias(GenericAlias):
|
||||
""" Represent `Callable[argtypes, resulttype]`.
|
||||
|
||||
@@ -455,15 +496,8 @@ class _CallableGenericAlias(GenericAlias):
|
||||
# rather than the default types.GenericAlias object. Most of the
|
||||
# code is copied from typing's _GenericAlias and the builtin
|
||||
# types.GenericAlias.
|
||||
|
||||
if not isinstance(item, tuple):
|
||||
item = (item,)
|
||||
# A special case in PEP 612 where if X = Callable[P, int],
|
||||
# then X[int, str] == X[[int, str]].
|
||||
if (len(self.__parameters__) == 1
|
||||
and _is_param_expr(self.__parameters__[0])
|
||||
and item and not _is_param_expr(item[0])):
|
||||
item = (item,)
|
||||
|
||||
new_args = super().__getitem__(item).__args__
|
||||
|
||||
@@ -491,9 +525,8 @@ def _type_repr(obj):
|
||||
|
||||
Copied from :mod:`typing` since collections.abc
|
||||
shouldn't depend on that module.
|
||||
(Keep this roughly in sync with the typing version.)
|
||||
"""
|
||||
if isinstance(obj, GenericAlias):
|
||||
return repr(obj)
|
||||
if isinstance(obj, type):
|
||||
if obj.__module__ == 'builtins':
|
||||
return obj.__qualname__
|
||||
@@ -1038,8 +1071,27 @@ Sequence.register(str)
|
||||
Sequence.register(range)
|
||||
Sequence.register(memoryview)
|
||||
|
||||
class _DeprecateByteStringMeta(ABCMeta):
|
||||
def __new__(cls, name, bases, namespace, **kwargs):
|
||||
if name != "ByteString":
|
||||
import warnings
|
||||
|
||||
class ByteString(Sequence):
|
||||
warnings._deprecated(
|
||||
"collections.abc.ByteString",
|
||||
remove=(3, 14),
|
||||
)
|
||||
return super().__new__(cls, name, bases, namespace, **kwargs)
|
||||
|
||||
def __instancecheck__(cls, instance):
|
||||
import warnings
|
||||
|
||||
warnings._deprecated(
|
||||
"collections.abc.ByteString",
|
||||
remove=(3, 14),
|
||||
)
|
||||
return super().__instancecheck__(instance)
|
||||
|
||||
class ByteString(Sequence, metaclass=_DeprecateByteStringMeta):
|
||||
"""This unifies bytes and bytearray.
|
||||
|
||||
XXX Should add all their methods.
|
||||
|
||||
45
Lib/collections/__init__.py
vendored
45
Lib/collections/__init__.py
vendored
@@ -45,6 +45,11 @@ except ImportError:
|
||||
else:
|
||||
_collections_abc.MutableSequence.register(deque)
|
||||
|
||||
try:
|
||||
from _collections import _deque_iterator
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
from _collections import defaultdict
|
||||
except ImportError:
|
||||
@@ -94,17 +99,19 @@ class OrderedDict(dict):
|
||||
# Individual links are kept alive by the hard reference in self.__map.
|
||||
# Those hard references disappear when a key is deleted from an OrderedDict.
|
||||
|
||||
def __new__(cls, /, *args, **kwds):
|
||||
"Create the ordered dict object and set up the underlying structures."
|
||||
self = dict.__new__(cls)
|
||||
self.__hardroot = _Link()
|
||||
self.__root = root = _proxy(self.__hardroot)
|
||||
root.prev = root.next = root
|
||||
self.__map = {}
|
||||
return self
|
||||
|
||||
def __init__(self, other=(), /, **kwds):
|
||||
'''Initialize an ordered dictionary. The signature is the same as
|
||||
regular dictionaries. Keyword argument order is preserved.
|
||||
'''
|
||||
try:
|
||||
self.__root
|
||||
except AttributeError:
|
||||
self.__hardroot = _Link()
|
||||
self.__root = root = _proxy(self.__hardroot)
|
||||
root.prev = root.next = root
|
||||
self.__map = {}
|
||||
self.__update(other, **kwds)
|
||||
|
||||
def __setitem__(self, key, value,
|
||||
@@ -271,7 +278,7 @@ class OrderedDict(dict):
|
||||
'od.__repr__() <==> repr(od)'
|
||||
if not self:
|
||||
return '%s()' % (self.__class__.__name__,)
|
||||
return '%s(%r)' % (self.__class__.__name__, list(self.items()))
|
||||
return '%s(%r)' % (self.__class__.__name__, dict(self.items()))
|
||||
|
||||
def __reduce__(self):
|
||||
'Return state information for pickling'
|
||||
@@ -511,9 +518,12 @@ def namedtuple(typename, field_names, *, rename=False, defaults=None, module=Non
|
||||
# specified a particular module.
|
||||
if module is None:
|
||||
try:
|
||||
module = _sys._getframe(1).f_globals.get('__name__', '__main__')
|
||||
except (AttributeError, ValueError):
|
||||
pass
|
||||
module = _sys._getframemodulename(1) or '__main__'
|
||||
except AttributeError:
|
||||
try:
|
||||
module = _sys._getframe(1).f_globals.get('__name__', '__main__')
|
||||
except (AttributeError, ValueError):
|
||||
pass
|
||||
if module is not None:
|
||||
result.__module__ = module
|
||||
|
||||
@@ -1015,8 +1025,8 @@ class ChainMap(_collections_abc.MutableMapping):
|
||||
|
||||
def __iter__(self):
|
||||
d = {}
|
||||
for mapping in reversed(self.maps):
|
||||
d.update(dict.fromkeys(mapping)) # reuses stored hash values if possible
|
||||
for mapping in map(dict.fromkeys, reversed(self.maps)):
|
||||
d |= mapping # reuses stored hash values if possible
|
||||
return iter(d)
|
||||
|
||||
def __contains__(self, key):
|
||||
@@ -1136,10 +1146,17 @@ class UserDict(_collections_abc.MutableMapping):
|
||||
def __iter__(self):
|
||||
return iter(self.data)
|
||||
|
||||
# Modify __contains__ to work correctly when __missing__ is present
|
||||
# Modify __contains__ and get() to work like dict
|
||||
# does when __missing__ is present.
|
||||
def __contains__(self, key):
|
||||
return key in self.data
|
||||
|
||||
def get(self, key, default=None):
|
||||
if key in self:
|
||||
return self[key]
|
||||
return default
|
||||
|
||||
|
||||
# Now, add the methods in dicts but not in MutableMapping
|
||||
def __repr__(self):
|
||||
return repr(self.data)
|
||||
|
||||
45
Lib/test/test_collections.py
vendored
45
Lib/test/test_collections.py
vendored
@@ -25,7 +25,7 @@ from collections.abc import Sized, Container, Callable, Collection
|
||||
from collections.abc import Set, MutableSet
|
||||
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView, ValuesView
|
||||
from collections.abc import Sequence, MutableSequence
|
||||
from collections.abc import ByteString
|
||||
from collections.abc import ByteString, Buffer
|
||||
|
||||
|
||||
class TestUserObjects(unittest.TestCase):
|
||||
@@ -71,6 +71,14 @@ class TestUserObjects(unittest.TestCase):
|
||||
obj[123] = "abc"
|
||||
self._copy_test(obj)
|
||||
|
||||
def test_dict_missing(self):
|
||||
class A(UserDict):
|
||||
def __missing__(self, key):
|
||||
return 456
|
||||
self.assertEqual(A()[123], 456)
|
||||
# get() ignores __missing__ on dict
|
||||
self.assertIs(A().get(123), None)
|
||||
|
||||
|
||||
################################################################################
|
||||
### ChainMap (helper class for configparser and the string module)
|
||||
@@ -539,7 +547,7 @@ class TestNamedTuple(unittest.TestCase):
|
||||
self.assertEqual(Dot(1)._replace(d=999), (999,))
|
||||
self.assertEqual(Dot(1)._fields, ('d',))
|
||||
|
||||
n = 5000
|
||||
n = support.EXCEEDS_RECURSION_LIMIT
|
||||
names = list(set(''.join([choice(string.ascii_letters)
|
||||
for j in range(10)]) for i in range(n)))
|
||||
n = len(names)
|
||||
@@ -1629,7 +1637,7 @@ class TestCollectionABCs(ABCTestCase):
|
||||
class SetUsingInstanceFromIterable(MutableSet):
|
||||
def __init__(self, values, created_by):
|
||||
if not created_by:
|
||||
raise ValueError(f'created_by must be specified')
|
||||
raise ValueError('created_by must be specified')
|
||||
self.created_by = created_by
|
||||
self._values = set(values)
|
||||
|
||||
@@ -1949,13 +1957,38 @@ class TestCollectionABCs(ABCTestCase):
|
||||
|
||||
def test_ByteString(self):
|
||||
for sample in [bytes, bytearray]:
|
||||
self.assertIsInstance(sample(), ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertIsInstance(sample(), ByteString)
|
||||
self.assertTrue(issubclass(sample, ByteString))
|
||||
for sample in [str, list, tuple]:
|
||||
self.assertNotIsInstance(sample(), ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertNotIsInstance(sample(), ByteString)
|
||||
self.assertFalse(issubclass(sample, ByteString))
|
||||
self.assertNotIsInstance(memoryview(b""), ByteString)
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.assertNotIsInstance(memoryview(b""), ByteString)
|
||||
self.assertFalse(issubclass(memoryview, ByteString))
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
self.validate_abstract_methods(ByteString, '__getitem__', '__len__')
|
||||
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
class X(ByteString): pass
|
||||
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
# No metaclass conflict
|
||||
class Z(ByteString, Awaitable): pass
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
# Need to implement __buffer__ and __release_buffer__
|
||||
# https://docs.python.org/3.13/reference/datamodel.html#emulating-buffer-types
|
||||
@unittest.expectedFailure
|
||||
def test_Buffer(self):
|
||||
for sample in [bytes, bytearray, memoryview]:
|
||||
self.assertIsInstance(sample(b"x"), Buffer)
|
||||
self.assertTrue(issubclass(sample, Buffer))
|
||||
for sample in [str, list, tuple]:
|
||||
self.assertNotIsInstance(sample(), Buffer)
|
||||
self.assertFalse(issubclass(sample, Buffer))
|
||||
self.validate_abstract_methods(Buffer, '__buffer__')
|
||||
|
||||
# TODO: RUSTPYTHON
|
||||
@unittest.expectedFailure
|
||||
|
||||
15
Lib/test/test_ordered_dict.py
vendored
15
Lib/test/test_ordered_dict.py
vendored
@@ -122,6 +122,17 @@ class OrderedDictTests:
|
||||
self.OrderedDict(Spam())
|
||||
self.assertEqual(calls, ['keys'])
|
||||
|
||||
def test_overridden_init(self):
|
||||
# Sync-up pure Python OD class with C class where
|
||||
# a consistent internal state is created in __new__
|
||||
# rather than __init__.
|
||||
OrderedDict = self.OrderedDict
|
||||
class ODNI(OrderedDict):
|
||||
def __init__(*args, **kwargs):
|
||||
pass
|
||||
od = ODNI()
|
||||
od['a'] = 1 # This used to fail because __init__ was bypassed
|
||||
|
||||
def test_fromkeys(self):
|
||||
OrderedDict = self.OrderedDict
|
||||
od = OrderedDict.fromkeys('abc')
|
||||
@@ -370,7 +381,7 @@ class OrderedDictTests:
|
||||
OrderedDict = self.OrderedDict
|
||||
od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])
|
||||
self.assertEqual(repr(od),
|
||||
"OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])")
|
||||
"OrderedDict({'c': 1, 'b': 2, 'a': 3, 'd': 4, 'e': 5, 'f': 6})")
|
||||
self.assertEqual(eval(repr(od)), od)
|
||||
self.assertEqual(repr(OrderedDict()), "OrderedDict()")
|
||||
|
||||
@@ -380,7 +391,7 @@ class OrderedDictTests:
|
||||
od = OrderedDict.fromkeys('abc')
|
||||
od['x'] = od
|
||||
self.assertEqual(repr(od),
|
||||
"OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
|
||||
"OrderedDict({'a': None, 'b': None, 'c': None, 'x': ...})")
|
||||
|
||||
def test_repr_recursive_values(self):
|
||||
OrderedDict = self.OrderedDict
|
||||
|
||||
5
Lib/test/test_typing.py
vendored
5
Lib/test/test_typing.py
vendored
@@ -705,6 +705,11 @@ class CollectionsCallableTests(BaseCallableTests, BaseTestCase):
|
||||
def test_concatenate(self): # TODO: RUSTPYTHON, remove when this passes
|
||||
super().test_concatenate() # TODO: RUSTPYTHON, remove when this passes
|
||||
|
||||
# TODO: RUSTPYTHON might be fixed by updating typing to 3.12
|
||||
@unittest.expectedFailure
|
||||
def test_repr(self): # TODO: RUSTPYTHON, remove when this passes
|
||||
super().test_repr() # TODO: RUSTPYTHON, remove when this passes
|
||||
|
||||
|
||||
class LiteralTests(BaseTestCase):
|
||||
def test_basics(self):
|
||||
|
||||
Reference in New Issue
Block a user