Skip to content

Commit 80a4e38

Browse files
gh-119821: Support non-dict globals in LOAD_FROM_DICT_OR_GLOBALS (#119822)
Support non-dict globals in LOAD_FROM_DICT_OR_GLOBALS 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.
1 parent 2237946 commit 80a4e38

File tree

8 files changed

+76
-58
lines changed

8 files changed

+76
-58
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 0 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,18 +1385,35 @@ dummy_func(
13851385
ERROR_NO_POP();
13861386
}
13871387
if (v == NULL) {
1388-
if (PyDict_GetItemRef(GLOBALS(), name, &v) < 0) {
1389-
ERROR_NO_POP();
1390-
}
1391-
if (v == NULL) {
1392-
if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) {
1388+
if (PyDict_CheckExact(GLOBALS())
1389+
&& PyDict_CheckExact(BUILTINS()))
1390+
{
1391+
v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
1392+
(PyDictObject *)BUILTINS(),
1393+
name);
1394+
if (v == NULL) {
1395+
if (!_PyErr_Occurred(tstate)) {
1396+
/* _PyDict_LoadGlobal() returns NULL without raising
1397+
* an exception if the key doesn't exist */
1398+
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
1399+
NAME_ERROR_MSG, name);
1400+
}
13931401
ERROR_NO_POP();
13941402
}
1403+
}
1404+
else {
1405+
/* Slow-path if globals or builtins is not a dict */
1406+
/* namespace 1: globals */
1407+
ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0, error);
13951408
if (v == NULL) {
1396-
_PyEval_FormatExcCheckArg(
1397-
tstate, PyExc_NameError,
1398-
NAME_ERROR_MSG, name);
1399-
ERROR_NO_POP();
1409+
/* namespace 2: builtins */
1410+
ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0, error);
1411+
if (v == NULL) {
1412+
_PyEval_FormatExcCheckArg(
1413+
tstate, PyExc_NameError,
1414+
NAME_ERROR_MSG, name);
1415+
ERROR_IF(true, error);
1416+
}
14001417
}
14011418
}
14021419
}

Python/executor_cases.c.h

Lines changed: 1 addition & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 26 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/optimizer_cases.c.h

Lines changed: 1 addition & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)