10000 [3.12] gh-119821: Support non-dict globals in LOAD_FROM_DICT_OR_GLOBA… · python/cpython@6d9677d · GitHub
[go: up one dir, main page]

Skip to content

Commit 6d9677d

Browse files
[3.12] gh-119821: Support non-dict globals in LOAD_FROM_DICT_OR_GLOBALS (#119822) (#119890)
The implementation basically copies LOAD_GLOBAL. Possibly it could be deduplicated, but that seems like it may get hairy since the two operations have different operands. This is important to fix in 3.14 for PEP 649, but it's a bug in earlier versions too, and we should backport to 3.13 and 3.12 if possible. (cherry picked from commit 80a4e38)
1 parent 2f7fada commit 6d9677d

File tree

4 files changed

+363
-329
lines changed

4 files changed

+363
-329
lines changed

Lib/test/test_type_aliases.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pickle
2+
import textwrap
23
import types
34
import unittest
45
from test.support import check_syntax_error, run_code
@@ -328,3 +329,22 @@ def test_pickling_local(self):
328329
with self.subTest(thing=thing, proto=proto):
329330
with self.assertRaises(pickle.PickleError):
330331
pickle.dumps(thing, protocol=proto)
332+
333+
334+
class TypeParamsExoticGlobalsTest(unittest.TestCase):
335+
def test_exec_with_unusual_globals(self):
336+
class customdict(dict):
337+
def __missing__(self, key):
338+
return key
339+
340+
code = compile("type Alias = undefined", "test", "exec")
341+
ns = customdict()
342+
exec(code, ns)
343+
Alias = ns["Alias"]
344+
self.assertEqual(Alias.__value__, "undefined")
345+
346+
code = compile("class A: type Alias = undefined", "test", "exec")
347+
ns = customdict()
348+
exec(code, ns)
349+
Alias = ns["A"].Alias
350+
self.assertEqual(Alias.__value__, "undefined")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix execution of :ref:`annotation scopes <annotation-scopes>` within classes
2+
when ``globals`` is set to a non-dict. Patch by Jelle Zijlstra.

Python/bytecodes.c

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,35 +1196,41 @@ dummy_func(
11961196
}
11971197
}
11981198
if (v == NULL) {
1199-
v = PyDict_GetItemWithError(GLOBALS(), name);
1200-
if (v != NULL) {
1199+
if (PyDict_CheckExact(GLOBALS())
1200+
&& PyDict_CheckExact(BUILTINS()))
1201+
{
1202+
v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
1203+
(PyDictObject *)BUILTINS(),
1204+
name);
1205+
if (v == NULL) {
1206+
if (!_PyErr_Occurred(tstate)) {
1207+
/* _PyDict_LoadGlobal() returns NULL without raising
1208+
* an exception if the key doesn't exist */
1209+
format_exc_check_arg(tstate, PyExc_NameError,
1210+
NAME_ERROR_MSG, name);
1211+
}
1212+
ERROR_IF(true, error);
1213+
}
12011214
Py_INCREF(v);
12021215
}
1203-
else if (_PyErr_Occurred(tstate)) {
1204-
goto error;
1205-
}
12061216
else {
1207-
if (PyDict_CheckExact(BUILTINS())) {
1208-
v = PyDict_GetItemWithError(BUILTINS(), name);
1209-
if (v == NULL) {
1210-
if (!_PyErr_Occurred(tstate)) {
1211-
format_exc_check_arg(
1212-
tstate, PyExc_NameError,
1213-
NAME_ERROR_MSG, name);
1214-
}
1215-
goto error;
1216-
}
1217-
Py_INCREF(v);
1218-
}
1219-
else {
1217+
/* Slow-path if globals or builtins is not a dict */
1218+
1219+
/* namespace 1: globals */
1220+
v = PyObject_GetItem(GLOBALS(), name);
1221+
if (v == NULL) {
1222+
ERROR_IF(!_PyErr_ExceptionMatches(tstate, PyExc_KeyError< 8000 /span>), error);
1223+
_PyErr_Clear(tstate);
1224+
1225+
/* namespace 2: builtins */
12201226
v = PyObject_GetItem(BUILTINS(), name);
12211227
if (v == NULL) {
12221228
if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
12231229
format_exc_check_arg(
12241230
tstate, PyExc_NameError,
12251231
NAME_ERROR_MSG, name);
12261232
}
1227-
goto error;
1233+
ERROR_IF(true, error);
12281234
}
12291235
}
12301236
}

0 commit comments

Comments
 (0)
0