Blender V4.3
bpy_capi_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include <Python.h>
13
14#include "BLI_listbase.h"
15#include "BLI_utildefines.h"
16
17#include "bpy_capi_utils.hh"
18
19#include "MEM_guardedalloc.h"
20
21#include "BKE_report.hh"
22
24
25short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool clear)
26{
27 char *report_str;
28
29 report_str = BKE_reports_string(reports, RPT_ERROR);
30
31 if (clear == true) {
32 BKE_reports_free(reports);
33 }
34
35 if (report_str) {
36 PyErr_SetString(exception, report_str);
37 MEM_freeN(report_str);
38 }
39
40 return (report_str == nullptr) ? 0 : -1;
41}
42
43void BPy_reports_write_stdout(const ReportList *reports, const char *header)
44{
45 const Report *report;
46 for (report = static_cast<const Report *>(reports->list.first); report; report = report->next) {
47 if (report->type < reports->printlevel) {
48 continue;
49 }
50 break;
51 }
52 if (report == nullptr) {
53 return;
54 }
55
56 if (header) {
57 PySys_WriteStdout("%s\n", header);
58 }
59
60 for (; report; report = report->next) {
61 if (report->type < reports->printlevel) {
62 continue;
63 }
64 PySys_WriteStdout("%s: %s\n", report->typestr, report->message);
65 }
66}
67
69 const char *error_prefix,
70 const bool use_full,
71 const bool use_location)
72{
73
74 if (!PyErr_Occurred()) {
75 return true;
76 }
77
78 PyObject *err_str_py = use_full ? PyC_ExceptionBuffer() : PyC_ExceptionBuffer_Simple();
79
80 /* Strip trailing newlines so the report doesn't show a blank-line in the info space. */
81 Py_ssize_t err_str_len;
82 const char *err_str = PyUnicode_AsUTF8AndSize(err_str_py, &err_str_len);
83 while (err_str_len > 0 && err_str[err_str_len - 1] == '\n') {
84 err_str_len -= 1;
85 }
86
87 if (error_prefix == nullptr) {
88 /* Not very helpful, better than nothing. */
89 error_prefix = "Python";
90 }
91
92 const char *location_filepath = nullptr;
93 int location_line_number = -1;
94
95 /* Give some additional context. */
96 if (use_location) {
97 PyC_FileAndNum(&location_filepath, &location_line_number);
98 }
99
100 /* Create a temporary report list so none of the reports are printed (only stored).
101 * In practically all cases printing should be handled by #PyErr_Print since this invokes
102 * `sys.excepthook` as expected. */
103 ReportList _reports_buf = {{nullptr}};
104 ReportList *reports_orig = reports;
105 if ((reports->flag & RPT_PRINT_HANDLED_BY_OWNER) == 0) {
106 reports = &_reports_buf;
107 BKE_reports_init(reports, reports_orig->flag | RPT_PRINT_HANDLED_BY_OWNER);
108 reports->storelevel = reports_orig->storelevel;
109 }
110
111 if (location_filepath) {
112 BKE_reportf(reports,
113 RPT_ERROR,
114 "%s: %.*s\n"
115 /* Location (when available). */
116 "Location: %s:%d",
117 error_prefix,
118 int(err_str_len),
119 err_str,
120 location_filepath,
121 location_line_number);
122 }
123 else {
124 BKE_reportf(reports, RPT_ERROR, "%s: %.*s", error_prefix, int(err_str_len), err_str);
125 }
126
127 if (reports != reports_orig) {
128 BKE_reports_move_to_reports(reports_orig, reports);
129 BKE_reports_free(reports);
130 }
131
132 /* Ensure this is _always_ printed to the output so developers don't miss exceptions. */
133 Py_DECREF(err_str_py);
134 return true;
135}
136
138{
139 return BPy_errors_to_report_ex(reports, nullptr, true, true);
140}
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
char * BKE_reports_string(ReportList *reports, eReportType level)
Definition report.cc:268
void BKE_reports_free(ReportList *reports)
Definition report.cc:69
void BKE_reports_init(ReportList *reports, int flag)
Definition report.cc:54
void BKE_reports_move_to_reports(ReportList *reports_dst, ReportList *reports_src)
Definition report.cc:113
@ RPT_PRINT_HANDLED_BY_OWNER
Read Guarded memory(de)allocation.
bool BPy_errors_to_report_ex(ReportList *reports, const char *error_prefix, const bool use_full, const bool use_location)
void BPy_reports_write_stdout(const ReportList *reports, const char *header)
short BPy_reports_to_error(ReportList *reports, PyObject *exception, const bool clear)
bool BPy_errors_to_report(ReportList *reports)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
static void clear(Message &msg)
Definition msgfmt.cc:218
PyObject * PyC_ExceptionBuffer()
PyObject * PyC_ExceptionBuffer_Simple()
void PyC_FileAndNum(const char **r_filename, int *r_lineno)
void * first
struct Report * next
const char * typestr
const char * message