[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