mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55: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"
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user