◐ Shell
clean mode source ↗

[3.14] gh-144475: Fix reference management in partial_repr (GH-145362) by miss-islington · Pull Request #145470 · python/cpython

Expand Up @@ -514,6 +514,58 @@ def test_partial_genericalias(self): self.assertEqual(alias.__args__, (int,)) self.assertEqual(alias.__parameters__, ())
# GH-144475: Tests that the partial object does not change until repr finishes def test_repr_safety_against_reentrant_mutation(self): g_partial = None
class Function: def __init__(self, name): self.name = name
def __call__(self): return None
def __repr__(self): return f"Function({self.name})"
class EvilObject: def __init__(self): self.triggered = False
def __repr__(self): if not self.triggered and g_partial is not None: self.triggered = True new_args_tuple = (None,) new_keywords_dict = {"keyword": None} new_tuple_state = (Function("new_function"), new_args_tuple, new_keywords_dict, None) g_partial.__setstate__(new_tuple_state) gc.collect() return f"EvilObject"
trigger = EvilObject() func = Function("old_function")
g_partial = functools.partial(func, None, trigger=trigger) self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), None, trigger=EvilObject)")
trigger.triggered = False g_partial = functools.partial(func, trigger, arg=None) self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, arg=None)")

trigger.triggered = False g_partial = functools.partial(func, trigger, None) self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, None)")
trigger.triggered = False g_partial = functools.partial(func, trigger=trigger, arg=None) self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), trigger=EvilObject, arg=None)")
trigger.triggered = False g_partial = functools.partial(func, trigger, None, None, None, None, arg=None) self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, None, None, None, None, arg=None)")


@unittest.skipUnless(c_functools, 'requires the C _functools module') class TestPartialC(TestPartial, unittest.TestCase): Expand Down