Commit 3a37d338 by Yannick Jadoul Committed by GitHub

Add __builtins__ to globals argument of `py::exec` and `py::eval` if not present (#2616)

* Add __builtins__ to globals argument of `py::exec` and `py::eval` if not present

* Refactor into inline ensure_builtins_in_globals function
parent ace4deb4
......@@ -14,6 +14,22 @@
#include "pybind11.h"
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)
inline void ensure_builtins_in_globals(object &global) {
#if PY_VERSION_HEX < 0x03080000
// Running exec and eval on Python 2 and 3 adds `builtins` module under
// `__builtins__` key to globals if not yet present.
// Python 3.8 made PyRun_String behave similarly. Let's also do that for
// older versions, for consistency.
if (!global.contains("__builtins__"))
global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
#else
(void) global;
#endif
}
PYBIND11_NAMESPACE_END(detail)
enum eval_mode {
/// Evaluate a string containing an isolated expression
......@@ -31,6 +47,8 @@ object eval(str expr, object global = globals(), object local = object()) {
if (!local)
local = global;
detail::ensure_builtins_in_globals(global);
/* PyRun_String does not accept a PyObject / encoding specifier,
this seems to be the only alternative */
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
......@@ -85,6 +103,8 @@ object eval_file(str fname, object global = globals(), object local = object())
if (!local)
local = global;
detail::ensure_builtins_in_globals(global);
int start;
switch (mode) {
case eval_expr: start = Py_eval_input; break;
......
......@@ -88,4 +88,12 @@ TEST_SUBMODULE(eval_, m) {
}
return false;
});
// test_eval_empty_globals
m.def("eval_empty_globals", [](py::object global) {
if (global.is_none())
global = py::dict();
auto int_class = py::eval("isinstance(42, int)", global);
return global;
});
}
......@@ -25,3 +25,11 @@ def test_eval_file():
assert m.test_eval_file(filename)
assert m.test_eval_file_failure()
def test_eval_empty_globals():
assert "__builtins__" in m.eval_empty_globals(None)
g = {}
assert "__builtins__" in m.eval_empty_globals(g)
assert "__builtins__" in g
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment