Skip to content
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
31 changes: 22 additions & 9 deletions Lib/test/seq_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,23 +261,20 @@ def test_minmax(self):
self.assertEqual(min(u), 0)
self.assertEqual(max(u), 2)

def test_addmul(self):
def test_add(self):
u1 = self.type2test([0])
u2 = self.type2test([0, 1])
self.assertEqual(u1, u1 + self.type2test())
self.assertEqual(u1, self.type2test() + u1)
self.assertEqual(u1 + self.type2test([1]), u2)
self.assertEqual(self.type2test([-1]) + u1, self.type2test([-1, 0]))
self.assertEqual(self.type2test(), u2*0)
self.assertEqual(self.type2test(), 0*u2)

def test_mul(self):
u2 = self.type2test([0, 1])
self.assertEqual(self.type2test(), u2*0)
self.assertEqual(self.type2test(), 0*u2)
self.assertEqual(u2, u2*1)
self.assertEqual(u2, 1*u2)
self.assertEqual(u2, u2*1)
self.assertEqual(u2, 1*u2)
self.assertEqual(u2+u2, u2*2)
self.assertEqual(u2+u2, 2*u2)
self.assertEqual(u2+u2, u2*2)
self.assertEqual(u2+u2, 2*u2)
self.assertEqual(u2+u2+u2, u2*3)
Expand All @@ -286,8 +283,9 @@ def test_addmul(self):
class subclass(self.type2test):
pass
u3 = subclass([0, 1])
self.assertEqual(u3, u3*1)
self.assertIsNot(u3, u3*1)
r = u3*1
self.assertEqual(r, u3)
self.assertIsNot(r, u3)

def test_iadd(self):
u = self.type2test([0, 1])
Expand Down Expand Up @@ -348,6 +346,21 @@ def test_subscript(self):
self.assertRaises(ValueError, a.__getitem__, slice(0, 10, 0))
self.assertRaises(TypeError, a.__getitem__, 'x')

def _assert_cmp(self, a, b, r):
self.assertIs(a == b, r == 0)
self.assertIs(a != b, r != 0)
self.assertIs(a > b, r > 0)
self.assertIs(a <= b, r <= 0)
self.assertIs(a < b, r < 0)
self.assertIs(a >= b, r >= 0)

def test_cmp(self):
a = self.type2test([0, 1])
self._assert_cmp(a, a, 0)
self._assert_cmp(a, self.type2test([0, 1]), 0)
self._assert_cmp(a, self.type2test([0]), 1)
self._assert_cmp(a, self.type2test([0, 2]), -1)

def test_count(self):
a = self.type2test([0, 1, 2])*3
self.assertEqual(a.count(0), 3)
Expand Down
83 changes: 83 additions & 0 deletions Lib/test/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -1574,6 +1574,26 @@ def make_pairs():
self.assertEqual(d.get(key3_3), 44)
self.assertGreaterEqual(eq_count, 1)

def test_overwrite_managed_dict(self):
# GH-130327: Overwriting an object's managed dictionary with another object's
# skipped traversal in favor of inline values, causing the GC to believe that
# the __dict__ wasn't reachable.
import gc

class Shenanigans:
pass

to_be_deleted = Shenanigans()
to_be_deleted.attr = "whatever"
holds_reference = Shenanigans()
holds_reference.__dict__ = to_be_deleted.__dict__
holds_reference.ref = {"circular": to_be_deleted, "data": 42}

del to_be_deleted
gc.collect()
self.assertEqual(holds_reference.ref['data'], 42)
self.assertEqual(holds_reference.attr, "whatever")

@unittest.expectedFailure # TODO: RUSTPYTHON
def test_unhashable_key(self):
d = {'a': 1}
Expand Down Expand Up @@ -1686,6 +1706,69 @@ def test_hash_collision_remove_add(self):
self.assertEqual(len(d), len(items), d)
self.assertEqual(d, dict(items))

def test_clear_reentrant_embedded(self):
# gh-130555: dict.clear() must be safe when values are embedded
# in an object and a destructor mutates the dict.
class MyObj: pass
class ClearOnDelete:
def __del__(self):
nonlocal x
del x

x = MyObj()
x.a = ClearOnDelete()

d = x.__dict__
d.clear()

def test_clear_reentrant_cycle(self):
# gh-130555: dict.clear() must be safe for embedded dicts when the
# object is part of a reference cycle and the last reference to the
# dict is via the cycle.
class MyObj: pass
obj = MyObj()
obj.f = obj
obj.attr = "attr"

d = obj.__dict__
del obj

d.clear()

def test_clear_reentrant_force_combined(self):
# gh-130555: dict.clear() must be safe when a destructor forces the
# dict from embedded/split to combined (setting ma_values to NULL).
class MyObj: pass
class ForceConvert:
def __del__(self):
d[1] = "trigger"

x = MyObj()
x.a = ForceConvert()
x.b = "other"

d = x.__dict__
d.clear()

def test_clear_reentrant_delete(self):
# gh-130555: dict.clear() must be safe when a destructor deletes
# a key from the same embedded dict.
class MyObj: pass
class DelKey:
def __del__(self):
try:
del d['b']
except KeyError:
pass

