Skip to content

Commit 3a99887

Browse files
committed
python 修复小于 3.12 版本下的异常处理 调整异常格式化逻辑 并精简异常信息
1 parent 5020e28 commit 3a99887

File tree

3 files changed

+93
-26
lines changed

3 files changed

+93
-26
lines changed

unity/native/papi-python/include/PapiData.h

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,25 @@ struct pesapi_value_ref__ : pesapi_env_ref__
5858

5959
struct caught_exception_info
6060
{
61-
PyObject* ex;
61+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
62+
PyObject* value;
63+
#else
64+
PyObject* type;
65+
PyObject* value;
66+
PyObject* traceback;
67+
#endif
68+
~caught_exception_info()
69+
{
70+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
71+
// From PyErr_GetRaisedException
72+
Py_XDECREF(value);
73+
#else
74+
// From PyErr_Fetch
75+
Py_XDECREF(type);
76+
Py_XDECREF(value);
77+
Py_XDECREF(traceback);
78+
#endif
79+
}
6280
};
6381

6482
struct pesapi_scope__;
@@ -110,20 +128,34 @@ struct pesapi_scope__
110128
return ret;
111129
}
112130

131+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
132+
// From PyErr_GetRaisedException
113133
void setCaughtException(PyObject* ex)
114134
{
115135
if (caught == nullptr)
116136
{
117137
caught = (caught_exception_info*) PyMem_Malloc(sizeof(caught_exception_info));
118138
}
119-
caught->ex = ex;
139+
caught->value = ex;
140+
}
141+
#else
142+
// From PyErr_Fetch
143+
void setCaughtException(PyObject * type, PyObject * value, PyObject * traceback)
144+
{
145+
if (caught == nullptr)
146+
{
147+
caught = (caught_exception_info*) PyMem_Malloc(sizeof(caught_exception_info));
148+
}
149+
caught->type = type;
150+
caught->value = value;
151+
caught->traceback = traceback;
120152
}
153+
#endif
121154

