Skip to content

Commit a702e9c

Browse files
authored
Update test_functools.py to 3.14.5 (RustPython#7861)
1 parent 9ee2752 commit a702e9c

1 file changed

Lines changed: 52 additions & 0 deletions

File tree

Lib/test/test_functools.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,58 @@ def test_partial_genericalias(self):
514514
self.assertEqual(alias.__args__, (int,))
515515
self.assertEqual(alias.__parameters__, ())
516516

517+
# GH-144475: Tests that the partial object does not change until repr finishes
518+
def test_repr_safety_against_reentrant_mutation(self):
519+
g_partial = None
520+
521+
class Function:
522+
def __init__(self, name):
523+
self.name = name
524+
525+
def __call__(self):
526+
return None
527+
528+
def __repr__(self):
529+
return f"Function({self.name})"
530+
531+
class EvilObject:
532+
def __init__(self):
533+
self.triggered = False
534+
535+
def __repr__(self):
536+
if not self.triggered and g_partial is not None:
537+
self.triggered = True
538+
new_args_tuple = (None,)
539+
new_keywords_dict = {"keyword": None}
540+
new_tuple_state = (Function("new_function"), new_args_tuple, new_keywords_dict, None)
541+
g_partial.__setstate__(new_tuple_state)
542+
gc.collect()
543+
return f"EvilObject"
544+
545+
trigger = EvilObject()
546+
func = Function("old_function")
547+
548+
g_partial = functools.partial(func, None, trigger=trigger)
549+
self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), None, trigger=EvilObject)")
550+
551+
trigger.triggered = False
552+
g_partial = functools.partial(func, trigger, arg=None)
553+
self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, arg=None)")
554+
555+
556+
trigger.triggered = False
557+
g_partial = functools.partial(func, trigger, None)
558+
self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, None)")
559+
560+
trigger.triggered = False
561+
g_partial = functools.partial(func, trigger=trigger, arg=None)
562+
self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), trigger=EvilObject, arg=None)")
563+
564+
trigger.triggered = False
565+
g_partial = functools.partial(func, trigger, None, None, None, None, arg=None)
566+
self.assertEqual(repr(g_partial),"functools.partial(Function(old_function), EvilObject, None, None, None, None, arg=None)")
567+
568+
517569

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

0 commit comments

Comments
 (0)