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).
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
          }
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								source/blender/python/BPY_extern_run.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								source/blender/python/BPY_extern_run.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										391
									
								
								source/blender/python/intern/bpy_interface_run.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								source/blender/python/intern/bpy_interface_run.c
									
									
									
									
									
										Normal file
									
								
							@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** \} */
 | 
			
		||||
@@ -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
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user