Skip to content

Commit b670214

Browse files
[3.12] gh-104879: Fix TypeAliasType.__module__ in exec() (GH-104881) (#104890)
(cherry picked from commit fe77a99) Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent 3d91d03 commit b670214

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

Lib/test/test_type_aliases.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,15 @@ def test_basic(self):
159159
self.assertEqual(TA.__type_params__, ())
160160
self.assertEqual(TA.__module__, __name__)
161161

162+
def test_attributes_with_exec(self):
163+
ns = {}
164+
exec("type TA = int", ns, ns)
165+
TA = ns["TA"]
166+
self.assertEqual(TA.__name__, "TA")
167+
self.assertIs(TA.__value__, int)
168+
self.assertEqual(TA.__type_params__, ())
169+
self.assertIs(TA.__module__, None)
170+
162171
def test_generic(self):
163172
T = TypeVar("T")
164173
TA = TypeAliasType("TA", list[T], type_params=(T,))

Lib/test/test_typing.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,20 @@ def test_basic_plain(self):
373373
self.assertIs(T.__covariant__, False)
374374
self.assertIs(T.__contravariant__, False)
375375
self.assertIs(T.__infer_variance__, False)
376+
self.assertEqual(T.__module__, __name__)
377+
378+
def test_basic_with_exec(self):
379+
ns = {}
380+
exec('from typing import TypeVar; T = TypeVar("T", bound=float)', ns, ns)
381+
T = ns['T']
382+
self.assertIsInstance(T, TypeVar)
383+
self.assertEqual(T.__name__, 'T')
384+
self.assertEqual(T.__constraints__, ())
385+
self.assertIs(T.__bound__, float)
386+
self.assertIs(T.__covariant__, False)
387+
self.assertIs(T.__contravariant__, False)
388+
self.assertIs(T.__infer_variance__, False)
389+
self.assertIs(T.__module__, None)
376390

377391
def test_attributes(self):
378392
T_bound = TypeVar('T_bound', bound=int)
@@ -939,6 +953,17 @@ def test_name(self):
939953
Ts2 = TypeVarTuple('Ts2')
940954
self.assertEqual(Ts2.__name__, 'Ts2')
941955

956+
def test_module(self):
957+
Ts = TypeVarTuple('Ts')
958+
self.assertEqual(Ts.__module__, __name__)
959+
960+
def test_exec(self):
961+
ns = {}
962+
exec('from typing import TypeVarTuple; Ts = TypeVarTuple("Ts")', ns)
963+
Ts = ns['Ts']
964+
self.assertEqual(Ts.__name__, 'Ts')
965+
self.assertIs(Ts.__module__, None)
966+
942967
def test_instance_is_equal_to_itself(self):
943968
Ts = TypeVarTuple('Ts')
944969
self.assertEqual(Ts, Ts)
@@ -8006,6 +8031,15 @@ def test_basic_plain(self):
80068031
self.assertEqual(P, P)
80078032
self.assertIsInstance(P, ParamSpec)
80088033
self.assertEqual(P.__name__, 'P')
8034+
self.assertEqual(P.__module__, __name__)
8035+
8036+
def test_basic_with_exec(self):
8037+
ns = {}
8038+
exec('from typing import ParamSpec; P = ParamSpec("P")', ns, ns)
8039+
P = ns['P']
8040+
self.assertIsInstance(P, ParamSpec)
8041+
self.assertEqual(P.__name__, 'P')
8042+
self.assertIs(P.__module__, None)
80098043

80108044
def test_valid_uses(self):
80118045
P = ParamSpec('P')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crash when accessing the ``__module__`` attribute of type aliases
2+
defined outside a module. Patch by Jelle Zijlstra.

Objects/typevarobject.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,8 +1319,13 @@ typealias_module(PyObject *self, void *unused)
13191319
return Py_NewRef(ta->module);
13201320
}
13211321
if (ta->compute_value != NULL) {
1322-
// PyFunction_GetModule() returns a borrowed reference
1323-
return Py_NewRef(PyFunction_GetModule(ta->compute_value));
1322+
PyObject* mod = PyFunction_GetModule(ta->compute_value);
1323+
if (mod != NULL) {
1324+
// PyFunction_GetModule() returns a borrowed reference,
1325+
// and it may return NULL (e.g., for functions defined
1326+
// in an exec()'ed block).
1327+
return Py_NewRef(mod);
1328+
}
13241329
}
13251330
Py_RETURN_NONE;
13261331
}

0 commit comments

Comments
 (0)