Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit51d693c

Browse files
authored
gh-102594: PyErr_SetObject adds note to exception raised on normalization error (#102675)
1 parent2dc9463 commit51d693c

File tree

6 files changed

+96
-5
lines changed

6 files changed

+96
-5
lines changed

‎Include/cpython/pyerrors.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ PyAPI_FUNC(PyObject *) _PyErr_FormatFromCause(
112112

113113
/* In exceptions.c */
114114

115+
PyAPI_FUNC(int)_PyException_AddNote(
116+
PyObject*exc,
117+
PyObject*note);
118+
115119
/* Helper that attempts to replace the current exception with one of the
116120
* same type but with a prefix added to the exception text. The resulting
117121
* exception description looks like:

‎Lib/test/test_capi/test_exceptions.py‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,25 @@ class Broken(Exception, metaclass=Meta):
169169
withself.assertRaises(ZeroDivisionError)ase:
170170
_testcapi.exc_set_object(Broken,Broken())
171171

172+
deftest_set_object_and_fetch(self):
173+
classBroken(Exception):
174+
def__init__(self,*arg):
175+
raiseValueError("Broken __init__")
176+
177+
exc=_testcapi.exc_set_object_fetch(Broken,'abcd')
178+
self.assertIsInstance(exc,ValueError)
179+
self.assertEqual(exc.__notes__[0],
180+
"Normalization failed: type=Broken args='abcd'")
181+
182+
classBadArg:
183+
def__repr__(self):
184+
raiseTypeError('Broken arg type')
185+
186+
exc=_testcapi.exc_set_object_fetch(Broken,BadArg())
187+
self.assertIsInstance(exc,ValueError)
188+
self.assertEqual(exc.__notes__[0],
189+
'Normalization failed: type=Broken args=<unknown>')
190+
191+
172192
if__name__=="__main__":
173193
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add note to exception raised in ``PyErr_SetObject`` when normalization fails.

‎Modules/_testcapi/exceptions.c‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@ exc_set_object(PyObject *self, PyObject *args)
9292
returnNULL;
9393
}
9494

95+
staticPyObject*
96+
exc_set_object_fetch(PyObject*self,PyObject*args)
97+
{
98+
PyObject*exc;
99+
PyObject*obj;
100+
PyObject*type;
101+
PyObject*value;
102+
PyObject*tb;
103+
104+
if (!PyArg_ParseTuple(args,"OO:exc_set_object",&exc,&obj)) {
105+
returnNULL;
106+
}
107+
108+
PyErr_SetObject(exc,obj);
109+
PyErr_Fetch(&type,&value,&tb);
110+
Py_XDECREF(type);
111+
Py_XDECREF(tb);
112+
returnvalue;
113+
}
114+
95115
staticPyObject*
96116
raise_exception(PyObject*self,PyObject*args)
97117
{
@@ -262,6 +282,7 @@ static PyMethodDef test_methods[] = {
262282
{"make_exception_with_doc",_PyCFunction_CAST(make_exception_with_doc),
263283
METH_VARARGS |METH_KEYWORDS},
264284
{"exc_set_object",exc_set_object,METH_VARARGS},
285+
{"exc_set_object_fetch",exc_set_object_fetch,METH_VARARGS},
265286
{"raise_exception",raise_exception,METH_VARARGS},
266287
{"raise_memoryerror",raise_memoryerror,METH_NOARGS},
267288
{"set_exc_info",test_set_exc_info,METH_VARARGS},

‎Objects/exceptions.c‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3749,6 +3749,21 @@ _PyExc_Fini(PyInterpreterState *interp)
37493749
_PyExc_FiniTypes(interp);
37503750
}
37513751

3752+
int
3753+
_PyException_AddNote(PyObject*exc,PyObject*note)
3754+
{
3755+
if (!PyExceptionInstance_Check(exc)) {
3756+
PyErr_Format(PyExc_TypeError,
3757+
"exc must be an exception, not '%s'",
3758+
Py_TYPE(exc)->tp_name);
3759+
return-1;
3760+
}
3761+
PyObject*r=BaseException_add_note(exc,note);
3762+
intres=r==NULL ?-1 :0;
3763+
Py_XDECREF(r);
3764+
returnres;
3765+
}
3766+
37523767
/* Helper to do the equivalent of "raise X from Y" in C, but always using
37533768
* the current exception rather than passing one in.
37543769
*

‎Python/errors.c‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,28 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
135135
returnexc_info;
136136
}
137137

138+
staticPyObject*
139+
get_normalization_failure_note(PyThreadState*tstate,PyObject*exception,PyObject*value)
140+
{
141+
PyObject*args=PyObject_Repr(value);
142+
if (args==NULL) {
143+
_PyErr_Clear(tstate);
144+
args=PyUnicode_FromFormat("<unknown>");
145+
}
146+
PyObject*note;
147+
constchar*tpname= ((PyTypeObject*)exception)->tp_name;
148+
if (args==NULL) {
149+
_PyErr_Clear(tstate);
150+
note=PyUnicode_FromFormat("Normalization failed: type=%s",tpname);
151+
}
152+
else {
153+
note=PyUnicode_FromFormat("Normalization failed: type=%s args=%S",
154+
tpname,args);
155+
Py_DECREF(args);
156+
}
157+
returnnote;
158+
}
159+
138160
void
139161
_PyErr_SetObject(PyThreadState*tstate,PyObject*exception,PyObject*value)
140162
{
@@ -160,19 +182,27 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value)
160182
Py_XINCREF(value);
161183
if (!is_subclass) {
162184
/* We must normalize the value right now */
163-
PyObject*fixed_value;
164185

165186
/* Issue #23571: functions must not be called with an
166187
exception set */
167188
_PyErr_Clear(tstate);
168189

169-
fixed_value=_PyErr_CreateException(exception,value);
170-
Py_XDECREF(value);
190+
PyObject*fixed_value=_PyErr_CreateException(exception,value);
171191
if (fixed_value==NULL) {
192+
PyObject*exc=_PyErr_GetRaisedException(tstate);
193+
assert(PyExceptionInstance_Check(exc));
194+
195+
PyObject*note=get_normalization_failure_note(tstate,exception,value);
196+
Py_XDECREF(value);
197+
if (note!=NULL) {
198+
/* ignore errors in _PyException_AddNote - they will be overwritten below */
199+
_PyException_AddNote(exc,note);
200+
Py_DECREF(note);
201+
}
202+
_PyErr_SetRaisedException(tstate,exc);
172203
return;
173204
}
174-
175-
value=fixed_value;
205+
Py_XSETREF(value,fixed_value);
176206
}
177207

178208
exc_value=_PyErr_GetTopmostException(tstate)->exc_value;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp