Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
970e3d9
allow a mapping, rather than just a dict subclass, as globals
blhsing Jul 5, 2024
cf9945e
fixed typo
blhsing Jul 5, 2024
55f6dd4
regenerated header files
blhsing Jul 5, 2024
0d347f8
fixed error handling of DELETE_GLOBAL
blhsing Jul 5, 2024
4e1af59
fixed borrowed builtins reference
blhsing Jul 5, 2024
40f7c35
fixed error handling
blhsing Jul 5, 2024
698aa1f
use PyMapping_HasKeyStringWithError for proper error handling
blhsing Jul 5, 2024
fa1dcac
fixed usage of id __lltrace__
blhsing Jul 5, 2024
4343867
made _PyEval_BuiltinsFromGlobals return a new, non-borrowed reference
blhsing Jul 5, 2024
c5b38b0
release reference to builtins module
blhsing Jul 5, 2024
0daa66b
streamline code
blhsing Jul 5, 2024
2852b8f
added dict-specific path for insertion of __builtins__ into globals
blhsing Jul 5, 2024
5120260
try PyDict_* before PyMapping_*
blhsing Jul 5, 2024
723d665
switch from EAFP to LBYL
blhsing Jul 5, 2024
3908ee8
fixed typo
blhsing Jul 5, 2024
4a14682
dict-specific path for function
blhsing Jul 5, 2024
ab2974e
more dict-specific paths
blhsing Jul 5, 2024
1218ab7
minor adjustments
blhsing Jul 5, 2024
375af2b
📜🤖 Added by blurb_it.
blurb-it[bot] Jul 5, 2024
06b225b
removed redundant PyDict_Check; streamlined code
blhsing Jul 8, 2024
d584987
fixed check for null globals
blhsing Jul 8, 2024
3d3a563
updated docs
blhsing Jul 8, 2024
8bbc34c
minor update to docs
blhsing Jul 8, 2024
ca2ea12
updated tests
blhsing Jul 8, 2024
0f9e289
Update 2024-07-05-16-24-14.gh-issue-121306.nUBgho.rst
blhsing Jul 8, 2024
186ee55
Update 2024-07-05-16-24-14.gh-issue-121306.nUBgho.rst
blhsing Jul 8, 2024
190c09f
fixed reference count
blhsing Jul 8, 2024
09df171
Merge branch 'master' into allow-mapping-as-globals
blhsing Jul 8, 2024
1949be7
updated test to validate evaluated result
blhsing Jul 9, 2024
bb888ff
updated style
blhsing Jul 9, 2024
db01f51
regen headers
blhsing Jul 9, 2024
f0cd4e8
removed comments that are no longer applicable
blhsing Jul 9, 2024
d7d7d04
allow a mapping to be object.__dict__ and by extension module.__dict_…
blhsing Jul 11, 2024
cab9a52
simplified macros for unified dict/mapping API
blhsing Jul 11, 2024
f8c62c6
corrected comments
blhsing Jul 11, 2024
aa2d9b4
regen headers
blhsing Jul 11, 2024
362e0ac
fixed headers
blhsing Jul 11, 2024
bf7be59
simplified macro
blhsing Jul 11, 2024
0bf8239
fixed reference count
blhsing Jul 11, 2024
278c2ca
fixed typo in doc
blhsing Jul 11, 2024
d6735b9
fixed reference count
blhsing Jul 11, 2024
18dad2b
fixed possible uninitialized usage
blhsing Jul 11, 2024
35ada07
fixed logical operation
blhsing Jul 11, 2024
2e6a88a
updated tests
blhsing Jul 11, 2024
c29a10c
added test for mapping __dict__ for module; DRYer code with better ma…
blhsing Jul 12, 2024
3513a29
updated comment
blhsing Jul 12, 2024
97b813d
updated comment
blhsing Jul 12, 2024
6ea65b9
reformatted code; updated news
blhsing Jul 12, 2024
8137cab
reformatted code for clarity
blhsing Jul 12, 2024
725a327
fixed typo
blhsing Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Lib/test/test_capi/test_eval_code_ex.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def f():
self.assertEqual(eval_code_ex(code, dict(a=1)), 1)

