@@ -41,19 +41,30 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
41
41
return NULL ;
42
42
/* the dict is created on the fly in PyObject_GenericSetAttr */
43
43
self -> dict = NULL ;
44
+ self -> kwargs = NULL ;
44
45
self -> traceback = self -> cause = self -> context = NULL ;
45
46
self -> suppress_context = 0 ;
46
47
47
48
if (args ) {
48
49
self -> args = args ;
49
50
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
+ }
51
57
}
52
58
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
+ }
57
68
}
58
69
59
70
return (PyObject * )self ;
@@ -76,6 +87,7 @@ BaseException_clear(PyBaseExceptionObject *self)
76
87
{
77
88
Py_CLEAR (self -> dict );
78
89
Py_CLEAR (self -> args );
90
+ Py_CLEAR (self -> kwargs );
79
91
Py_CLEAR (self -> traceback );
80
92
Py_CLEAR (self -> cause );
81
93
Py_CLEAR (self -> context );
@@ -95,6 +107,7 @@ BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg)
95
107
{
96
108
Py_VISIT (self -> dict );
97
109
Py_VISIT (self -> args );
110
+ Py_VISIT (self -> kwargs );
98
111
Py_VISIT (self -> traceback );
99
112
Py_VISIT (self -> cause );
100
113
Py_VISIT (self -> context );
@@ -118,21 +131,144 @@ static PyObject *
118
131
BaseException_repr (PyBaseExceptionObject * self )
119
132
{
120
133
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 ;
126
223
}
127
224
128
225
/* Pickling support */
129
226
static PyObject *
130
227
BaseException_reduce (PyBaseExceptionObject * self , PyObject * Py_UNUSED (ignored ))
131
228
{
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 ;
136
272
}
137
273
138
274
/*
@@ -206,6 +342,26 @@ BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUS
206
342
return 0 ;
207
343
}
208
344
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
+
209
365
static PyObject *
210
366
BaseException_get_tb (PyBaseExceptionObject * self , void * Py_UNUSED (ignored ))
211
367
{
@@ -296,6 +452,7 @@ BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored))
296
452
static PyGetSetDef BaseException_getset [] = {
297
453
{"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict },
298
454
{"args" , (getter )BaseException_get_args , (setter )BaseException_set_args },
455
+ {"kwargs" , (getter )BaseException_get_kwargs , (setter )BaseException_set_kwargs },
299
456
{"__traceback__" , (getter )BaseException_get_tb , (setter )BaseException_set_tb },
300
457
{"__context__" , BaseException_get_context ,
301
458
BaseException_set_context , PyDoc_STR ("exception context" )},
0 commit comments