[LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { _LOAD_FAST_CHECK, 0, 0 } } },
[LOAD_FAST_LOAD_FAST] = { .nuops = 2, .uops = { { _LOAD_FAST, 5, 0 }, { _LOAD_FAST, 6, 0 } } },
[LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_DEREF, 0, 0 } } },
- [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } },
[LOAD_GLOBAL] = { .nuops = 1, .uops = { { _LOAD_GLOBAL, 0, 0 } } },
[LOAD_GLOBAL_BUILTIN] = { .nuops = 3, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _GUARD_BUILTINS_VERSION, 1, 2 }, { _LOAD_GLOBAL_BUILTINS, 1, 3 } } },
[LOAD_GLOBAL_MODULE] = { .nuops = 2, .uops = { { _GUARD_GLOBALS_VERSION, 1, 1 }, { _LOAD_GLOBAL_MODULE, 1, 3 } } },
[_STORE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_DELETE_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_LOCALS] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
- [_LOAD_FROM_DICT_OR_GLOBALS] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_GLOBAL] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_GLOBALS_VERSION] = HAS_DEOPT_FLAG,
[_GUARD_BUILTINS_VERSION] = HAS_DEOPT_FLAG,
[_LOAD_FAST_CHECK] = "_LOAD_FAST_CHECK",
[_LOAD_FAST_LOAD_FAST] = "_LOAD_FAST_LOAD_FAST",
[_LOAD_FROM_DICT_OR_DEREF] = "_LOAD_FROM_DICT_OR_DEREF",
- [_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS",
[_LOAD_GLOBAL] = "_LOAD_GLOBAL",
[_LOAD_GLOBAL_BUILTINS] = "_LOAD_GLOBAL_BUILTINS",
[_LOAD_GLOBAL_MODULE] = "_LOAD_GLOBAL_MODULE",
return 0;
case _LOAD_LOCALS:
return 0;
- case _LOAD_FROM_DICT_OR_GLOBALS:
- return 1;
case _LOAD_GLOBAL:
return 0;
case _GUARD_GLOBALS_VERSION:
import pickle
+import textwrap
import types
import unittest
from test.support import check_syntax_error, run_code
with self.subTest(thing=thing, proto=proto):
with self.assertRaises(pickle.PickleError):
pickle.dumps(thing, protocol=proto)
+
+
+class TypeParamsExoticGlobalsTest(unittest.TestCase):
+ def test_exec_with_unusual_globals(self):
+ class customdict(dict):
+ def __missing__(self, key):
+ return key
+
+ code = compile("type Alias = undefined", "test", "exec")
+ ns = customdict()
+ exec(code, ns)
+ Alias = ns["Alias"]
+ self.assertEqual(Alias.__value__, "undefined")
+
+ code = compile("class A: type Alias = undefined", "test", "exec")
+ ns = customdict()
+ exec(code, ns)
+ Alias = ns["A"].Alias
+ self.assertEqual(Alias.__value__, "undefined")
--- /dev/null
+Fix execution of :ref:`annotation scopes <annotation-scopes>` within classes
+when ``globals`` is set to a non-dict. Patch by Jelle Zijlstra.
ERROR_NO_POP();
}
if (v == NULL) {
- if (PyDict_GetItemRef(GLOBALS(), name, &v) < 0) {
- ERROR_NO_POP();
- }
- if (v == NULL) {
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) {
+ if (PyDict_CheckExact(GLOBALS())
+ && PyDict_CheckExact(BUILTINS()))
+ {
+ v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
+ (PyDictObject *)BUILTINS(),
+ name);
+ if (v == NULL) {
+ if (!_PyErr_Occurred(tstate)) {
+ /* _PyDict_LoadGlobal() returns NULL without raising
+ * an exception if the key doesn't exist */
+ _PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
+ NAME_ERROR_MSG, name);
+ }
ERROR_NO_POP();
}
+ }
+ else {
+ /* Slow-path if globals or builtins is not a dict */
+ /* namespace 1: globals */
+ ERROR_IF(PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0, error);
if (v == NULL) {
- _PyEval_FormatExcCheckArg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- ERROR_NO_POP();
+ /* namespace 2: builtins */
+ ERROR_IF(PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0, error);
+ if (v == NULL) {
+ _PyEval_FormatExcCheckArg(
+ tstate, PyExc_NameError,
+ NAME_ERROR_MSG, name);
+ ERROR_IF(true, error);
+ }
}
}
}
break;
}
- case _LOAD_FROM_DICT_OR_GLOBALS: {
- PyObject *mod_or_class_dict;
- PyObject *v;
- oparg = CURRENT_OPARG();
- mod_or_class_dict = stack_pointer[-1];
- PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
- if (PyMapping_GetOptionalItem(mod_or_class_dict, name, &v) < 0) {
- JUMP_TO_ERROR();
- }
- if (v == NULL) {
- if (PyDict_GetItemRef(GLOBALS(), name, &v) < 0) {
- JUMP_TO_ERROR();
- }
- if (v == NULL) {
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) {
- JUMP_TO_ERROR();
- }
- if (v == NULL) {
- _PyEval_FormatExcCheckArg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- JUMP_TO_ERROR();
- }
- }
- }
- Py_DECREF(mod_or_class_dict);
- stack_pointer[-1] = v;
- break;
- }
+ /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 because it has both popping and not-popping errors */
/* _LOAD_NAME is not a viable micro-op for tier 2 because it has both popping and not-popping errors */
goto error;
}
if (v == NULL) {
- if (PyDict_GetItemRef(GLOBALS(), name, &v) < 0) {
- goto error;
- }
- if (v == NULL) {
- if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) {
+ if (PyDict_CheckExact(GLOBALS())
+ && PyDict_CheckExact(BUILTINS()))
+ {
+ v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
+ (PyDictObject *)BUILTINS(),
+ name);
+ if (v == NULL) {
+ if (!_PyErr_Occurred(tstate)) {
+ /* _PyDict_LoadGlobal() returns NULL without raising
+ * an exception if the key doesn't exist */
+ _PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
+ NAME_ERROR_MSG, name);
+ }
goto error;
}
+ }
+ else {
+ /* Slow-path if globals or builtins is not a dict */
+ /* namespace 1: globals */
+ if (PyMapping_GetOptionalItem(GLOBALS(), name, &v) < 0) goto pop_1_error;
if (v == NULL) {
- _PyEval_FormatExcCheckArg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- goto error;
+ /* namespace 2: builtins */
+ if (PyMapping_GetOptionalItem(BUILTINS(), name, &v) < 0) goto pop_1_error;
+ if (v == NULL) {
+ _PyEval_FormatExcCheckArg(
+ tstate, PyExc_NameError,
+ NAME_ERROR_MSG, name);
+ if (true) goto pop_1_error;
+ }
}
}
}
break;
}
- case _LOAD_FROM_DICT_OR_GLOBALS: {
- _Py_UopsSymbol *v;
- v = sym_new_not_null(ctx);
- stack_pointer[-1] = v;
- break;
- }
+ /* _LOAD_FROM_DICT_OR_GLOBALS is not a viable micro-op for tier 2 */
/* _LOAD_NAME is not a viable micro-op for tier 2 */