self.assertRaises(NameError, eval_code_ex, code, {})
self.assertRaises(SystemError, eval_code_ex, code, UserDict(a=1))
self.assertRaises(SystemError, eval_code_ex, code, [])
self.assertRaises(SystemError, eval_code_ex, code, 1)
eval_code_ex(code, UserDict(a=1))
self.assertRaises(TypeError, eval_code_ex, code, [])
self.assertRaises(TypeError, eval_code_ex, code, 1)
# CRASHES eval_code_ex(code, NULL)
# CRASHES eval_code_ex(1, {})
# CRASHES eval_code_ex(NULL, {})
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_capi/test_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def run(s, *args):
self.assertRaises(SystemError, run, b'a\n', NULL)
self.assertRaises(SystemError, run, b'a\n', NULL, {})
self.assertRaises(SystemError, run, b'a\n', NULL, dict(a=1))
self.assertRaises(SystemError, run, b'a\n', UserDict())
self.assertRaises(SystemError, run, b'a\n', UserDict(), {})
self.assertRaises(SystemError, run, b'a\n', UserDict(), dict(a=1))
self.assertRaises(NameError, run, b'a\n', UserDict())
self.assertRaises(NameError, run, b'a\n', UserDict(), {})
run(b'a\n', UserDict(), dict(a=1))

# CRASHES run(NULL, {})

Expand Down Expand Up @@ -97,9 +97,9 @@ def run(*args):
self.assertRaises(SystemError, run, NULL)
self.assertRaises(SystemError, run, NULL, {})
self.assertRaises(SystemError, run, NULL, dict(a=1))
self.assertRaises(SystemError, run, UserDict())
self.assertRaises(SystemError, run, UserDict(), {})
self.assertRaises(SystemError, run, UserDict(), dict(a=1))
self.assertRaises(NameError, run, UserDict())
self.assertRaises(NameError, run, UserDict(), {})
run(UserDict(), dict(a=1))

@unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths')
@unittest.skipIf(os.name == 'nt', 'does not work on Windows')
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def keys(self):
self.assertEqual(m.results, ('z', g))
exec('z = locals()', g, m)
self.assertEqual(m.results, ('z', m))
self.assertRaises(TypeError, exec, 'z = b', m)
self.assertRaises(NameError, exec, 'z = b', m)

