summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2024-05-28 18:03:33 (GMT)
committerGitHub <noreply@github.com>2024-05-28 18:03:33 (GMT)
commit6394a72e99b342d980297ec437ecafea92a044c4 (patch)
treedcf3ff8f0f88722a6318a28b56ad1496412f335b /Lib
parent2b46253c5fdf57fd35eb471ad0035e61afe924a6 (diff)
downloadcpython-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.py3
-rw-r--r--Lib/test/test_type_params.py94
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):