File indexing completed on 2025-02-16 05:12:16

0001 /*
0002     pybind11/eval.h: Support for evaluating Python expressions and statements
0003     from strings and files
0004 
0005     Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
0006                        Wenzel Jakob <wenzel.jakob@epfl.ch>
0007 
0008     All rights reserved. Use of this source code is governed by a
0009     BSD-style license that can be found in the LICENSE file.
0010 */
0011 
0012 #pragma once
0013 
0014 #include <utility>
0015 
0016 #include "pybind11.h"
0017 
0018 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0019 PYBIND11_NAMESPACE_BEGIN(detail)
0020 
0021 inline void ensure_builtins_in_globals(object &global) {
0022     #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
0023         // Running exec and eval on Python 2 and 3 adds `builtins` module under
0024         // `__builtins__` key to globals if not yet present.
0025         // Python 3.8 made PyRun_String behave similarly. Let's also do that for
0026         // older versions, for consistency. This was missing from PyPy3.8 7.3.7.
0027         if (!global.contains("__builtins__"))
0028             global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
0029     #else
0030         (void) global;
0031     #endif
0032 }
0033 
0034 PYBIND11_NAMESPACE_END(detail)
0035 
0036 enum eval_mode {
0037     /// Evaluate a string containing an isolated expression
0038     eval_expr,
0039 
0040     /// Evaluate a string containing a single statement. Returns \c none
0041     eval_single_statement,
0042 
0043     /// Evaluate a string containing a sequence of statement. Returns \c none
0044     eval_statements
0045 };
0046 
0047 template <eval_mode mode = eval_expr>
0048 object eval(const str &expr, object global = globals(), object local = object()) {
0049     if (!local)
0050         local = global;
0051 
0052     detail::ensure_builtins_in_globals(global);
0053 
0054     /* PyRun_String does not accept a PyObject / encoding specifier,
0055        this seems to be the only alternative */
0056     std::string buffer = "# -*- coding: utf-8 -*-\n" + (std::string) expr;
0057 
0058     int start = 0;
0059     switch (mode) {
0060         case eval_expr:             start = Py_eval_input;   break;
0061         case eval_single_statement: start = Py_single_input; break;
0062         case eval_statements:       start = Py_file_input;   break;
0063         default: pybind11_fail("invalid evaluation mode");
0064     }
0065 
0066     PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
0067     if (!result)
0068         throw error_already_set();
0069     return reinterpret_steal<object>(result);
0070 }
0071 
0072 template <eval_mode mode = eval_expr, size_t N>
0073 object eval(const char (&s)[N], object global = globals(), object local = object()) {
0074     /* Support raw string literals by removing common leading whitespace */
0075     auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s))
0076                                : str(s);
0077     return eval<mode>(expr, global, local);
0078 }
0079 
0080 inline void exec(const str &expr, object global = globals(), object local = object()) {
0081     eval<eval_statements>(expr, std::move(global), std::move(local));
0082 }
0083 
0084 template <size_t N>
0085 void exec(const char (&s)[N], object global = globals(), object local = object()) {
0086     eval<eval_statements>(s, global, local);
0087 }
0088 
0089 #if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
0090 template <eval_mode mode = eval_statements>
0091 object eval_file(str, object, object) {
0092     pybind11_fail("eval_file not supported in PyPy3. Use eval");
0093 }
0094 template <eval_mode mode = eval_statements>
0095 object eval_file(str, object) {
0096     pybind11_fail("eval_file not supported in PyPy3. Use eval");
0097 }
0098 template <eval_mode mode = eval_statements>
0099 object eval_file(str) {
0100     pybind11_fail("eval_file not supported in PyPy3. Use eval");
0101 }
0102 #else
0103 template <eval_mode mode = eval_statements>
0104 object eval_file(str fname, object global = globals(), object local = object()) {
0105     if (!local)
0106         local = global;
0107 
0108     detail::ensure_builtins_in_globals(global);
0109 
0110     int start = 0;
0111     switch (mode) {
0112         case eval_expr:             start = Py_eval_input;   break;
0113         case eval_single_statement: start = Py_single_input; break;
0114         case eval_statements:       start = Py_file_input;   break;
0115         default: pybind11_fail("invalid evaluation mode");
0116     }
0117 
0118     int closeFile = 1;
0119     std::string fname_str = (std::string) fname;
0120 #if PY_VERSION_HEX >= 0x03040000
0121     FILE *f = _Py_fopen_obj(fname.ptr(), "r");
0122 #elif PY_VERSION_HEX >= 0x03000000
0123     FILE *f = _Py_fopen(fname.ptr(), "r");
0124 #else
0125     /* No unicode support in open() :( */
0126     auto fobj = reinterpret_steal<object>(PyFile_FromString(
0127         const_cast<char *>(fname_str.c_str()),
0128         const_cast<char*>("r")));
0129     FILE *f = nullptr;
0130     if (fobj)
0131         f = PyFile_AsFile(fobj.ptr());
0132     closeFile = 0;
0133 #endif
0134     if (!f) {
0135         PyErr_Clear();
0136         pybind11_fail("File \"" + fname_str + "\" could not be opened!");
0137     }
0138 
0139     // In Python2, this should be encoded by getfilesystemencoding.
0140     // We don't boher setting it since Python2 is past EOL anyway.
0141     // See PR#3233
0142 #if PY_VERSION_HEX >= 0x03000000
0143     if (!global.contains("__file__")) {
0144         global["__file__"] = std::move(fname);
0145     }
0146 #endif
0147 
0148 #if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
0149     PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
0150                                   local.ptr());
0151     (void) closeFile;
0152 #else
0153     PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
0154                                     local.ptr(), closeFile);
0155 #endif
0156 
0157     if (!result)
0158         throw error_already_set();
0159     return reinterpret_steal<object>(result);
0160 }
0161 #endif
0162 
0163 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)