[Bf-blender-cvs] [1765d0d26ac] soc-2020-info-editor: Print python eval logs: simplify implementation

Mateusz Grzeliński noreply at git.blender.org
Fri Jul 3 12:25:04 CEST 2020


Commit: 1765d0d26ac8813b81d8bf16143d5884038dadf8
Author: Mateusz Grzeliński
Date:   Fri Jul 3 12:24:57 2020 +0200
Branches: soc-2020-info-editor
https://developer.blender.org/rB1765d0d26ac8813b81d8bf16143d5884038dadf8

Print python eval logs: simplify implementation

===================================================================

M	source/blender/python/intern/bpy_capi_utils.c
M	source/blender/python/intern/bpy_interface.c
M	source/blender/python/intern/bpy_interface_inoutwrapper.c
M	source/blender/python/intern/bpy_interface_inoutwrapper.h

===================================================================

diff --git a/source/blender/python/intern/bpy_capi_utils.c b/source/blender/python/intern/bpy_capi_utils.c
index 89ef2f40a30..ba96d6ee7e8 100644
--- a/source/blender/python/intern/bpy_capi_utils.c
+++ b/source/blender/python/intern/bpy_capi_utils.c
@@ -97,6 +97,7 @@ void BPy_reports_write_stdout(const ReportList *reports, const char *header)
   }
 }
 
+/** converts error to report and clears it */
 bool BPy_errors_to_report_ex(ReportList *reports, const bool use_full, const bool use_location)
 {
   PyObject *pystring;
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index b4e9a4bd47a..5b949c7d1a5 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -25,6 +25,7 @@
  */
 
 #include <BKE_report.h>
+#include <BLT_translation.h>
 #include <Python.h>
 
 #include "MEM_guardedalloc.h"
@@ -248,7 +249,6 @@ static struct _inittab bpy_internal_modules[] = {
 #endif
     {"gpu", BPyInit_gpu},
     {"idprop", BPyInit_idprop},
-    {"_inoutwrapper", PyInit_in_out_wrapper},
     {NULL, NULL},
 };
 
@@ -497,15 +497,33 @@ static bool python_script_exec(
       }
     }
 