x = MyObj()
x.a = DelKey()
x.b = "value_b"
x.c = "value_c"

d = x.__dict__
d.clear()


class CAPITest(unittest.TestCase):

Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_listcomps.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ def test_references___class___defined(self):
code, outputs={"res": [2]}, scopes=["module", "function"])
self._check_in_scopes(code, raises=NameError, scopes=["class"])

def test_references___classdict__(self):
code = """
class i: [__classdict__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___conditional_annotations__(self):
code = """
class i: [__conditional_annotations__ for x in y]
"""
self._check_in_scopes(code, raises=NameError)

def test_references___class___enclosing(self):
code = """
__class__ = 2
Expand Down
2 changes: 0 additions & 2 deletions Lib/test/test_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -1969,7 +1969,6 @@ def check_set_op_does_not_crash(self, function):
self.assertIn("changed size during iteration", str(e))


@unittest.skip("TODO: RUSTPYTHON; segfault")
class TestBinaryOpsMutating(TestOperationsMutating):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class no longer segfaults, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct:)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to this, 60 tests will be reported as no longer being skipped. 🎉


def test_eq_with_mutation(self):
Expand Down Expand Up @@ -2058,7 +2057,6 @@ class TestBinaryOpsMutating_Subclass_Set(TestBinaryOpsMutating, unittest.TestCas
constructor2 = set


@unittest.skip("TODO: RUSTPYTHON; segfault")
class TestMethodsMutating(TestOperationsMutating):
Comment on lines -2061 to 2060
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class no longer segfaults, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct:)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to this, 66 tests will be reported as no longer being skipped. 🎉


def test_issubset_with_mutation(self):
Expand Down
93 changes: 93 additions & 0 deletions Lib/test/test_userdict.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# Check every path through every method of UserDict

from collections import UserDict
from test import mapping_tests
import unittest
import collections
import types


class UserDictSubclass(UserDict):
pass

class UserDictSubclass2(UserDict):
pass


d0 = {}
d1 = {"one": 1}
Expand Down Expand Up @@ -155,6 +165,25 @@ def test_init(self):
self.assertRaises(TypeError, collections.UserDict, (), ())
self.assertRaises(TypeError, collections.UserDict.__init__)

def test_data(self):
u = UserDict()
self.assertEqual(u.data, {})
self.assertIs(type(u.data), dict)
d = {'a': 1, 'b': 2}
u = UserDict(d)
self.assertEqual(u.data, d)
self.assertIsNot(u.data, d)
self.assertIs(type(u.data), dict)
u = UserDict(u)
self.assertEqual(u.data, d)
self.assertIs(type(u.data), dict)
u = UserDict([('a', 1), ('b', 2)])
self.assertEqual(u.data, d)
self.assertIs(type(u.data), dict)
u = UserDict(a=1, b=2)
self.assertEqual(u.data, d)
self.assertIs(type(u.data), dict)

def test_update(self):
for kw in 'self', 'dict', 'other', 'iterable':
d = collections.UserDict()
Expand Down Expand Up @@ -215,6 +244,70 @@ class G(collections.UserDict):

test_repr_deep = mapping_tests.TestHashMappingProtocol.test_repr_deep

@unittest.expectedFailure # TODO: RUSTPYTHON; TypeError: unsupported operand type(s) for |: 'UserDict' and 'mappingproxy'
def test_mixed_or(self):
for t in UserDict, dict, types.MappingProxyType:
with self.subTest(t.__name__):
u = UserDict({0: 'a', 1: 'b'}) | t({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)

u = t({0: 'a', 1: 'b'}) | UserDict({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)

u = UserDict({0: 'a', 1: 'b'}) | UserDictSubclass({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)

u = UserDictSubclass({0: 'a', 1: 'b'}) | UserDict({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDictSubclass)

u = UserDictSubclass({0: 'a', 1: 'b'}) | UserDictSubclass2({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDictSubclass)

u = UserDict({1: 'c', 2: 'd'}).__ror__(UserDict({0: 'a', 1: 'b'}))
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)

u = UserDictSubclass({1: 'c', 2: 'd'}).__ror__(UserDictSubclass2({0: 'a', 1: 'b'}))
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDictSubclass)

def test_mixed_ior(self):
for t in UserDict, dict, types.MappingProxyType:
with self.subTest(t.__name__):
u = u2 = UserDict({0: 'a', 1: 'b'})
u |= t({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)
self.assertIs(u, u2)

u = dict({0: 'a', 1: 'b'})
u |= UserDict({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), dict)

u = u2 = UserDict({0: 'a', 1: 'b'})
u |= UserDictSubclass({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDict)
self.assertIs(u, u2)

u = u2 = UserDictSubclass({0: 'a', 1: 'b'})
u |= UserDict({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDictSubclass)
self.assertIs(u, u2)

u = u2 = UserDictSubclass({0: 'a', 1: 'b'})
u |= UserDictSubclass2({1: 'c', 2: 'd'})
self.assertEqual(u, {0: 'a', 1: 'c', 2: 'd'})
self.assertIs(type(u), UserDictSubclass)
self.assertIs(u, u2)


if __name__ == "__main__":
unittest.main()
Loading