@@ -41,19 +41,30 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
4141 return NULL ;
4242 /* the dict is created on the fly in PyObject_GenericSetAttr */
4343 self -> dict = NULL ;
44+ self -> kwargs = NULL ;
4445 self -> traceback = self -> cause = self -> context = NULL ;
4546 self -> suppress_context = 0 ;
4647
4748 if (args ) {
4849 self -> args = args ;
4950 Py_INCREF (args );
50- return (PyObject * )self ;
51+ } else {
52+ self -> args = PyTuple_New (2 );
53+ if (!self -> args ) {
54+ Py_DECREF (self );
55+ return NULL ;
56+ }
5157 }
5258
53- self -> args = PyTuple_New (0 );
54- if (!self -> args ) {
55- Py_DECREF (self );
56- return NULL ;
59+ if (kwds ) {
60+ self -> kwargs = kwds ;
61+ Py_INCREF (kwds );
62+ } else {
63+ self -> kwargs = PyDict_New ();
64+ if (!self -> kwargs ) {
65+ Py_DECREF (self );
66+ return NULL ;
67+ }
5768 }
5869
5970 return (PyObject * )self ;
@@ -76,6 +87,7 @@ BaseException_clear(PyBaseExceptionObject *self)
7687{
7788 Py_CLEAR (self -> dict );
7889 Py_CLEAR (self -> args );
90+ Py_CLEAR (self -> kwargs );
7991 Py_CLEAR (self -> traceback );
8092 Py_CLEAR (self -> cause );
8193 Py_CLEAR (self -> context );
@@ -95,6 +107,7 @@ BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg)
95107{
96108 Py_VISIT (self -> dict );
97109 Py_VISIT (self -> args );
110+ Py_VISIT (self -> kwargs );
98111 Py_VISIT (self -> traceback );
99112 Py_VISIT (self -> cause );
100113 Py_VISIT (self -> context );
@@ -118,21 +131,144 @@ static PyObject *
118131BaseException_repr (PyBaseExceptionObject * self )
119132{
120133 const char * name = _PyType_Name (Py_TYPE (self ));
121- if (PyTuple_GET_SIZE (self -> args ) == 1 )
122- return PyUnicode_FromFormat ("%s(%R)" , name ,
123- PyTuple_GET_ITEM (self -> args , 0 ));
124- else
125- return PyUnicode_FromFormat ("%s%R" , name , self -> args );
134+ PyObject * separator = NULL ;
135+ PyObject * args = NULL ;
136+ PyObject * kwargs = NULL ;
137+ PyObject * seq = NULL ;
138+ PyObject * repr = NULL ;
139+ PyObject * item = NULL ;
140+ PyObject * items = NULL ;
141+ PyObject * it = NULL ;
142+ PyObject * key = NULL ;
143+ PyObject * value = NULL ;
144+ PyObject * result = NULL ;
145+
146+ separator = PyUnicode_FromString (", " );
147+
148+ if (PyTuple_Check (self -> args )) {
149+ const Py_ssize_t len = PyTuple_Size (self -> args );
150+ seq = PyTuple_New (len );
151+ if (seq == NULL ) {
152+ goto fail ;
153+ }
154+ for (Py_ssize_t i = 0 ; i < len ; i ++ ) {
155+ repr = PyObject_Repr (PyTuple_GET_ITEM (self -> args , i ));
156+ if (repr == NULL ) {
157+ goto fail ;
158+ }
159+ PyTuple_SET_ITEM (seq , i , repr );
160+ }
161+ args = PyUnicode_Join (separator , seq );
162+ Py_DECREF (seq );
163+ }
164+
165+ if (PyMapping_Check (self -> kwargs )) {
166+ const Py_ssize_t len = PyMapping_Length (self -> kwargs );
167+ if (len == -1 ) {
168+ goto fail ;
169+ }
170+ seq = PyTuple_New (len );
171+ items = PyMapping_Items (self -> kwargs );
172+ if (seq == NULL || items == NULL ) {
173+ goto fail ;
174+ }
175+ it = PyObject_GetIter (items );
176+ if (it == NULL ) {
177+ goto fail ;
178+ }
179+ Py_ssize_t i = 0 ;
180+ while ((item = PyIter_Next (it )) != NULL ) {
181+ if (!PyTuple_Check (item ) || PyTuple_GET_SIZE (item ) != 2 ) {
182+ PyErr_SetString (PyExc_ValueError , "items must return 2-tuples" );
183+ goto fail ;
184+ }
185+ key = PyTuple_GET_ITEM (item , 0 );
186+ value = PyTuple_GET_ITEM (item , 1 );
187+ PyTuple_SET_ITEM (seq , i , PyUnicode_FromFormat ("%S=%R" , key , value ));
188+ i ++ ;
189+ Py_DECREF (item );
190+ }
191+ kwargs = PyUnicode_Join (separator , seq );
192+ Py_DECREF (seq );
193+ Py_DECREF (items );
194+ Py_DECREF (it );
195+ }
196+ Py_DECREF (separator );
197+
198+ if (args == NULL && kwargs == NULL ) {
199+ result = PyUnicode_FromFormat ("%s()" , name , kwargs );
200+ } else if (kwargs == NULL || PyUnicode_GET_LENGTH (kwargs ) == 0 ) {
201+ result = PyUnicode_FromFormat ("%s(%S)" , name , args );
202+ } else if (args == NULL || PyUnicode_GET_LENGTH (args ) == 0 ) {
203+ result = PyUnicode_FromFormat ("%s(%S)" , name , kwargs );
204+ } else {
205+ result = PyUnicode_FromFormat ("%s(%S, %S)" , name , args , kwargs );
206+ }
207+ Py_XDECREF (args );
208+ Py_XDECREF (kwargs );
209+ return result ;
210+
211+ fail :
212+ Py_XDECREF (separator );
213+ Py_XDECREF (args );
214+ Py_XDECREF (kwargs );
215+ Py_XDECREF (seq );
216+ Py_XDECREF (repr );
217+ Py_XDECREF (item );
218+ Py_XDECREF (items );
219+ Py_XDECREF (it );
220+ Py_XDECREF (key );
221+ Py_XDECREF (value );
222+ return NULL ;
126223}
127224
128225/* Pickling support */
129226static PyObject *
130227BaseException_reduce (PyBaseExceptionObject * self , PyObject * Py_UNUSED (ignored ))
131228{
132- if (self -> args && self -> dict )
133- return PyTuple_Pack (3 , Py_TYPE (self ), self -> args , self -> dict );
134- else
135- return PyTuple_Pack (2 , Py_TYPE (self ), self -> args );
229+ PyObject * functools ;
230+ PyObject * partial ;
231+ PyObject * constructor ;
232+ PyObject * args ;
233+ PyObject * result ;
234+ PyObject * * newargs ;
235+
236+ _Py_IDENTIFIER (partial );
237+ functools = PyImport_ImportModule ("functools" );
238+ if (!functools )
239+ return NULL ;
240+ partial = _PyObject_GetAttrId (functools , & PyId_partial );
241+ Py_DECREF (functools );
242+ if (!partial )
243+ return NULL ;
244+
245+ Py_ssize_t len = 1 ;
246+ if (PyTuple_Check (self -> args )) {
247+ len += PyTuple_GET_SIZE (self -> args );
248+ }
249+ newargs = PyMem_RawMalloc (len * sizeof (PyObject * ));
250+ newargs [0 ] = (PyObject * )Py_TYPE (self );
251+
252+ for (Py_ssize_t i = 1 ; i < len ; i ++ ) {
253+ newargs [i ] = PyTuple_GetItem (self -> args , i - 1 );
254+ }
255+ constructor = _PyObject_FastCallDict (partial , newargs , len , self -> kwargs );
256+ PyMem_RawFree (newargs );
257+
258+ Py_DECREF (partial );
259+
260+ args = PyTuple_New (0 );
261+ if (!args ) {
262+ return NULL ;
263+ }
264+ if (self -> args && self -> dict ){
265+ result = PyTuple_Pack (3 , constructor , args , self -> dict );
266+ } else {
267+ result = PyTuple_Pack (2 , constructor , args );
268+ }
269+ Py_DECREF (constructor );
270+ Py_DECREF (args );
271+ return result ;
136272}
137273
138274/*
@@ -206,6 +342,26 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUS
206342 return 0 ;
207343}
208344
345+ static PyObject *
346+ BaseException_get_kwargs (PyBaseExceptionObject * self , void * Py_UNUSED (ignored )) {
347+ if (self -> kwargs == NULL ) {
348+ Py_RETURN_NONE ;
349+ }
350+ Py_INCREF (self -> kwargs );
351+ return self -> kwargs ;
352+ }
353+
354+ static int
355+ BaseException_set_kwargs (PyBaseExceptionObject * self , PyObject * val , void * Py_UNUSED (ignored )) {
356+ if (val == NULL ) {
357+ PyErr_SetString (PyExc_TypeError , "kwargs may not be deleted" );
358+ return -1 ;
359+ }
360+ Py_INCREF (val );
361+ self -> kwargs = val ;
362+ return 0 ;
363+ }
364+
209365static PyObject *
210366BaseException_get_tb (PyBaseExceptionObject * self , void * Py_UNUSED (ignored ))
211367{
@@ -296,6 +452,7 @@ BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
296452static PyGetSetDef BaseException_getset [] = {
297453 {"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict },
298454 {"args" , (getter )BaseException_get_args , (setter )BaseException_set_args },
455+ {"kwargs" , (getter )BaseException_get_kwargs , (setter )BaseException_set_kwargs },
299456 {"__traceback__" , (getter )BaseException_get_tb , (setter )BaseException_set_tb },
300457 {"__context__" , BaseException_get_context ,
301458 BaseException_set_context , PyDoc_STR ("exception context" )},
0 commit comments