-    char *output;
     if (text->compiled) {
-      BPY_intern_init_inoutwrapper();
       py_dict = PyC_DefaultNameSpace(fn_dummy);
+
+      bool wrapper_init_ok = BPY_intern_init_io_wrapper();
+      if (!wrapper_init_ok) {
+        CLOG_WARN(BPY_LOG_RNA,
+                  "Setting python IO wrapper failed! Script output will not be visible in Info Edotr");
+      }
+
       py_result = PyEval_EvalCode(text->compiled, py_dict, py_dict);
-      output = BPY_intern_get_inout_buffer();
-      BKE_report(reports, RPT_INFO, output);
-      BPY_intern_free_inoutwrapper();
-      MEM_freeN(output);
+
+      if (wrapper_init_ok) {
+        // printing io buffer will fail if error is set
+        if (PyErr_Occurred()) {
+          PyObject *error_type, *error_value, *error_traceback;
+          PyErr_Fetch(&error_type, &error_value, &error_traceback);
+          PyErr_Clear();
+          PyObject *pystring = BPY_intern_get_io_buffer();
+          BKE_report(reports, RPT_INFO, _PyUnicode_AsString(pystring));
+          PyErr_Restore(error_type, error_value, error_traceback);
+        }
+        else {
+          PyObject *pystring = BPY_intern_get_io_buffer();
+          BKE_report(reports, RPT_INFO, _PyUnicode_AsString(pystring));
+        }
+        BPY_intern_free_io_twrapper();
+      }
     }
   }
   else {
@@ -563,6 +581,7 @@ static bool python_script_exec(
     BPy_errors_to_report(reports);
   }
   else {
+    BPy_errors_to_report(reports);
     Py_DECREF(py_result);
   }
 
diff --git a/source/blender/python/intern/bpy_interface_inoutwrapper.c b/source/blender/python/intern/bpy_interface_inoutwrapper.c
index a0f837ab422..e0d7bb75ec4 100644
--- a/source/blender/python/intern/bpy_interface_inoutwrapper.c
+++ b/source/blender/python/intern/bpy_interface_inoutwrapper.c
@@ -20,215 +20,67 @@
  * This file wraps around pythons stdin stdout and exposes it in buffer
  */
 
-#include <BLI_dynstr.h>
 #include <Python.h>
 
 #include "MEM_guardedalloc.h"
 
-#include "CLG_log.h"
-
-#include "BLI_fileops.h"
-#include "BLI_listbase.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
 #include "BLI_string_utf8.h"
-#include "BLI_threads.h"
 #include "BLI_utildefines.h"
 
-#include "RNA_types.h"
-
-#include "bpy.h"
-#include "bpy_capi_utils.h"
-#include "bpy_intern_string.h"
-#include "bpy_path.h"
-#include "bpy_rna.h"
-#include "bpy_traceback.h"
-
-#include "bpy_app_translations.h"
-
-#include "DNA_text_types.h"
-
-#include "BKE_appdir.h"
-#include "BKE_context.h"
-#include "BKE_global.h" /* only for script checking */
-#include "BKE_main.h"
-#include "BKE_text.h"
 #include "bpy_interface_inoutwrapper.h"
 
-// todo avoid single global buffer
-static DynStr *io_buffer = NULL;
-
-// Internal state
-PyObject *g_stdout;
-PyObject *g_stdout_saved;
-PyObject *g_stderr;
-PyObject *g_stderr_saved;
+PyObject *string_io_mod = NULL;
+PyObject *string_io = NULL;
+PyObject *stdout_backup = NULL;
+PyObject *stderr_backup = NULL;
+PyObject *string_io_buf = NULL;
+PyObject *string_io_getvalue = NULL;
 
-// instead of printing to stdout, use this function
-typedef size_t (*print_handle)(char *);
-
-typedef struct InOutWrapper {
-  PyObject_HEAD print_handle write;
-} InOutWrapper;
-
-static PyObject *Stdout_write(PyObject *self, PyObject *args)
+PyObject *BPY_intern_init_io_wrapper()
 {
-  size_t written = 0;
-  InOutWrapper *selfimpl = (InOutWrapper *)(self);
-  if (selfimpl->write) {
-    char *data;
-    if (!PyArg_ParseTuple(args, "s", &data))
-      return 0;
+  PyImport_ImportModule("sys");
+  stdout_backup = PySys_GetObject("stdout"); /* borrowed */
+  stderr_backup = PySys_GetObject("stderr"); /* borrowed */
+  BLI_assert(stderr_backup != NULL);
 
-    written = selfimpl->write(data);
+  if (!(string_io_mod = PyImport_ImportModule("io"))) {
+    return NULL;
   }
-  return PyLong_FromSize_t(written);
-}
-
-static PyObject *Stdout_flush(PyObject *UNUSED(self), PyObject *UNUSED(args))
-{
-  // no-op
-  return Py_BuildValue("");
-}
-
-PyMethodDef InOut_methods[] = {
-    {"write", Stdout_write, METH_VARARGS, "sys.stdout.write"},
-    {"flush", Stdout_flush, METH_VARARGS, "sys.stdout.write"},
-    {0, 0, 0, 0}  // sentinel
-};
-
-PyTypeObject InOutHandlerType = {
-    PyVarObject_HEAD_INIT(0, 0) "InOutHandlerType", /* tp_name */
-    sizeof(InOutWrapper),                           /* tp_basicsize */
-    0,                                              /* tp_itemsize */
-    0,                                              /* tp_dealloc */
-    0,                                              /* tp_print */
-    0,                                              /* tp_getattr */
-    0,                                              /* tp_setattr */
-    0,                                              /* tp_reserved */
-    0,                                              /* tp_repr */
-    0,                                              /* tp_as_number */
-    0,                                              /* tp_as_sequence */
-    0,                                              /* tp_as_mapping */
-    0,                                              /* tp_hash  */
-    0,                                              /* tp_call */
-    0,                                              /* tp_str */
-    0,                                              /* tp_getattro */
-    0,                                              /* tp_setattro */
-    0,                                              /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT,                             /* tp_flags */
-    "InOutWrapper objects",                         /* tp_doc */
-    0,                                              /* tp_traverse */
-    0,                                              /* tp_clear */
-    0,                                              /* tp_richcompare */
-    0,                                              /* tp_weaklistoffset */
-    0,                                              /* tp_iter */
-    0,                                              /* tp_iternext */
-    InOut_methods,                                  /* tp_methods */
-};
-
-PyModuleDef in_out_wrapper_module = {
-    PyModuleDef_HEAD_INIT,
-    "_in_out_wrapper",
-    0,
-    -1,
-    0,
-};
-
-PyMODINIT_FUNC PyInit_in_out_wrapper(void)
-{
-  g_stdout = NULL;
-  g_stdout_saved = NULL;
-
-  InOutHandlerType.tp_new = PyType_GenericNew;
-  if (PyType_Ready(&InOutHandlerType) < 0)
-    return 0;
-
-  PyObject *m = PyModule_Create(&in_out_wrapper_module);
-  if (m) {
-    Py_INCREF(&InOutHandlerType);
-    PyModule_AddObject(m, "InOutWrapper", (PyObject *)(&InOutHandlerType));
+  else if (!(string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
+    return NULL;
   }
-  return m;
-}
-
-static void set_stdout(print_handle write)
-{
-  if (!g_stdout) {
-    g_stdout_saved = PySys_GetObject("stdout");  // borrowed
-    g_stdout = InOutHandlerType.tp_new(&InOutHandlerType, NULL, NULL);
+  else if (!(string_io_getvalue = PyObject_GetAttrString(string_io, "getvalue"))) {
+    return NULL;
   }
+  Py_INCREF(stdout_backup);  // since these were borrowed we don't want them freed when replaced.
+  Py_INCREF(stderr_backup);
 
-  InOutWrapper *impl = (InOutWrapper *)(g_stdout);
-  impl->write = write;
-  PySys_SetObject("stdout", g_stdout);
-}
-
-static void set_stderr(print_handle write)
-{
-  if (!g_stderr) {
-    g_stderr_saved = PySys_GetObject("stderr");  // borrowed
-    g_stderr = InOutHandlerType.tp_new(&InOutHandlerType, NULL, NULL);
+  if (PySys_SetObject("stdout", string_io) == -1) {
+    return NULL;
+  }
+  if (PySys_SetObject("stderr", string_io) == -1) {
+    return NULL;
   }
 
-  InOutWrapper *impl = (InOutWrapper *)(g_stderr);
-  impl->write = write;
-  PySys_SetObject("stderr", g_stdout);
-}
-
-// todo investigate if not calling reset causes memory leak
-static void reset_stdout(void)
-{
-  if (g_stdout_saved)
-    PySys_SetObject("stdout", g_stdout_saved);
-
-  Py_XDECREF(g_stdout);
-  g_stdout = 0;
-}
-
-static void reset_stderr(void)
-{
-  if (g_stdout_saved)
-    PySys_SetObject("stderr", g_stderr_saved);
-
-  Py_XDECREF(g_stdout);
-  g_stdout = 0;
-}
-
-// todo there is no use for returning written bytes
-static size_t custom_write(char *input)
-{
-  int len = BLI_dynstr_get_len(io_buffer);
-  BLI_dynstr_append(io_buffer, input);
-  printf("custom write> %s", input);
-  return BLI_dynstr_get_len(io_buffer) - len;
-}
-
-// todo investigate possible conflicts with BPy_reports_write_stdout
-/* use it anywhere after Py_Initialize */
-void BPY_intern_init_inoutwrapper()
-{
-  PyImport_ImportModule("_inoutwrapper");
-  BLI_assert(io_buffer == NULL);
-  io_buffer = BLI_dynstr_new();
-
-  // switch sys.stdout to custom handler
-  print_handle stdout_write_hadle = custom_write;
-  set_stdout(stdout_write_hadle);
-  set_stderr(stdout_write_hadle);
+  return 1;
 }
 
-char *BPY_intern_get_inout_buffer()
+PyObject *BPY_intern_get_io_buffer()
 {
-  BLI_assert(io_buffer != NULL);
-  return BLI_dynstr_get_cstring(io_buffer);
+  BLI_assert(string_io_get

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list