122155
~pesapi_scope__()
123156
{
124157
if (caught)
125158
{
126-
Py_XDECREF(caught->ex);
127159
caught->~caught_exception_info();
128160
PyMem_Free(caught);
129161
}

unity/native/papi-python/source/PapiPythonImpl.cpp

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -602,23 +602,64 @@ const char* pesapi_get_exception_as_string(pesapi_scope pscope, int with_stack)
602602
{
603603
return nullptr;
604604
}
605-
auto ex = scope->caught->ex;
606605
auto globals = PyModule_GetDict(PyImport_AddModule("__main__"));
607-
PyDict_SetItem(globals, PyUnicode_FromString("__pesapi_last_exception"), ex);
608-
const char* ret;
606+
607+
const char* ret = nullptr;
609608
if (with_stack)
610609
{
610+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
611+
PyDict_SetItem(globals, PyUnicode_FromString("__pesapi_last_exception"), scope->caught->value);
611612
PyRun_SimpleString(
612613
"import traceback\n"
613-
"try:\n"
614-
" raise __pesapi_last_exception\n"
615-
"except Exception as e:\n"
616-
" __pesapi_last_exception_str = ''.join(traceback.format_exception(type(e), e, e.__traceback__))\n");
614+
"if __pesapi_last_exception.__traceback__ is not None:\n"
615+
" __pesapi_last_exception_str = ''.join(traceback.format_exception(type(__pesapi_last_exception), __pesapi_last_exception, __pesapi_last_exception.__traceback__))\n"
616+
"else:\n"
617+
" __pesapi_last_exception_str = ''.join(traceback.format_exception_only(type(__pesapi_last_exception), __pesapi_last_exception))\n");
617618
ret = PyUnicode_AsUTF8(PyDict_GetItem(globals, PyUnicode_FromString("__pesapi_last_exception_str")));
619+
#else
620+
auto tracebackModule = PyImport_ImportModule("traceback");
621+
auto traceback = scope->caught->traceback;
622+
auto type = scope->caught->type;
623+
auto value = scope->caught->value;
624+
if (traceback)
625+
{
626+
if (PyObject* formatExceptionFunc = PyObject_GetAttrString(tracebackModule, "format_exception");
627+
formatExceptionFunc && PyCallable_Check(formatExceptionFunc))
628+
{
629+
if (PyObject* formattedList = PyObject_CallFunctionObjArgs(formatExceptionFunc, type, value, traceback, nullptr))
630+
{
631+
if (PyObject* formattedStr = PyUnicode_Join(PyUnicode_FromString(""), formattedList))
632+
{
633+
ret = strdup(PyUnicode_AsUTF8(formattedStr));
634+
Py_DECREF(formattedStr);
635+
}
636+
Py_DECREF(formattedList);
637+
}
638+
Py_DECREF(formatExceptionFunc);
639+
}
640+
}
641+
else
642+
{
643+
if (PyObject* formatExceptionOnlyFunc = PyObject_GetAttrString(tracebackModule, "format_exception_only");
644+
formatExceptionOnlyFunc && PyCallable_Check(formatExceptionOnlyFunc))
645+
{
646+
if (PyObject* formattedList = PyObject_CallFunctionObjArgs(formatExceptionOnlyFunc, type, value, nullptr))
647+
{
648+
if (PyObject* formattedStr = PyUnicode_Join(PyUnicode_FromString(""), formattedList))
649+
{
650+
ret = strdup(PyUnicode_AsUTF8(formattedStr));
651+
Py_DECREF(formattedStr);
652+
}
653+
Py_DECREF(formattedList);
654+
}
655+
Py_DECREF(formatExceptionOnlyFunc);
656+
}
657+
}
658+
#endif
618659
}
619660
else
620661
{
621-
ret = PyUnicode_AsUTF8(PyObject_Str(ex));
662+
ret = PyUnicode_AsUTF8(PyObject_Str(scope->caught->value));
622663
}
623664
PyDict_DelItemString(globals, "__pesapi_last_exception");
624665
return ret;
@@ -780,16 +821,13 @@ pesapi_value pesapi_call_function(
780821
else
781822
{
782823
auto scope = (pesapi_scope__*)mapper->getCurrentScope();
783-
#if PY_VERSION_HEX >= 0x030B0000
824+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
784825
scope->setCaughtException(PyErr_GetRaisedException());
785826
#else
786827
{
787-
PyObject *type = nullptr, *value = nullptr, *tb = nullptr;
788-
PyErr_Fetch(&type, &value, &tb);
789-
PyObject *exc = value ? value : type;
790-
if (exc) Py_XINCREF(exc);
791-
PyErr_Restore(type, value, tb);
792-
scope->setCaughtException(exc);
828+
PyObject *type = nullptr, *value = nullptr, *traceback = nullptr;
829+
PyErr_Fetch(&type, &value, &traceback);
830+
scope->setCaughtException(type, value, traceback);
793831
}
794832
#endif
795833
return nullptr;
@@ -816,16 +854,13 @@ pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size,
816854
}
817855
}
818856
auto scope = (pesapi_scope__*)mapper->getCurrentScope();
819-
#if PY_VERSION_HEX >= 0x030B0000
857+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 12
820858
scope->setCaughtException(PyErr_GetRaisedException());
821859
#else
822860
{
823-
PyObject *type = nullptr, *value = nullptr, *tb = nullptr;
824-
PyErr_Fetch(&type, &value, &tb);
825-
PyObject *exc = value ? value : type;
826-
if (exc) Py_XINCREF(exc);
827-
PyErr_Restore(type, value, tb);
828-
scope->setCaughtException(exc);
861+
PyObject *type = nullptr, *value = nullptr, *traceback = nullptr;
862+
PyErr_Fetch(&type, &value, &traceback);
863+
scope->setCaughtException(type, value, traceback);
829864
}
830865
#endif
831866
return nullptr;

unity/native/papi-python/test/papi_py_base_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ TEST_F(PApiBaseTest, EvalJavaScriptEx)
427427

428428
EXPECT_STREQ("abc", apis->get_exception_as_string(scope, false));
429429
EXPECT_STREQ(
430-
"Traceback (most recent call last):\n File \"<string>\", line 3, in <module>\n File \"test.py\", line 1, in <module>\n "
430+
"Traceback (most recent call last):\n File \"test.py\", line 1, in <module>\n "
431431
"File \"test.py\", line 1, in <lambda>\n File \"test.py\", line 1, in <genexpr>\nException: abc\n",
432432
apis->get_exception_as_string(scope, true));
433433
}

0 commit comments

Comments
 (0)