Update collections/test_{collections,defaultdict} from CPython 3.10.5

This commit is contained in:
CPython developers authored and Jeong Yunwon committed 2022-07-18 03:54:49 +09:00
1 parent da54c40566
commit 9537149572
4 files changed
+198 -178

No files matched your search

+87 -101
View File
@@ -27,7 +27,6 @@ __all__ = [
]
import _collections_abc
import heapq as _heapq
import sys as _sys
from itertools import chain as _chain
@@ -56,22 +55,6 @@ except ImportError:
from ._defaultdict import defaultdict
def __getattr__(name):
# For backwards compatibility, continue to make the collections ABCs
# through Python 3.6 available through the collections module.
# Note, no new collections ABCs were added in Python 3.7
if name in _collections_abc.__all__:
obj = getattr(_collections_abc, name)
import warnings
warnings.warn("Using or importing the ABCs from 'collections' instead "
"of from 'collections.abc' is deprecated since Python 3.3, "
"and in 3.10 it will stop working",
DeprecationWarning, stacklevel=2)
globals()[name] = obj
return obj
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
################################################################################
### OrderedDict
################################################################################
@@ -111,17 +94,10 @@ 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 __init__(*args, **kwds):
def __init__(self, other=(), /, **kwds):
'''Initialize an ordered dictionary. The signature is the same as
regular dictionaries. Keyword argument order is preserved.
'''
if not args:
raise TypeError("descriptor '__init__' of 'OrderedDict' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
@@ -129,7 +105,7 @@ class OrderedDict(dict):
self.__root = root = _proxy(self.__hardroot)
root.prev = root.next = root
self.__map = {}
self.__update(*args, **kwds)
self.__update(other, **kwds)
def __setitem__(self, key, value,
dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
@@ -455,8 +431,8 @@ def namedtuple(typename, field_names, *, rename=False, defaults=None, module=Non
_make.__func__.__doc__ = (f'Make a new {typename} object from a sequence '
'or iterable')
def _replace(_self, /, **kwds):
result = _self._make(_map(kwds.pop, field_names, _self))
def _replace(self, /, **kwds):
result = self._make(_map(kwds.pop, field_names, self))
if kwds:
raise ValueError(f'Got unexpected field names: {list(kwds)!r}')
return result
@@ -500,6 +476,7 @@ def namedtuple(typename, field_names, *, rename=False, defaults=None, module=Non
'__repr__': __repr__,
'_asdict': _asdict,
'__getnewargs__': __getnewargs__,
'__match_args__': field_names,
}
for index, name in enumerate(field_names):
doc = _sys.intern(f'Alias for field number {index}')
@@ -589,7 +566,7 @@ class Counter(dict):
# http://code.activestate.com/recipes/259174/
# Knuth, TAOCP Vol. II section 4.6.3
def __init__(*args, **kwds):
def __init__(self, iterable=None, /, **kwds):
'''Create a new, empty Counter object. And if given, count elements
from an input iterable. Or, initialize the count from another mapping
of elements to their counts.
@@ -600,20 +577,18 @@ class Counter(dict):
>>> c = Counter(a=4, b=2) # a new counter from keyword args
'''
if not args:
raise TypeError("descriptor '__init__' of 'Counter' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
super(Counter, self).__init__()
self.update(*args, **kwds)
super().__init__()
self.update(iterable, **kwds)
def __missing__(self, key):
'The count of elements not in the Counter is zero.'
# Needed so that self[missing_item] does not raise KeyError
return 0
def total(self):
'Sum of the counts'
return sum(self.values())
def most_common(self, n=None):
'''List the n most common elements and their counts from the most
common to the least. If n is None, then list all element counts.
@@ -625,7 +600,10 @@ class Counter(dict):
# Emulate Bag.sortedByCount from Smalltalk
if n is None:
return sorted(self.items(), key=_itemgetter(1), reverse=True)
return _heapq.nlargest(n, self.items(), key=_itemgetter(1))
# Lazy import to speedup Python startup time
import heapq
return heapq.nlargest(n, self.items(), key=_itemgetter(1))
def elements(self):
'''Iterator over elements repeating each as many times as its count.
@@ -663,7 +641,7 @@ class Counter(dict):
raise NotImplementedError(
'Counter.fromkeys() is undefined. Use Counter(iterable) instead.')
def update(*args, **kwds):
def update(self, iterable=None, /, **kwds):
'''Like dict.update() but add counts instead of replacing them.
Source can be an iterable, a dictionary, or another Counter instance.
@@ -683,14 +661,6 @@ class Counter(dict):
# contexts. Instead, we implement straight-addition. Both the inputs
# and outputs are allowed to contain zero and negative counts.
if not args:
raise TypeError("descriptor 'update' of 'Counter' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
iterable = args[0] if args else None
if iterable is not None:
if isinstance(iterable, _collections_abc.Mapping):
if self:
@@ -699,13 +669,13 @@ class Counter(dict):
self[elem] = count + self_get(elem, 0)
else:
# fast path when counter is empty
super(Counter, self).update(iterable)
super().update(iterable)
else:
_count_elements(self, iterable)
if kwds:
self.update(kwds)
def subtract(*args, **kwds):
def subtract(self, iterable=None, /, **kwds):
'''Like dict.update() but subtracts counts instead of replacing them.
Counts can be reduced below zero. Both the inputs and outputs are
allowed to contain zero and negative counts.
@@ -721,14 +691,6 @@ class Counter(dict):
-1
'''
if not args:
raise TypeError("descriptor 'subtract' of 'Counter' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
iterable = args[0] if args else None
if iterable is not None:
self_get = self.get
if isinstance(iterable, _collections_abc.Mapping):
@@ -752,6 +714,42 @@ class Counter(dict):
if elem in self:
super().__delitem__(elem)
def __eq__(self, other):
'True if all counts agree. Missing counts are treated as zero.'
if not isinstance(other, Counter):
return NotImplemented
return all(self[e] == other[e] for c in (self, other) for e in c)
def __ne__(self, other):
'True if any counts disagree. Missing counts are treated as zero.'
if not isinstance(other, Counter):
return NotImplemented
return not self == other
def __le__(self, other):
'True if all counts in self are a subset of those in other.'
if not isinstance(other, Counter):
return NotImplemented
return all(self[e] <= other[e] for c in (self, other) for e in c)
def __lt__(self, other):
'True if all counts in self are a proper subset of those in other.'
if not isinstance(other, Counter):
return NotImplemented
return self <= other and self != other
def __ge__(self, other):
'True if all counts in self are a superset of those in other.'
if not isinstance(other, Counter):
return NotImplemented
return all(self[e] >= other[e] for c in (self, other) for e in c)
def __gt__(self, other):
'True if all counts in self are a proper superset of those in other.'
if not isinstance(other, Counter):
return NotImplemented
return self >= other and self != other
def __repr__(self):
if not self:
return f'{self.__class__.__name__}()'
@@ -772,12 +770,30 @@ class Counter(dict):
# To strip negative and zero counts, add-in an empty counter:
# c += Counter()
#
# Rich comparison operators for multiset subset and superset tests
# are deliberately omitted due to semantic conflicts with the
# existing inherited dict equality method. Subset and superset
# semantics ignore zero counts and require that p≤q ∧ p≥q → p=q;
# however, that would not be the case for p=Counter(a=1, b=0)
# and q=Counter(a=1) where the dictionaries are not equal.
# Results are ordered according to when an element is first
# encountered in the left operand and then by the order
# encountered in the right operand.
#
# When the multiplicities are all zero or one, multiset operations
# are guaranteed to be equivalent to the corresponding operations
# for regular sets.
# Given counter multisets such as:
# cp = Counter(a=1, b=0, c=1)
# cq = Counter(c=1, d=0, e=1)
# The corresponding regular sets would be:
# sp = {'a', 'c'}
# sq = {'c', 'e'}
# All of the following relations would hold:
# set(cp + cq) == sp | sq
# set(cp - cq) == sp - sq
# set(cp | cq) == sp | sq
# set(cp & cq) == sp & sq
# (cp == cq) == (sp == sq)
# (cp != cq) == (sp != sq)
# (cp <= cq) == (sp <= sq)
# (cp < cq) == (sp < sq)
# (cp >= cq) == (sp >= sq)
# (cp > cq) == (sp > sq)
def __add__(self, other):
'''Add counts from two counters.
@@ -1006,12 +1022,15 @@ class ChainMap(_collections_abc.MutableMapping):
__copy__ = copy
def new_child(self, m=None): # like Django's Context.push()
def new_child(self, m=None, **kwargs): # like Django's Context.push()
'''New ChainMap with a new map followed by all previous maps.
If no map is provided, an empty dict is used.
Keyword arguments update the map or new empty dict.
'''
if m is None:
m = {}
m = kwargs
elif kwargs:
m.update(kwargs)
return self.__class__(m, *self.maps)
@property
@@ -1073,34 +1092,16 @@ class ChainMap(_collections_abc.MutableMapping):
class UserDict(_collections_abc.MutableMapping):
# Start by filling-out the abstract methods
def __init__(*args, **kwargs):
if not args:
raise TypeError("descriptor '__init__' of 'UserDict' object "
"needs an argument")
self, *args = args
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
if args:
dict = args[0]
elif 'dict' in kwargs:
dict = kwargs.pop('dict')
import warnings
warnings.warn("Passing 'dict' as keyword argument is deprecated",
DeprecationWarning, stacklevel=2)
else:
dict = None
def __init__(self, dict=None, /, **kwargs):
self.data = {}
if dict is not None:
self.update(dict)
if len(kwargs):
if kwargs:
self.update(kwargs)
def __len__(self):
return len(self.data)
def __bool__(self):
return bool(self.data)
def __getitem__(self, key):
if key in self.data:
return self.data[key]
@@ -1153,9 +1154,6 @@ class UserDict(_collections_abc.MutableMapping):
inst.__dict__["data"] = self.__dict__["data"].copy()
return inst
def __sizeof__(self):
return _sys.getsizeof(self.data)
def copy(self):
if self.__class__ is UserDict:
return UserDict(self.data.copy())
@@ -1222,9 +1220,6 @@ class UserList(_collections_abc.MutableSequence):
def __len__(self):
return len(self.data)
def __bool__(self):
return bool(self.data)
def __getitem__(self, i):
if isinstance(i, slice):
return self.__class__(self.data[i])
@@ -1276,9 +1271,6 @@ class UserList(_collections_abc.MutableSequence):
inst.__dict__["data"] = self.__dict__["data"][:]
return inst
def __sizeof__(self):
return _sys.getsizeof(self.data)
def append(self, item):
self.data.append(item)
@@ -1381,9 +1373,6 @@ class UserString(_collections_abc.Sequence):
char = char.data
return char in self.data
def __bool__(self):
return bool(self.data)
def __len__(self):
return len(self.data)
@@ -1413,9 +1402,6 @@ class UserString(_collections_abc.Sequence):
def __rmod__(self, template):
return self.__class__(str(template) % self)
def __sizeof__(self):
return _sys.getsizeof(self.data)
# the following methods are defined in alphabetical order:
def capitalize(self):
return self.__class__(self.data.capitalize())
@@ -1571,4 +1557,4 @@ class UserString(_collections_abc.Sequence):
return self.__class__(self.data.upper())
def zfill(self, width):
return self.__class__(self.data.zfill(width))
return self.__class__(self.data.zfill(width))
+1
View File
@@ -1,2 +1,3 @@
from _collections_abc import *
from _collections_abc import __all__
from _collections_abc import _CallableGenericAlias
+72 -44
View File
@@ -7,6 +7,7 @@ import inspect
import operator
import pickle
from random import choice, randrange
from itertools import product, chain, combinations
import string
import sys
from test import support
@@ -248,6 +249,10 @@ class TestChainMap(unittest.TestCase):
for k, v in dict(a=1, B=20, C=30, z=100).items(): # check get
self.assertEqual(d.get(k, 100), v)
c = ChainMap({'a': 1, 'b': 2})
d = c.new_child(b=20, c=30)
self.assertEqual(d.maps, [{'b': 20, 'c': 30}, {'a': 1, 'b': 2}])
def test_union_operators(self):
cm1 = ChainMap(dict(a=1, b=2), dict(c=3, d=4))
cm2 = ChainMap(dict(a=10, e=5), dict(b=20, d=4))
@@ -663,8 +668,7 @@ class TestNamedTuple(unittest.TestCase):
a.w = 5
self.assertEqual(a.__dict__, {'w': 5})
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_field_descriptor(self):
Point = namedtuple('Point', 'x y')
p = Point(11, 22)
@@ -683,9 +687,14 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(np.y, 2)
def test_new_builtins_issue_43102(self):
self.assertEqual(
namedtuple('C', ()).__new__.__globals__['__builtins__'],
{})
obj = namedtuple('C', ())
new_func = obj.__new__
self.assertEqual(new_func.__globals__['__builtins__'], {})
self.assertEqual(new_func.__builtins__, {})
def test_match_args(self):
Point = namedtuple('Point', 'x y')
self.assertEqual(Point.__match_args__, ('x', 'y'))
################################################################################
@@ -1516,7 +1525,7 @@ class TestCollectionABCs(ABCTestCase):
items = [5,43,2,1]
s = MySet(items)
r = s.pop()
self.assertEquals(len(s), len(items) - 1)
self.assertEqual(len(s), len(items) - 1)
self.assertNotIn(r, s)
self.assertIn(r, items)
@@ -1566,10 +1575,6 @@ class TestCollectionABCs(ABCTestCase):
def test_issue26915(self):
# Container membership test should check identity first
class CustomEqualObject:
def __eq__(self, other):
return False
class CustomSequence(Sequence):
def __init__(self, seq):
self._seq = seq
@@ -1579,7 +1584,7 @@ class TestCollectionABCs(ABCTestCase):
return len(self._seq)
nan = float('nan')
obj = CustomEqualObject
obj = support.NEVER_EQ
seq = CustomSequence([nan, obj, nan])
containers = [
seq,
@@ -1599,7 +1604,7 @@ class TestCollectionABCs(ABCTestCase):
self.assertSetEqual(set(s1), set(s2))
def test_Set_from_iterable(self):
"""Verify _from_iterable overriden to an instance method works."""
"""Verify _from_iterable overridden to an instance method works."""
class SetUsingInstanceFromIterable(MutableSet):
def __init__(self, values, created_by):
if not created_by:
@@ -1994,6 +1999,12 @@ class TestCollectionABCs(ABCTestCase):
self.assertEqual(len(mss), len(mss2))
self.assertEqual(list(mss), list(mss2))
def test_illegal_patma_flags(self):
with self.assertRaises(TypeError):
class Both(Collection):
__abc_tpflags__ = (Sequence.__flags__ | Mapping.__flags__)
################################################################################
### Counter
@@ -2087,6 +2098,10 @@ class TestCounter(unittest.TestCase):
self.assertRaises(TypeError, Counter, (), ())
self.assertRaises(TypeError, Counter.__init__)
def test_total(self):
c = Counter(a=10, b=5, c=0)
self.assertEqual(c.total(), 15)
def test_order_preservation(self):
# Input order dictates items() order
self.assertEqual(list(Counter('abracadabra').items()),
@@ -2240,31 +2255,6 @@ class TestCounter(unittest.TestCase):
set_result = setop(set(p.elements()), set(q.elements()))
self.assertEqual(counter_result, dict.fromkeys(set_result, 1))
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_subset_superset_not_implemented(self):
# Verify that multiset comparison operations are not implemented.
# These operations were intentionally omitted because multiset
# comparison semantics conflict with existing dict equality semantics.
# For multisets, we would expect that if p<=q and p>=q are both true,
# then p==q. However, dict equality semantics require that p!=q when
# one of sets contains an element with a zero count and the other
# doesn't.
p = Counter(a=1, b=0)
q = Counter(a=1, c=0)
self.assertNotEqual(p, q)
with self.assertRaises(TypeError):
p < q
with self.assertRaises(TypeError):
p <= q
with self.assertRaises(TypeError):
p > q
with self.assertRaises(TypeError):
p >= q
def test_inplace_operations(self):
elements = 'abcd'
for i in range(1000):
@@ -2339,23 +2329,61 @@ class TestCounter(unittest.TestCase):
self.assertTrue(c.called)
self.assertEqual(dict(c), {'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r':2 })
def test_multiset_operations_equivalent_to_set_operations(self):
# When the multiplicities are all zero or one, multiset operations
# are guaranteed to be equivalent to the corresponding operations
# for regular sets.
s = list(product(('a', 'b', 'c'), range(2)))
powerset = chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
counters = [Counter(dict(groups)) for groups in powerset]
for cp, cq in product(counters, repeat=2):
sp = set(cp.elements())
sq = set(cq.elements())
self.assertEqual(set(cp + cq), sp | sq)
self.assertEqual(set(cp - cq), sp - sq)
self.assertEqual(set(cp | cq), sp | sq)
self.assertEqual(set(cp & cq), sp & sq)
self.assertEqual(cp == cq, sp == sq)
self.assertEqual(cp != cq, sp != sq)
self.assertEqual(cp <= cq, sp <= sq)
self.assertEqual(cp >= cq, sp >= sq)
self.assertEqual(cp < cq, sp < sq)
self.assertEqual(cp > cq, sp > sq)
def test_eq(self):
self.assertEqual(Counter(a=3, b=2, c=0), Counter('ababa'))
self.assertNotEqual(Counter(a=3, b=2), Counter('babab'))
def test_le(self):
self.assertTrue(Counter(a=3, b=2, c=0) <= Counter('ababa'))
self.assertFalse(Counter(a=3, b=2) <= Counter('babab'))
def test_lt(self):
self.assertTrue(Counter(a=3, b=1, c=0) < Counter('ababa'))
self.assertFalse(Counter(a=3, b=2, c=0) < Counter('ababa'))
def test_ge(self):
self.assertTrue(Counter(a=2, b=1, c=0) >= Counter('aab'))
self.assertFalse(Counter(a=3, b=2, c=0) >= Counter('aabd'))
def test_gt(self):
self.assertTrue(Counter(a=3, b=2, c=0) > Counter('aab'))
self.assertFalse(Counter(a=2, b=1, c=0) > Counter('aab'))
################################################################################
### Run tests
################################################################################
def test_main(verbose=None):
# TODO: RUSTPYTHON
# NamedTupleDocs = doctest.DocTestSuite(module=collections)
# test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
test_classes = [TestNamedTuple, TestOneTrickPonyABCs,
NamedTupleDocs = doctest.DocTestSuite(module=collections)
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs,
TestCollectionABCs, TestCounter, TestChainMap,
TestUserObjects,
]
support.run_unittest(*test_classes)
# TODO: RUSTPYTHON
# support.run_doctest(collections, verbose)
support.run_doctest(collections, verbose)
if __name__ == "__main__":
test_main(verbose=True)
test_main(verbose=True)
+38 -33
View File
@@ -72,27 +72,6 @@ class TestDefaultDict(unittest.TestCase):
d3[13]
self.assertEqual(repr(d3), "defaultdict(%s, {13: 43})" % repr(foo))
def test_print(self):
d1 = defaultdict()
def foo(): return 42
d2 = defaultdict(foo, {1: 2})
# NOTE: We can't use tempfile.[Named]TemporaryFile since this
# code must exercise the tp_print C code, which only gets
# invoked for *real* files.
tfn = tempfile.mktemp()
try:
f = open(tfn, "w+")
try:
print(d1, file=f)
print(d2, file=f)
f.seek(0)
self.assertEqual(f.readline(), repr(d1) + "\n")
self.assertEqual(f.readline(), repr(d2) + "\n")
finally:
f.close()
finally:
os.remove(tfn)
def test_copy(self):
d1 = defaultdict()
d2 = d1.copy()
@@ -160,18 +139,6 @@ class TestDefaultDict(unittest.TestCase):
r"sub\(<bound method .*sub\._factory "
r"of sub\(\.\.\., \{\}\)>, \{\}\)")
# NOTE: printing a subclass of a builtin type does not call its
# tp_print slot. So this part is essentially the same test as above.
tfn = tempfile.mktemp()
try:
f = open(tfn, "w+")
try:
print(d, file=f)
finally:
f.close()
finally:
os.remove(tfn)
def test_callable_arg(self):
self.assertRaises(TypeError, defaultdict, {})
@@ -183,5 +150,43 @@ class TestDefaultDict(unittest.TestCase):
o = pickle.loads(s)
self.assertEqual(d, o)
def test_union(self):
i = defaultdict(int, {1: 1, 2: 2})
s = defaultdict(str, {0: "zero", 1: "one"})
i_s = i | s
self.assertIs(i_s.default_factory, int)
self.assertDictEqual(i_s, {1: "one", 2: 2, 0: "zero"})
self.assertEqual(list(i_s), [1, 2, 0])
s_i = s | i
self.assertIs(s_i.default_factory, str)
self.assertDictEqual(s_i, {0: "zero", 1: 1, 2: 2})
self.assertEqual(list(s_i), [0, 1, 2])
i_ds = i | dict(s)
self.assertIs(i_ds.default_factory, int)
self.assertDictEqual(i_ds, {1: "one", 2: 2, 0: "zero"})
self.assertEqual(list(i_ds), [1, 2, 0])
ds_i = dict(s) | i
self.assertIs(ds_i.default_factory, int)
self.assertDictEqual(ds_i, {0: "zero", 1: 1, 2: 2})
self.assertEqual(list(ds_i), [0, 1, 2])
with self.assertRaises(TypeError):
i | list(s.items())
with self.assertRaises(TypeError):
list(s.items()) | i
# We inherit a fine |= from dict, so just a few sanity checks here:
i |= list(s.items())
self.assertIs(i.default_factory, int)
self.assertDictEqual(i, {1: "one", 2: 2, 0: "zero"})
self.assertEqual(list(i), [1, 2, 0])
with self.assertRaises(TypeError):
i |= None
if __name__ == "__main__":
unittest.main()