class A:
"Non-mapping"
Expand Down
17 changes: 9 additions & 8 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2105,17 +2105,18 @@ PyFrame_GetGenerator(PyFrameObject *frame)
PyObject*
_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals)
{
PyObject *builtins = PyDict_GetItemWithError(globals, &_Py_ID(__builtins__));
if (builtins) {
PyObject *builtins;
int has_builtins = PyMapping_GetOptionalItem(
globals, &_Py_ID(__builtins__), &builtins);
if (has_builtins < 0) {
return NULL;
}
if (has_builtins) {
if (PyModule_Check(builtins)) {
builtins = _PyModule_GetDict(builtins);
builtins = Py_XNewRef(_PyModule_GetDict(builtins));
assert(builtins != NULL);
}
return builtins;
}
if (PyErr_Occurred()) {
return NULL;
}

return _PyEval_GetBuiltins(tstate);
return Py_NewRef(_PyEval_GetBuiltins(tstate));
}
7 changes: 3 additions & 4 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr)
{
PyObject *module;
if (PyDict_GetItemRef(constr->fc_globals, &_Py_ID(__name__), &module) < 0) {
if (PyMapping_GetOptionalItemString(constr->fc_globals, "__name__", &module) < 0) {
return NULL;
}

Expand Down Expand Up @@ -174,15 +174,14 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
// __module__: Use globals['__name__'] if it exists, or NULL.
PyObject *module;
PyObject *builtins = NULL;
if (PyDict_GetItemRef(globals, &_Py_ID(__name__), &module) < 0) {
if (PyMapping_GetOptionalItemString(globals, "__name__", &module) < 0) {
goto error;
}

builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref
builtins = _PyEval_BuiltinsFromGlobals(tstate, globals);
if (builtins == NULL) {
goto error;
}
Py_INCREF(builtins);

PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type);
if (op == NULL) {
Expand Down
18 changes: 8 additions & 10 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -963,10 +963,8 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals,
PyErr_SetString(PyExc_TypeError, "locals must be a mapping");
return NULL;
}
if (globals != Py_None && !PyDict_Check(globals)) {
PyErr_SetString(PyExc_TypeError, PyMapping_Check(globals) ?
"globals must be a real dict; try eval(expr, {}, mapping)"
: "globals must be a dict");
if (globals != Py_None && !PyMapping_Check(globals)) {
PyErr_SetString(PyExc_TypeError, "globals must be a mapping");
return NULL;
}
if (globals == Py_None) {
Expand All @@ -993,9 +991,9 @@ builtin_eval_impl(PyObject *module, PyObject *source, PyObject *globals,
goto error;
}

int r = PyDict_Contains(globals, &_Py_ID(__builtins__));
int r = PyMapping_HasKeyStringWithError(globals, "__builtins__");
if (r == 0) {
r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins());
r = PyMapping_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
}
if (r < 0) {
goto error;
Expand Down Expand Up @@ -1084,8 +1082,8 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals,
Py_INCREF(locals);
}

if (!PyDict_Check(globals)) {
PyErr_Format(PyExc_TypeError, "exec() globals must be a dict, not %.100s",
if (!PyMapping_Check(globals)) {
PyErr_Format(PyExc_TypeError, "globals must be a mapping or None, not %.100s",
Py_TYPE(globals)->tp_name);
goto error;
}
Expand All @@ -1095,9 +1093,9 @@ builtin_exec_impl(PyObject *module, PyObject *source, PyObject *globals,
Py_TYPE(locals)->tp_name);
goto error;
}
int r = PyDict_Contains(globals, &_Py_ID(__builtins__));
int r = PyMapping_HasKeyStringWithError(globals, "__builtins__");
if (r == 0) {
r = PyDict_SetItem(globals, &_Py_ID(__builtins__), PyEval_GetBuiltins());
r = PyMapping_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
}
if (r < 0) {
goto error;
Expand Down
16 changes: 8 additions & 8 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1466,21 +1466,21 @@ dummy_func(

inst(STORE_GLOBAL, (v --)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyDict_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v));
int err = PyObject_SetItem(GLOBALS(), name, PyStackRef_AsPyObjectBorrow(v));
DECREF_INPUTS();
ERROR_IF(err, error);
}

inst(DELETE_GLOBAL, (--)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyDict_Pop(GLOBALS(), name, NULL);
int err = PyMapping_DelItem(GLOBALS(), name);
// Can't use ERROR_IF here.
if (err < 0) {
ERROR_NO_POP();
}
if (err == 0) {
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
if (_PyErr_Occurred(tstate) &&
_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
_PyEval_FormatExcCheckArg(tstate, PyExc_NameError,
NAME_ERROR_MSG, name);
}
ERROR_NO_POP();
}
}
Expand Down Expand Up @@ -1551,7 +1551,7 @@ dummy_func(
ERROR_NO_POP();
}
if (v_o == NULL) {
if (PyDict_GetItemRef(GLOBALS(), name, &v_o) < 0) {
if (PyMapping_GetOptionalItem(GLOBALS(), name, &v_o) < 0) {
ERROR_NO_POP();
}
if (v_o == NULL) {
Expand Down
4 changes: 3 additions & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, _PyInterpreterFrame *skip
if (frame == skip_frame) {
return 0;
}
int r = PyDict_Contains(globals, &_Py_ID(__lltrace__));
int r = PyMapping_HasKeyWithError(globals, &_Py_ID(__lltrace__));
if (r < 0) {
return -1;
}
Expand Down Expand Up @@ -623,6 +623,7 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
EVAL_CALL_STAT_INC(EVAL_CALL_LEGACY);
PyObject *res = _PyEval_Vector(tstate, func, locals, NULL, 0, NULL);
Py_DECREF(func);
Py_DECREF(builtins);
return res;
}

Expand Down Expand Up @@ -1946,6 +1947,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
Py_XDECREF(kwnames);
PyMem_Free(newargs);
Py_DECREF(defaults);
Py_DECREF(builtins);
return res;
}

Expand Down
14 changes: 7 additions & 7 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Python/pythonrun.c
Original file line number Diff line number Diff line change
Expand Up @@ -1273,16 +1273,16 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py
_PyRuntime.signals.unhandled_keyboard_interrupt = 0;

/* Set globals['__builtins__'] if it doesn't exist */
if (!globals || !PyDict_Check(globals)) {
PyErr_SetString(PyExc_SystemError, "globals must be a real dict");
if (!globals || !PyMapping_Check(globals)) {
PyErr_SetString(PyExc_SystemError, "globals must be a mapping");
return NULL;
}
int has_builtins = PyDict_ContainsString(globals, "__builtins__");
int has_builtins = PyMapping_HasKeyStringWithError(globals, "__builtins__");
if (has_builtins < 0) {
return NULL;
}
if (!has_builtins) {
if (PyDict_SetItemString(globals, "__builtins__",
if (PyMapping_SetItemString(globals, "__builtins__",
tstate->interp->builtins) < 0)
{
return NULL;
Expand Down