Skip to content

Update collections from Python 3.11.2 #4876

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 66 additions & 48 deletions Lib/collections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,19 @@ def pop(self, key, default=__marker):
is raised.

'''
if key in self:
result = self[key]
del self[key]
marker = self.__marker
result = dict.pop(self, key, marker)
if result is not marker:
# The same as in __delitem__().
link = self.__map.pop(key)
link_prev = link.prev
link_next = link.next
link_prev.next = link_next
link_next.prev = link_prev
link.prev = None
link.next = None
return result
if default is self.__marker:
if default is marker:
raise KeyError(key)
return default

Expand All @@ -267,10 +275,22 @@ def __repr__(self):

def __reduce__(self):
'Return state information for pickling'
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
return self.__class__, (), inst_dict or None, None, iter(self.items())
state = self.__getstate__()
if state:
if isinstance(state, tuple):
state, slots = state
else:
slots = {}
state = state.copy()
slots = slots.copy()
for k in vars(OrderedDict()):
state.pop(k, None)
slots.pop(k, None)
if slots:
state = state, slots
else:
state = state or None
return self.__class__, (), state, None, iter(self.items())

def copy(self):
'od.copy() -> a shallow copy of od'
Expand Down Expand Up @@ -613,11 +633,9 @@ def elements(self):
['A', 'A', 'B', 'B', 'C', 'C']

# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
>>> import math
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
>>> product = 1
>>> for factor in prime_factors.elements(): # loop over factors
... product *= factor # and multiply them
>>> product
>>> math.prod(prime_factors.elements())
1836

Note, if an element's count has been set to zero or is a negative
Expand Down Expand Up @@ -714,42 +732,6 @@ def __delitem__(self, elem):
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__}()'
Expand Down Expand Up @@ -795,6 +777,42 @@ def __repr__(self):
# (cp >= cq) == (sp >= sq)
# (cp > cq) == (sp > sq)

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 __add__(self, other):
'''Add counts from two counters.

Expand Down
12 changes: 9 additions & 3 deletions Lib/test/test_ordered_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ def test_equality(self):
# different length implied inequality
self.assertNotEqual(od1, OrderedDict(pairs[:-1]))

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_copying(self):
OrderedDict = self.OrderedDict
# Check that ordered dicts are copyable, deepcopyable, picklable,
Expand Down Expand Up @@ -324,6 +326,8 @@ def check(dup):
check(update_test)
check(OrderedDict(od))

@unittest.expectedFailure
# TODO: RUSTPYTHON
def test_yaml_linkage(self):
OrderedDict = self.OrderedDict
# Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature.
Expand All @@ -334,6 +338,8 @@ def test_yaml_linkage(self):
# '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n'
self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1]))

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_reduce_not_too_fat(self):
OrderedDict = self.OrderedDict
# do not save instance dictionary if not needed
Expand All @@ -345,6 +351,8 @@ def test_reduce_not_too_fat(self):
self.assertEqual(od.__dict__['x'], 10)
self.assertEqual(od.__reduce__()[2], {'x': 10})

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_pickle_recursive(self):
OrderedDict = self.OrderedDict
od = OrderedDict()
Expand Down Expand Up @@ -983,8 +991,6 @@ def test_popitem(self):
self.assertEqual(c.popitem(last=True), (3, 3))
self.assertEqual(c.counts, {'get': 0, 'set': 3, 'del': 0})

# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_pop(self):
c = self.type2test(3)
for i in range(1, 4):
Expand Down Expand Up @@ -1013,7 +1019,7 @@ class PySimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase):
class type2test(SimpleLRUCache, py_coll.OrderedDict):
pass

@unittest.skip("TODO: RUSTPYTHON")

@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
class CSimpleLRUCacheTests(SimpleLRUCacheTests, unittest.TestCase):

Expand Down