eval.h 5.4 KB
Newer Older
1
/*
NaDDu's avatar
NaDDu committed
2
    pybind11/eval.h: Support for evaluating Python expressions and statements
3
4
5
6
7
8
9
10
11
12
13
    from strings and files

    Copyright (c) 2016 Klemens Morgenstern <klemens.morgenstern@ed-chemnitz.de> and
                       Wenzel Jakob <wenzel.jakob@epfl.ch>

    All rights reserved. Use of this source code is governed by a
    BSD-style license that can be found in the LICENSE file.
*/

#pragma once

14
15
#include <utility>

Wenzel Jakob's avatar
Wenzel Jakob committed
16
#include "pybind11.h"
17

18
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
19
20
21
PYBIND11_NAMESPACE_BEGIN(detail)

inline void ensure_builtins_in_globals(object &global) {
22
    #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x03080000
23
24
25
        // 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
26
        // older versions, for consistency. This was missing from PyPy3.8 7.3.7.
27
28
29
30
31
32
33
34
        if (!global.contains("__builtins__"))
            global["__builtins__"] = module_::import(PYBIND11_BUILTINS_MODULE);
    #else
        (void) global;
    #endif
}

PYBIND11_NAMESPACE_END(detail)
35
36
37
38
39
40
41
42
43
44
45
46
47

enum eval_mode {
    /// Evaluate a string containing an isolated expression
    eval_expr,

    /// Evaluate a string containing a single statement. Returns \c none
    eval_single_statement,

    /// Evaluate a string containing a sequence of statement. Returns \c none
    eval_statements
};

template <eval_mode mode = eval_expr>
48
object eval(const str &expr, object global = globals(), object local = object()) {
49
    if (!local) {
50
        local = global;
51
    }
52

53
54
    detail::ensure_builtins_in_globals(global);

Wenzel Jakob's avatar
Wenzel Jakob committed
55
56
57
58
    /* 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;

59
    int start = 0;
60
61
62
63
64
65
66
    switch (mode) {
        case eval_expr:             start = Py_eval_input;   break;
        case eval_single_statement: start = Py_single_input; break;
        case eval_statements:       start = Py_file_input;   break;
        default: pybind11_fail("invalid evaluation mode");
    }

67
    PyObject *result = PyRun_String(buffer.c_str(), start, global.ptr(), local.ptr());
68
    if (!result) {
69
        throw error_already_set();
70
    }
71
    return reinterpret_steal<object>(result);
72
73
}

74
template <eval_mode mode = eval_expr, size_t N>
75
object eval(const char (&s)[N], object global = globals(), object local = object()) {
76
    /* Support raw string literals by removing common leading whitespace */
77
    auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s))
78
79
80
81
                               : str(s);
    return eval<mode>(expr, global, local);
}

82
83
inline void exec(const str &expr, object global = globals(), object local = object()) {
    eval<eval_statements>(expr, std::move(global), std::move(local));
84
85
86
}

template <size_t N>
87
void exec(const char (&s)[N], object global = globals(), object local = object()) {
88
89
90
    eval<eval_statements>(s, global, local);
}

91
#if defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03000000
Isuru Fernando's avatar
Isuru Fernando committed
92
93
94
95
96
97
98
99
100
101
102
103
104
template <eval_mode mode = eval_statements>
object eval_file(str, object, object) {
    pybind11_fail("eval_file not supported in PyPy3. Use eval");
}
template <eval_mode mode = eval_statements>
object eval_file(str, object) {
    pybind11_fail("eval_file not supported in PyPy3. Use eval");
}
template <eval_mode mode = eval_statements>
object eval_file(str) {
    pybind11_fail("eval_file not supported in PyPy3. Use eval");
}
#else
105
template <eval_mode mode = eval_statements>
106
object eval_file(str fname, object global = globals(), object local = object()) {
107
    if (!local) {
108
        local = global;
109
    }
110

111
112
    detail::ensure_builtins_in_globals(global);

113
    int start = 0;
114
115
116
117
118
119
120
    switch (mode) {
        case eval_expr:             start = Py_eval_input;   break;
        case eval_single_statement: start = Py_single_input; break;
        case eval_statements:       start = Py_file_input;   break;
        default: pybind11_fail("invalid evaluation mode");
    }

Wenzel Jakob's avatar
Wenzel Jakob committed
121
122
123
124
125
126
127
128
    int closeFile = 1;
    std::string fname_str = (std::string) fname;
#if PY_VERSION_HEX >= 0x03040000
    FILE *f = _Py_fopen_obj(fname.ptr(), "r");
#elif PY_VERSION_HEX >= 0x03000000
    FILE *f = _Py_fopen(fname.ptr(), "r");
#else
    /* No unicode support in open() :( */
129
    auto fobj = reinterpret_steal<object>(PyFile_FromString(
Wenzel Jakob's avatar
Wenzel Jakob committed
130
        const_cast<char *>(fname_str.c_str()),
131
        const_cast<char*>("r")));
Wenzel Jakob's avatar
Wenzel Jakob committed
132
133
134
135
136
137
138
139
140
    FILE *f = nullptr;
    if (fobj)
        f = PyFile_AsFile(fobj.ptr());
    closeFile = 0;
#endif
    if (!f) {
        PyErr_Clear();
        pybind11_fail("File \"" + fname_str + "\" could not be opened!");
    }
141

142
143
144
145
146
147
148
149
150
    // In Python2, this should be encoded by getfilesystemencoding.
    // We don't boher setting it since Python2 is past EOL anyway.
    // See PR#3233
#if PY_VERSION_HEX >= 0x03000000
    if (!global.contains("__file__")) {
        global["__file__"] = std::move(fname);
    }
#endif

Wenzel Jakob's avatar
Wenzel Jakob committed
151
152
153
154
155
#if PY_VERSION_HEX < 0x03000000 && defined(PYPY_VERSION)
    PyObject *result = PyRun_File(f, fname_str.c_str(), start, global.ptr(),
                                  local.ptr());
    (void) closeFile;
#else
156
157
    PyObject *result = PyRun_FileEx(f, fname_str.c_str(), start, global.ptr(),
                                    local.ptr(), closeFile);
Wenzel Jakob's avatar
Wenzel Jakob committed
158
159
#endif

160
    if (!result) {
161
        throw error_already_set();
162
    }
163
    return reinterpret_steal<object>(result);
164
}
Isuru Fernando's avatar
Isuru Fernando committed
165
#endif
166

167
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)