mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
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
This commit is contained in:
parent
ace4deb4f0
commit
3a37d33830
@ -14,6 +14,22 @@
|
|||||||
#include "pybind11.h"
|
#include "pybind11.h"
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
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 {
|
enum eval_mode {
|
||||||
/// Evaluate a string containing an isolated expression
|
/// Evaluate a string containing an isolated expression
|
||||||
@ -31,6 +47,8 @@ object eval(str expr, object global = globals(), object local = object()) {
|
|||||||
if (!local)
|
if (!local)
|
||||||
local = global;
|
local = global;
|
||||||
|
|
||||||
|
detail::ensure_builtins_in_globals(global);
|
||||||
|
|
||||||
/* PyRun_String does not accept a PyObject / encoding specifier,
|
/* PyRun_String does not accept a PyObject / encoding specifier,
|
||||||
this seems to be the only alternative */
|
this seems to be the only alternative */
|
||||||
std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
|
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)
|
if (!local)
|
||||||
local = global;
|
local = global;
|
||||||
|
|
||||||
|
detail::ensure_builtins_in_globals(global);
|
||||||
|
|
||||||
int start;
|
int start;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case eval_expr: start = Py_eval_input; break;
|
case eval_expr: start = Py_eval_input; break;
|
||||||
|
@ -88,4 +88,12 @@ TEST_SUBMODULE(eval_, m) {
|
|||||||
}
|
}
|
||||||
return false;
|
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(filename)
|
||||||
|
|
||||||
assert m.test_eval_file_failure()
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user