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
path: root/source
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
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')
-rw-r--r--source/blender/editors/interface/interface.c8
-rw-r--r--source/blender/editors/interface/interface_context_menu.c7
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c12
-rw-r--r--source/blender/editors/space_script/script_edit.c7
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/util/numinput.c6
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h10
-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
-rw-r--r--source/blender/windowmanager/intern/wm.c3
-rw-r--r--source/blender/windowmanager/intern/wm_files.c8
-rw-r--r--source/creator/creator_args.c12
15 files changed, 503 insertions, 399 deletions
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 2ee1ecccd56..41e7db3a38c 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -69,7 +69,9 @@
#include "RNA_access.h"
-#include "BPY_extern.h"
+#ifdef WITH_PYTHON
+# include "BPY_extern_run.h"
+#endif
#include "ED_numinput.h"
#include "ED_screen.h"
@@ -2812,7 +2814,7 @@ char *ui_but_string_get_dynamic(uiBut *but, int *r_str_size)
}
/**
- * Report a generic error prefix when evaluating a string with #BPY_execute_string_as_number
+ * Report a generic error prefix when evaluating a string with #BPY_run_string_as_number
* as the Python error on it's own doesn't provide enough context.
*/
#define UI_NUMBER_EVAL_ERROR_PREFIX IFACE_("Error evaluating number, see Info editor for details")
@@ -2837,7 +2839,7 @@ static bool ui_number_from_string(bContext *C, const char *str, double *r_value)
{
bool ok;
#ifdef WITH_PYTHON
- ok = BPY_execute_string_as_number(C, NULL, str, UI_NUMBER_EVAL_ERROR_PREFIX, r_value);
+ ok = BPY_run_string_as_number(C, NULL, str, UI_NUMBER_EVAL_ERROR_PREFIX, r_value);
#else
UNUSED_VARS(C);
*r_value = atof(str);
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 46876fca9a5..59178e209db 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -47,7 +47,10 @@
#include "RNA_access.h"
-#include "BPY_extern.h"
+#ifdef WITH_PYTHON
+# include "BPY_extern.h"
+# include "BPY_extern_run.h"
+#endif
#include "WM_api.h"
#include "WM_types.h"
@@ -407,7 +410,7 @@ static void ui_but_user_menu_add(bContext *C, uiBut *but, bUserMenu *um)
"'%s').label",
idname);
char *expr_result = NULL;
- if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
+ if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
STRNCPY(drawstr, expr_result);
MEM_freeN(expr_result);
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index 41b41cb3d75..c324e27dff9 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -63,7 +63,7 @@
#include "BLT_translation.h"
#ifdef WITH_PYTHON
-# include "BPY_extern.h"
+# include "BPY_extern_run.h"
#endif
#include "ED_screen.h"
@@ -433,7 +433,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
+ else if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
if (STREQ(expr_result, "")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -490,7 +490,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
expr_result = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
+ else if (BPY_run_string_as_string(C, expr_imports, expr, __func__, &expr_result)) {
if (STREQ(expr_result, ".")) {
MEM_freeN(expr_result);
expr_result = NULL;
@@ -594,7 +594,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
shortcut = BLI_strdup(has_valid_context_error);
}
- else if (BPY_execute_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
+ else if (BPY_run_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
@@ -658,7 +658,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
/* pass */
}
- else if (BPY_execute_string_as_string_and_size(
+ else if (BPY_run_string_as_string_and_size(
C, expr_imports, expr, __func__, &expr_result, &expr_result_len)) {
/* pass. */
}
@@ -736,7 +736,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) {
/* pass */
}
- else if (BPY_execute_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
+ else if (BPY_run_string_as_intptr(C, expr_imports, expr, __func__, &expr_result)) {
if (expr_result != 0) {
{
uiTooltipField *field = text_field_add(data,
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index e9ed1cec228..f9d7e8371b2 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -42,7 +42,7 @@
#include "script_intern.h" // own include
#ifdef WITH_PYTHON
-# include "BPY_extern.h" /* BPY_script_exec */
+# include "BPY_extern_run.h"
#endif
static int run_pyfile_exec(bContext *C, wmOperator *op)
@@ -50,7 +50,7 @@ static int run_pyfile_exec(bContext *C, wmOperator *op)
char path[512];
RNA_string_get(op->ptr, "filepath", path);
#ifdef WITH_PYTHON
- if (BPY_execute_filepath(C, path, op->reports)) {
+ if (BPY_run_filepath(C, path, op->reports)) {
ARegion *region = CTX_wm_region(C);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
@@ -120,8 +120,7 @@ static int script_reload_exec(bContext *C, wmOperator *op)
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
- BPY_execute_string(
- C, (const char *[]){"bpy", NULL}, "bpy.utils.load_scripts(reload_scripts=True)");
+ BPY_run_string(C, (const char *[]){"bpy", NULL}, "bpy.utils.load_scripts(reload_scripts=True)");
WM_cursor_wait(0);
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 201f9dae5d5..688dce3c54e 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -55,6 +55,7 @@
#ifdef WITH_PYTHON
# include "BPY_extern.h"
+# include "BPY_extern_run.h"
#endif
#include "text_format.h"
@@ -756,7 +757,7 @@ static int text_run_script(bContext *C, ReportList *reports)
void *curl_prev = text->curl;
int curc_prev = text->curc;
- if (BPY_execute_text(C, text, reports, !is_live)) {
+ if (BPY_run_text(C, text, reports, !is_live)) {
if (is_live) {
/* for nice live updates */
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index 384da6fb931..041b2fec00b 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -38,7 +38,7 @@
#include "WM_types.h"
#ifdef WITH_PYTHON
-# include "BPY_extern.h"
+# include "BPY_extern_run.h"
#endif
#include "ED_numinput.h"
@@ -294,10 +294,10 @@ bool user_string_to_number(bContext *C,
bUnit_ReplaceString(
str_unit_convert, sizeof(str_unit_convert), str, unit_scale, unit->system, type);
- return BPY_execute_string_as_number(C, NULL, str_unit_convert, error_prefix, r_value);
+ return BPY_run_string_as_number(C, NULL, str_unit_convert, error_prefix, r_value);
}
- int success = BPY_execute_string_as_number(C, NULL, str, error_prefix, r_value);
+ int success = BPY_run_string_as_number(C, NULL, str, error_prefix, r_value);
*r_value *= bUnit_PreferredInputUnitScalar(unit, type);
*r_value /= unit_scale;
return success;
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
index bae69aa0a42..e2022c1de85 100644
--- a/source/blender/freestyle/intern/system/PythonInterpreter.h
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -42,7 +42,7 @@ extern "C" {
#include "BKE_report.h"
#include "BKE_text.h"
-#include "BPY_extern.h"
+#include "BPY_extern_run.h"
#include "bpy_capi_utils.h"
@@ -68,12 +68,12 @@ class PythonInterpreter : public Interpreter {
BKE_reports_clear(reports);
char *fn = const_cast<char *>(filename.c_str());
#if 0
- bool ok = BPY_execute_filepath(_context, fn, reports);
+ bool ok = BPY_run_filepath(_context, fn, reports);
#else
bool ok;
Text *text = BKE_text_load(&_freestyle_bmain, fn, G_MAIN->name);
if (text) {
- ok = BPY_execute_text(_context, text, reports, false);
+ ok = BPY_run_text(_context, text, reports, false);
BKE_id_delete(&_freestyle_bmain, text);
}
else {
@@ -102,7 +102,7 @@ class PythonInterpreter : public Interpreter {
BKE_reports_clear(reports);
- if (!BPY_execute_string(_context, NULL, str.c_str())) {
+ if (!BPY_run_string(_context, NULL, str.c_str())) {
BPy_errors_to_report(reports);
cerr << "\nError executing Python script from PythonInterpreter::interpretString" << endl;
cerr << "Name: " << name << endl;
@@ -122,7 +122,7 @@ class PythonInterpreter : public Interpreter {
BKE_reports_clear(reports);
- if (!BPY_execute_text(_context, text, reports, false)) {
+ if (!BPY_run_text(_context, text, reports, false)) {
cerr << "\nError executing Python script from PythonInterpreter::interpretText" << endl;
cerr << "Name: " << name << endl;
cerr << "Errors: " << endl;
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;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 43c08a2b980..22210012bb6 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -66,6 +66,7 @@
#ifdef WITH_PYTHON
# include "BPY_extern.h"
+# include "BPY_extern_run.h"
#endif
/* ****************************************************** */
@@ -270,7 +271,7 @@ void WM_keyconfig_reload(bContext *C)
{
if (CTX_py_init_get(C) && !G.background) {
#ifdef WITH_PYTHON
- BPY_execute_string(C, (const char *[]){"bpy", NULL}, "bpy.utils.keyconfig_init()");
+ BPY_run_string(C, (const char *[]){"bpy", NULL}, "bpy.utils.keyconfig_init()");
#endif
}
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a8d393cfbae..1be22b2283c 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -121,8 +121,8 @@
#include "RE_engine.h"
#ifdef WITH_PYTHON
-# include "BPY_extern.h"
# include "BPY_extern_python.h"
+# include "BPY_extern_run.h"
#endif
#include "DEG_depsgraph.h"
@@ -580,14 +580,14 @@ static void wm_file_read_post(bContext *C,
if (use_userdef || reset_app_template) {
/* Only run when we have a template path found. */
if (BKE_appdir_app_template_any()) {
- BPY_execute_string(
+ BPY_run_string(
C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()");
reset_all = true;
}
}
if (reset_all) {
/* sync addons, these may have changed from the defaults */
- BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
+ BPY_run_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
}
if (use_data) {
BPY_python_reset(C);
@@ -924,7 +924,7 @@ void wm_homefile_read(bContext *C,
*
* Note that this fits into 'wm_file_read_pre' function but gets messy
* since we need to know if 'reset_app_template' is true. */
- BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()");
+ BPY_run_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()");
}
#endif /* WITH_PYTHON */
}
diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c
index cd19ecd6ebc..90c01436520 100644
--- a/source/creator/creator_args.c
+++ b/source/creator/creator_args.c
@@ -61,8 +61,8 @@
# endif
# ifdef WITH_PYTHON
-# include "BPY_extern.h"
# include "BPY_extern_python.h"
+# include "BPY_extern_run.h"
# endif
# include "RE_engine.h"
@@ -1780,7 +1780,7 @@ static int arg_handle_python_file_run(int argc, const char **argv, void *data)
BLI_path_abs_from_cwd(filename, sizeof(filename));
bool ok;
- BPY_CTX_SETUP(ok = BPY_execute_filepath(C, filename, NULL));
+ BPY_CTX_SETUP(ok = BPY_run_filepath(C, filename, NULL));
if (!ok && app_state.exit_code_on_error.python) {
printf("\nError: script failed, file: '%s', exiting.\n", argv[1]);
BPY_python_end();
@@ -1815,7 +1815,7 @@ static int arg_handle_python_text_run(int argc, const char **argv, void *data)
bool ok;
if (text) {
- BPY_CTX_SETUP(ok = BPY_execute_text(C, text, NULL, false));
+ BPY_CTX_SETUP(ok = BPY_run_text(C, text, NULL, false));
}
else {
printf("\nError: text block not found %s.\n", argv[1]);
@@ -1852,7 +1852,7 @@ static int arg_handle_python_expr_run(int argc, const char **argv, void *data)
/* workaround for scripts not getting a bpy.context.scene, causes internal errors elsewhere */
if (argc > 1) {
bool ok;
- BPY_CTX_SETUP(ok = BPY_execute_string_ex(C, NULL, argv[1], false));
+ BPY_CTX_SETUP(ok = BPY_run_string_ex(C, NULL, argv[1], false));
if (!ok && app_state.exit_code_on_error.python) {
printf("\nError: script failed, expr: '%s', exiting.\n", argv[1]);
BPY_python_end();
@@ -1879,7 +1879,7 @@ static int arg_handle_python_console_run(int UNUSED(argc), const char **argv, vo
# ifdef WITH_PYTHON
bContext *C = data;
- BPY_CTX_SETUP(BPY_execute_string(C, (const char *[]){"code", NULL}, "code.interact()"));
+ BPY_CTX_SETUP(BPY_run_string(C, (const char *[]){"code", NULL}, "code.interact()"));
return 0;
# else
@@ -1952,7 +1952,7 @@ static int arg_handle_addons_set(int argc, const char **argv, void *data)
BLI_snprintf(str, slen, script_str, argv[1]);
BLI_assert(strlen(str) + 1 == slen);
- BPY_CTX_SETUP(BPY_execute_string_ex(C, NULL, str, false));
+ BPY_CTX_SETUP(BPY_run_string_ex(C, NULL, str, false));
free(str);
# else
UNUSED_VARS(argv, data);