Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2020-08-17 10:46:06 +0300
committerCampbell Barton <ideasman42@gmail.com>2020-08-17 11:32:20 +0300
commit7341ceb674b2fc5c01d4328f398516ef8f358ae5 (patch)
treef755074228baf162cf3d7cc5fcdf8d1ae3193e18 /source/blender/python
parent397cec6a4dad6784604622ee707bb74a2e6a92a1 (diff)
Cleanup: move Python script execution into BPY_extern_run.h
This commit renames 'execute' to 'run' because: - This follows Python's "PyRun" which these functions wrap. - Execution functions can use either exec/eval modes, making naming awkward (for future API refactoring).
Diffstat (limited to 'source/blender/python')
-rw-r--r--source/blender/python/BPY_extern.h34
-rw-r--r--source/blender/python/BPY_extern_run.h68
-rw-r--r--source/blender/python/intern/CMakeLists.txt1
-rw-r--r--source/blender/python/intern/bpy_interface.c332
-rw-r--r--source/blender/python/intern/bpy_interface_run.c391
5 files changed, 462 insertions, 364 deletions
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index 3fc4df270d5..e1e0d01055a 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -67,40 +67,6 @@ void BPY_thread_restore(BPy_ThreadStatePtr tstate);
} \
(void)0
-bool BPY_execute_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
-bool BPY_execute_text(struct bContext *C,
- struct Text *text,
- struct ReportList *reports,
- const bool do_jump);
-
-bool BPY_execute_string_as_number(struct bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- double *r_value);
-bool BPY_execute_string_as_intptr(struct bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- intptr_t *r_value);
-bool BPY_execute_string_as_string_and_size(struct bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- char **r_value,
- size_t *r_value_size);
-bool BPY_execute_string_as_string(struct bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- char **r_value);
-
-bool BPY_execute_string_ex(struct bContext *C,
- const char *imports[],
- const char *expr,
- bool use_eval);
-bool BPY_execute_string(struct bContext *C, const char *imports[], const char *expr);
-
void BPY_text_free_code(struct Text *text);
void BPY_modules_update(
struct bContext *C); // XXX - annoying, need this for pointers that get out of date
diff --git a/source/blender/python/BPY_extern_run.h b/source/blender/python/BPY_extern_run.h
new file mode 100644
index 00000000000..67ac56f2798
--- /dev/null
+++ b/source/blender/python/BPY_extern_run.h
@@ -0,0 +1,68 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup python
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "BLI_sys_types.h"
+
+struct ReportList;
+struct Text;
+struct bContext;
+
+/* bpy_interface_run.c */
+bool BPY_run_filepath(struct bContext *C, const char *filepath, struct ReportList *reports);
+bool BPY_run_text(struct bContext *C,
+ struct Text *text,
+ struct ReportList *reports,
+ const bool do_jump);
+
+bool BPY_run_string_as_number(struct bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ double *r_value);
+bool BPY_run_string_as_intptr(struct bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ intptr_t *r_value);
+bool BPY_run_string_as_string_and_size(struct bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ char **r_value,
+ size_t *r_value_size);
+bool BPY_run_string_as_string(struct bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ char **r_value);
+
+bool BPY_run_string_ex(struct bContext *C, const char *imports[], const char *expr, bool use_eval);
+
+bool BPY_run_string(struct bContext *C, const char *imports[], const char *expr);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 769618005af..44949c478cc 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
bpy_gizmo_wrap.c
bpy_interface.c
bpy_interface_atexit.c
+ bpy_interface_run.c
bpy_intern_string.c
bpy_library_load.c
bpy_library_write.c
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 81e1905bed7..3941d25e9f7 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -64,6 +64,7 @@
#include "BPY_extern.h"
#include "BPY_extern_python.h"
+#include "BPY_extern_run.h"
#include "../generic/py_capi_utils.h"
@@ -428,18 +429,6 @@ void BPY_python_use_system_env(void)
py_use_system_env = true;
}
-static void python_script_error_jump_text(struct Text *text)
-{
- int lineno;
- int offset;
- python_script_error_jump(text->id.name + 2, &lineno, &offset);
- if (lineno != -1) {
- /* select the line with the error */
- txt_move_to(text, lineno - 1, INT_MAX, false);
- txt_move_to(text, lineno - 1, offset, true);
- }
-}
-
void BPY_python_backtrace(FILE *fp)
{
fputs("\n# Python backtrace\n", fp);
@@ -467,152 +456,6 @@ typedef struct {
} PyModuleObject;
#endif
-/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
-static void bpy_text_filename_get(char *fn, const Main *bmain, size_t fn_len, const Text *text)
-{
- BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(bmain, &text->id), SEP, text->id.name + 2);
-}
-
-static bool python_script_exec(
- bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
-{
- Main *bmain_old = CTX_data_main(C);
- PyObject *main_mod = NULL;
- PyObject *py_dict = NULL, *py_result = NULL;
- PyGILState_STATE gilstate;
-
- BLI_assert(fn || text);
-
- if (fn == NULL && text == NULL) {
- return 0;
- }
-
- bpy_context_set(C, &gilstate);
-
- PyC_MainModule_Backup(&main_mod);
-
- if (text) {
- char fn_dummy[FILE_MAXDIR];
- bpy_text_filename_get(fn_dummy, bmain_old, sizeof(fn_dummy), text);
-
- if (text->compiled == NULL) { /* if it wasn't already compiled, do it now */
- char *buf;
- PyObject *fn_dummy_py;
-
- fn_dummy_py = PyC_UnicodeFromByte(fn_dummy);
-
- buf = txt_to_buf(text, NULL);
- text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1);
- MEM_freeN(buf);
-
- Py_DECREF(fn_dummy_py);
-
- if (PyErr_Occurred()) {
- if (do_jump) {
- python_script_error_jump_text(text);
- }
- BPY_text_free_code(text);
- }
- }
-
- if (text->compiled) {
- py_dict = PyC_DefaultNameSpace(fn_dummy);
- py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict);
- }
- }
- else {
- FILE *fp = BLI_fopen(fn, "r");
-
- if (fp) {
- py_dict = PyC_DefaultNameSpace(fn);
-
-#ifdef _WIN32
- /* Previously we used PyRun_File to run directly the code on a FILE
- * object, but as written in the Python/C API Ref Manual, chapter 2,
- * 'FILE structs for different C libraries can be different and
- * incompatible'.
- * So now we load the script file data to a buffer.
- *
- * Note on use of 'globals()', it's important not copy the dictionary because
- * tools may inspect 'sys.modules["__main__"]' for variables defined in the code
- * where using a copy of 'globals()' causes code execution
- * to leave the main namespace untouched. see: T51444
- *
- * This leaves us with the problem of variables being included,
- * currently this is worked around using 'dict.__del__' it's ugly but works.
- */
- {
- const char *pystring =
- "with open(__file__, 'rb') as f:"
- "exec(compile(f.read(), __file__, 'exec'), globals().__delitem__('f') or globals())";
-
- fclose(fp);
-
- py_result = PyRun_String(pystring, Py_file_input, py_dict, py_dict);
- }
-#else
- py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
- fclose(fp);
-#endif
- }
- else {
- PyErr_Format(
- PyExc_IOError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
- py_result = NULL;
- }
- }
-
- if (!py_result) {
- if (text) {
- if (do_jump) {
- /* ensure text is valid before use, the script may have freed its self */
- Main *bmain_new = CTX_data_main(C);
- if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->texts, text) != -1)) {
- python_script_error_jump_text(text);
- }
- }
- }
- BPy_errors_to_report(reports);
- }
- else {
- Py_DECREF(py_result);
- }
-
- if (py_dict) {
-#ifdef PYMODULE_CLEAR_WORKAROUND
- PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem(PyImport_GetModuleDict(),
- bpy_intern_str___main__);
- PyObject *dict_back = mmod->md_dict;
- /* freeing the module will clear the namespace,
- * gives problems running classes defined in this namespace being used later. */
- mmod->md_dict = NULL;
- Py_DECREF(dict_back);
-#endif
-
-#undef PYMODULE_CLEAR_WORKAROUND
- }
-
- PyC_MainModule_Restore(main_mod);
-
- bpy_context_clear(C, &gilstate);
-
- return (py_result != NULL);
-}
-
-/* Can run a file or text block */
-bool BPY_execute_filepath(bContext *C, const char *filepath, struct ReportList *reports)
-{
- return python_script_exec(C, filepath, NULL, reports, false);
-}
-
-bool BPY_execute_text(bContext *C,
- struct Text *text,
- struct ReportList *reports,
- const bool do_jump)
-{
- return python_script_exec(C, NULL, text, reports, do_jump);
-}
-
void BPY_DECREF(void *pyob_ptr)
{
PyGILState_STATE gilstate = PyGILState_Ensure();
@@ -631,177 +474,6 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
PyGILState_Release(gilstate);
}
-/**
- * \return success
- */
-bool BPY_execute_string_as_number(bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- double *r_value)
-{
- PyGILState_STATE gilstate;
- bool ok = true;
-
- if (!r_value || !expr) {
- return -1;
- }
-
- if (expr[0] == '\0') {
- *r_value = 0.0;
- return ok;
- }
-
- bpy_context_set(C, &gilstate);
-
- ok = PyC_RunString_AsNumber(imports, expr, "<expr as number>", r_value);
-
- if (ok == false) {
- if (report_prefix != NULL) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
- }
- else {
- PyErr_Clear();
- }
- }
-
- bpy_context_clear(C, &gilstate);
-
- return ok;
-}
-
-/**
- * \return success
- */
-bool BPY_execute_string_as_string_and_size(bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- char **r_value,
- size_t *r_value_size)
-{
- BLI_assert(r_value && expr);
- PyGILState_STATE gilstate;
- bool ok = true;
-
- if (expr[0] == '\0') {
- *r_value = NULL;
- return ok;
- }
-
- bpy_context_set(C, &gilstate);
-
- ok = PyC_RunString_AsStringAndSize(imports, expr, "<expr as str>", r_value, r_value_size);
-
- if (ok == false) {
- if (report_prefix != NULL) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), false, false, report_prefix);
- }
- else {
- PyErr_Clear();
- }
- }
-
- bpy_context_clear(C, &gilstate);
-
- return ok;
-}
-
-bool BPY_execute_string_as_string(bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- char **r_value)
-{
- size_t value_dummy_size;
- return BPY_execute_string_as_string_and_size(
- C, imports, expr, report_prefix, r_value, &value_dummy_size);
-}
-
-/**
- * Support both int and pointers.
- *
- * \return success
- */
-bool BPY_execute_string_as_intptr(bContext *C,
- const char *imports[],
- const char *expr,
- const char *report_prefix,
- intptr_t *r_value)
-{
- BLI_assert(r_value && expr);
- PyGILState_STATE gilstate;
- bool ok = true;
-
- if (expr[0] == '\0') {
- *r_value = 0;
- return ok;
- }
-
- bpy_context_set(C, &gilstate);
-
- ok = PyC_RunString_AsIntPtr(imports, expr, "<expr as intptr>", r_value);
-
- if (ok == false) {
- if (report_prefix != NULL) {
- BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
- }
- else {
- PyErr_Clear();
- }
- }
-
- bpy_context_clear(C, &gilstate);
-
- return ok;
-}
-
-bool BPY_execute_string_ex(bContext *C, const char *imports[], const char *expr, bool use_eval)
-{
- BLI_assert(expr);
- PyGILState_STATE gilstate;
- PyObject *main_mod = NULL;
- PyObject *py_dict, *retval;
- bool ok = true;
-
- if (expr[0] == '\0') {
- return ok;
- }
-
- bpy_context_set(C, &gilstate);
-
- PyC_MainModule_Backup(&main_mod);
-
- py_dict = PyC_DefaultNameSpace("<blender string>");
-
- if (imports && (!PyC_NameSpace_ImportArray(py_dict, imports))) {
- Py_DECREF(py_dict);
- retval = NULL;
- }
- else {
- retval = PyRun_String(expr, use_eval ? Py_eval_input : Py_file_input, py_dict, py_dict);
- }
-
- if (retval == NULL) {
- ok = false;
- BPy_errors_to_report(CTX_wm_reports(C));
- }
- else {
- Py_DECREF(retval);
- }
-
- PyC_MainModule_Restore(main_mod);
-
- bpy_context_clear(C, &gilstate);
-
- return ok;
-}
-
-bool BPY_execute_string(bContext *C, const char *imports[], const char *expr)
-{
- return BPY_execute_string_ex(C, imports, expr, true);
-}
-
void BPY_modules_load_user(bContext *C)
{
PyGILState_STATE gilstate;
@@ -834,7 +506,7 @@ void BPY_modules_load_user(bContext *C)
}
}
else {
- BPY_execute_text(C, text, NULL, false);
+ BPY_run_text(C, text, NULL, false);
/* Check if the script loaded a new file. */
if (bmain != CTX_data_main(C)) {
diff --git a/source/blender/python/intern/bpy_interface_run.c b/source/blender/python/intern/bpy_interface_run.c
new file mode 100644
index 00000000000..f936be2edbf
--- /dev/null
+++ b/source/blender/python/intern/bpy_interface_run.c
@@ -0,0 +1,391 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#include <stdio.h>
+
+#include <Python.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_fileops.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_text.h"
+
+#include "DNA_text_types.h"
+
+#include "BPY_extern.h"
+#include "BPY_extern_run.h"
+
+#include "bpy_capi_utils.h"
+#include "bpy_traceback.h"
+
+#include "../generic/py_capi_utils.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Private Utilities
+ * \{ */
+
+static void python_script_error_jump_text(Text *text)
+{
+ int lineno;
+ int offset;
+ python_script_error_jump(text->id.name + 2, &lineno, &offset);
+ if (lineno != -1) {
+ /* select the line with the error */
+ txt_move_to(text, lineno - 1, INT_MAX, false);
+ txt_move_to(text, lineno - 1, offset, true);
+ }
+}
+
+/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
+static void bpy_text_filename_get(char *fn, const Main *bmain, size_t fn_len, const Text *text)
+{
+ BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(bmain, &text->id), SEP, text->id.name + 2);
+}
+
+static bool python_script_exec(
+ bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
+{
+ Main *bmain_old = CTX_data_main(C);
+ PyObject *main_mod = NULL;
+ PyObject *py_dict = NULL, *py_result = NULL;
+ PyGILState_STATE gilstate;
+
+ BLI_assert(fn || text);
+
+ if (fn == NULL && text == NULL) {
+ return 0;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ PyC_MainModule_Backup(&main_mod);
+
+ if (text) {
+ char fn_dummy[FILE_MAXDIR];
+ bpy_text_filename_get(fn_dummy, bmain_old, sizeof(fn_dummy), text);
+
+ if (text->compiled == NULL) { /* if it wasn't already compiled, do it now */
+ char *buf;
+ PyObject *fn_dummy_py;
+
+ fn_dummy_py = PyC_UnicodeFromByte(fn_dummy);
+
+ buf = txt_to_buf(text, NULL);
+ text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1);
+ MEM_freeN(buf);
+
+ Py_DECREF(fn_dummy_py);
+
+ if (PyErr_Occurred()) {
+ if (do_jump) {
+ python_script_error_jump_text(text);
+ }
+ BPY_text_free_code(text);
+ }
+ }
+
+ if (text->compiled) {
+ py_dict = PyC_DefaultNameSpace(fn_dummy);
+ py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict);
+ }
+ }
+ else {
+ FILE *fp = BLI_fopen(fn, "r");
+
+ if (fp) {
+ py_dict = PyC_DefaultNameSpace(fn);
+
+#ifdef _WIN32
+ /* Previously we used PyRun_File to run directly the code on a FILE
+ * object, but as written in the Python/C API Ref Manual, chapter 2,
+ * 'FILE structs for different C libraries can be different and
+ * incompatible'.
+ * So now we load the script file data to a buffer.
+ *
+ * Note on use of 'globals()', it's important not copy the dictionary because
+ * tools may inspect 'sys.modules["__main__"]' for variables defined in the code
+ * where using a copy of 'globals()' causes code execution
+ * to leave the main namespace untouched. see: T51444
+ *
+ * This leaves us with the problem of variables being included,
+ * currently this is worked around using 'dict.__del__' it's ugly but works.
+ */
+ {
+ const char *pystring =
+ "with open(__file__, 'rb') as f:"
+ "exec(compile(f.read(), __file__, 'exec'), globals().__delitem__('f') or globals())";
+
+ fclose(fp);
+
+ py_result = PyRun_String(pystring, Py_file_input, py_dict, py_dict);
+ }
+#else
+ py_result = PyRun_File(fp, fn, Py_file_input, py_dict, py_dict);
+ fclose(fp);
+#endif
+ }
+ else {
+ PyErr_Format(
+ PyExc_IOError, "Python file \"%s\" could not be opened: %s", fn, strerror(errno));
+ py_result = NULL;
+ }
+ }
+
+ if (!py_result) {
+ if (text) {
+ if (do_jump) {
+ /* ensure text is valid before use, the script may have freed its self */
+ Main *bmain_new = CTX_data_main(C);
+ if ((bmain_old == bmain_new) && (BLI_findindex(&bmain_new->texts, text) != -1)) {
+ python_script_error_jump_text(text);
+ }
+ }
+ }
+ BPy_errors_to_report(reports);
+ }
+ else {
+ Py_DECREF(py_result);
+ }
+
+ if (py_dict) {
+#ifdef PYMODULE_CLEAR_WORKAROUND
+ PyModuleObject *mmod = (PyModuleObject *)PyDict_GetItem(PyImport_GetModuleDict(),
+ bpy_intern_str___main__);
+ PyObject *dict_back = mmod->md_dict;
+ /* freeing the module will clear the namespace,
+ * gives problems running classes defined in this namespace being used later. */
+ mmod->md_dict = NULL;
+ Py_DECREF(dict_back);
+#endif
+
+#undef PYMODULE_CLEAR_WORKAROUND
+ }
+
+ PyC_MainModule_Restore(main_mod);
+
+ bpy_context_clear(C, &gilstate);
+
+ return (py_result != NULL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run Text / Filename / String
+ * \{ */
+
+/* Can run a file or text block */
+bool BPY_run_filepath(bContext *C, const char *filepath, struct ReportList *reports)
+{
+ return python_script_exec(C, filepath, NULL, reports, false);
+}
+
+bool BPY_run_text(bContext *C, struct Text *text, struct ReportList *reports, const bool do_jump)
+{
+ return python_script_exec(C, NULL, text, reports, do_jump);
+}
+
+bool BPY_run_string_ex(bContext *C, const char *imports[], const char *expr, bool use_eval)
+{
+ BLI_assert(expr);
+ PyGILState_STATE gilstate;
+ PyObject *main_mod = NULL;
+ PyObject *py_dict, *retval;
+ bool ok = true;
+
+ if (expr[0] == '\0') {
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ PyC_MainModule_Backup(&main_mod);
+
+ py_dict = PyC_DefaultNameSpace("<blender string>");
+
+ if (imports && (!PyC_NameSpace_ImportArray(py_dict, imports))) {
+ Py_DECREF(py_dict);
+ retval = NULL;
+ }
+ else {
+ retval = PyRun_String(expr, use_eval ? Py_eval_input : Py_file_input, py_dict, py_dict);
+ }
+
+ if (retval == NULL) {
+ ok = false;
+ BPy_errors_to_report(CTX_wm_reports(C));
+ }
+ else {
+ Py_DECREF(retval);
+ }
+
+ PyC_MainModule_Restore(main_mod);
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+bool BPY_run_string(bContext *C, const char *imports[], const char *expr)
+{
+ return BPY_run_string_ex(C, imports, expr, true);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Run Python & Evaluate Utilities
+ *
+ * Return values as plain C types, useful to run Python scripts
+ * in code that doesn't deal with Python data-types.
+ * \{ */
+
+/**
+ * \return success
+ */
+bool BPY_run_string_as_number(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ double *r_value)
+{
+ PyGILState_STATE gilstate;
+ bool ok = true;
+
+ if (!r_value || !expr) {
+ return -1;
+ }
+
+ if (expr[0] == '\0') {
+ *r_value = 0.0;
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ ok = PyC_RunString_AsNumber(imports, expr, "<expr as number>", r_value);
+
+ if (ok == false) {
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+/**
+ * \return success
+ */
+bool BPY_run_string_as_string_and_size(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ char **r_value,
+ size_t *r_value_size)
+{
+ BLI_assert(r_value && expr);
+ PyGILState_STATE gilstate;
+ bool ok = true;
+
+ if (expr[0] == '\0') {
+ *r_value = NULL;
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ ok = PyC_RunString_AsStringAndSize(imports, expr, "<expr as str>", r_value, r_value_size);
+
+ if (ok == false) {
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), false, false, report_prefix);
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+bool BPY_run_string_as_string(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ char **r_value)
+{
+ size_t value_dummy_size;
+ return BPY_run_string_as_string_and_size(
+ C, imports, expr, report_prefix, r_value, &value_dummy_size);
+}
+
+/**
+ * Support both int and pointers.
+ *
+ * \return success
+ */
+bool BPY_run_string_as_intptr(bContext *C,
+ const char *imports[],
+ const char *expr,
+ const char *report_prefix,
+ intptr_t *r_value)
+{
+ BLI_assert(r_value && expr);
+ PyGILState_STATE gilstate;
+ bool ok = true;
+
+ if (expr[0] == '\0') {
+ *r_value = 0;
+ return ok;
+ }
+
+ bpy_context_set(C, &gilstate);
+
+ ok = PyC_RunString_AsIntPtr(imports, expr, "<expr as intptr>", r_value);
+
+ if (ok == false) {
+ if (report_prefix != NULL) {
+ BPy_errors_to_report_ex(CTX_wm_reports(C), report_prefix, false, false);
+ }
+ else {
+ PyErr_Clear();
+ }
+ }
+
+ bpy_context_clear(C, &gilstate);
+
+ return ok;
+}
+
+/** \} */