diff options
author | Jelle Zijlstra <jelle.zijlstra@gmail.com> | 2024-05-28 18:03:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-28 18:03:33 (GMT) |
commit | 6394a72e99b342d980297ec437ecafea92a044c4 (patch) | |
tree | dcf3ff8f0f88722a6318a28b56ad1496412f335b /Lib | |
parent | 2b46253c5fdf57fd35eb471ad0035e61afe924a6 (diff) | |
download | cpython-6394a72e99b342d980297ec437ecafea92a044c4.zip cpython-6394a72e99b342d980297ec437ecafea92a044c4.tar.gz cpython-6394a72e99b342d980297ec437ecafea92a044c4.tar.bz2 |
[3.13] gh-119311: Fix name mangling with PEP 695 generic classes (#119464) (#119643)
Fixes #119311. Fixes #119395.
(cherry picked from commit a9a74da4a0ca0645f049e67b6434a95e30592c32)
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 3 | ||||
-rw-r--r-- | Lib/test/test_type_params.py | 94 |
2 files changed, 96 insertions, 1 deletions
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index db44677..7742855 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -472,6 +472,7 @@ _code_type = type(_write_atomic.__code__) # Python 3.13a1 3568 (Change semantics of END_FOR) # Python 3.13a5 3569 (Specialize CONTAINS_OP) # Python 3.13a6 3570 (Add __firstlineno__ class attribute) +# Python 3.13b1 3571 (Fix miscompilation of private names in generic classes) # Python 3.14 will start with 3600 @@ -488,7 +489,7 @@ _code_type = type(_write_atomic.__code__) # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3570).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3571).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py index 82f1007..aa9d408 100644 --- a/Lib/test/test_type_params.py +++ b/Lib/test/test_type_params.py @@ -823,6 +823,100 @@ class TypeParamsManglingTest(unittest.TestCase): self.assertEqual(Foo.Alias.__value__, (T, V)) + def test_no_leaky_mangling_in_module(self): + ns = run_code(""" + __before = "before" + class X[T]: pass + __after = "after" + """) + self.assertEqual(ns["__before"], "before") + self.assertEqual(ns["__after"], "after") + + def test_no_leaky_mangling_in_function(self): + ns = run_code(""" + def f(): + class X[T]: pass + _X_foo = 2 + __foo = 1 + assert locals()['__foo'] == 1 + return __foo + """) + self.assertEqual(ns["f"](), 1) + + def test_no_leaky_mangling_in_class(self): + ns = run_code(""" + class Outer: + __before = "before" + class Inner[T]: + __x = "inner" + __after = "after" + """) + Outer = ns["Outer"] + self.assertEqual(Outer._Outer__before, "before") + self.assertEqual(Outer.Inner._Inner__x, "inner") + self.assertEqual(Outer._Outer__after, "after") + + def test_no_mangling_in_bases(self): + ns = run_code(""" + class __Base: + def __init_subclass__(self, **kwargs): + self.kwargs = kwargs + + class Derived[T](__Base, __kwarg=1): + pass + """) + Derived = ns["Derived"] + self.assertEqual(Derived.__bases__, (ns["__Base"], Generic)) + self.assertEqual(Derived.kwargs, {"__kwarg": 1}) + + def test_no_mangling_in_nested_scopes(self): + ns = run_code(""" + from test.test_type_params import make_base + + class __X: + pass + + class Y[T: __X]( + make_base(lambda: __X), + # doubly nested scope + make_base(lambda: (lambda: __X)), + # list comprehension + make_base([__X for _ in (1,)]), + # genexp + make_base(__X for _ in (1,)), + ): + pass + """) + Y = ns["Y"] + T, = Y.__type_params__ + self.assertIs(T.__bound__, ns["__X"]) + base0 = Y.__bases__[0] + self.assertIs(base0.__arg__(), ns["__X"]) + base1 = Y.__bases__[1] + self.assertIs(base1.__arg__()(), ns["__X"]) + base2 = Y.__bases__[2] + self.assertEqual(base2.__arg__, [ns["__X"]]) + base3 = Y.__bases__[3] + self.assertEqual(list(base3.__arg__), [ns["__X"]]) + + def test_type_params_are_mangled(self): + ns = run_code(""" + from test.test_type_params import make_base + + class Foo[__T, __U: __T](make_base(__T), make_base(lambda: __T)): + param = __T + """) + Foo = ns["Foo"] + T, U = Foo.__type_params__ + self.assertEqual(T.__name__, "__T") + self.assertEqual(U.__name__, "__U") + self.assertIs(U.__bound__, T) + self.assertIs(Foo.param, T) + + base1, base2, *_ = Foo.__bases__ + self.assertIs(base1.__arg__, T) + self.assertIs(base2.__arg__(), T) + class TypeParamsComplexCallsTest(unittest.TestCase): def test_defaults(self): |