@@ -319,6 +319,7 @@ typedef struct PicklerObject {
319
319
objects to support self-referential objects
320
320
pickling. */
321
321
PyObject * pers_func ; /* persistent_id() method, can be NULL */
322
+ PyObject * dispatch_table ; /* private dispatch_table, can be NULL */
322
323
PyObject * arg ;
323
324
324
325
PyObject * write ; /* write() method of the output stream. */
@@ -764,6 +765,7 @@ _Pickler_New(void)
764
765
return NULL ;
765
766
766
767
self -> pers_func = NULL ;
768
+ self -> dispatch_table = NULL ;
767
769
self -> arg = NULL ;
768
770
self -> write = NULL ;
769
771
self -> proto = 0 ;
@@ -3176,17 +3178,24 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
3176
3178
/* XXX: This part needs some unit tests. */
3177
3179
3178
3180
/* Get a reduction callable, and call it. This may come from
3179
- * copyreg.dispatch_table, the object's __reduce_ex__ method,
3180
- * or the object's __reduce__ method.
3181
+ * self.dispatch_table, copyreg.dispatch_table, the object's
3182
+ * __reduce_ex__ method, or the object's __reduce__ method.
3181
3183
*/
3182
- reduce_func = PyDict_GetItem (dispatch_table , (PyObject * )type );
3184
+ if (self -> dispatch_table == NULL ) {
3185
+ reduce_func = PyDict_GetItem (dispatch_table , (PyObject * )type );
3186
+ /* PyDict_GetItem() unlike PyObject_GetItem() and
3187
+ PyObject_GetAttr() returns a borrowed ref */
3188
+ Py_XINCREF (reduce_func );
3189
+ } else {
3190
+ reduce_func = PyObject_GetItem (self -> dispatch_table , (PyObject * )type );
3191
+ if (reduce_func == NULL ) {
3192
+ if (PyErr_ExceptionMatches (PyExc_KeyError ))
3193
+ PyErr_Clear ();
3194
+ else
3195
+ goto error ;
3196
+ }
3197
+ }
3183
3198
if (reduce_func != NULL ) {
3184
- /* Here, the reference count of the reduce_func object returned by
3185
- PyDict_GetItem needs to be increased to be consistent with the one
3186
- returned by PyObject_GetAttr. This is allow us to blindly DECREF
3187
- reduce_func at the end of the save() routine.
3188
- */
3189
- Py_INCREF (reduce_func );
3190
3199
Py_INCREF (obj );
3191
3200
reduce_value = _Pickler_FastCall (self , reduce_func , obj );
3192
3201
}
@@ -3359,6 +3368,7 @@ Pickler_dealloc(PicklerObject *self)
3359
3368
Py_XDECREF (self -> output_buffer );
3360
3369
Py_XDECREF (self -> write );
3361
3370
Py_XDECREF (self -> pers_func );
3371
+ Py_XDECREF (self -> dispatch_table );
3362
3372
Py_XDECREF (self -> arg );
3363
3373
Py_XDECREF (self -> fast_memo );
3364
3374
@@ -3372,6 +3382,7 @@ Pickler_traverse(PicklerObject *self, visitproc visit, void *arg)
3372
3382
{
3373
3383
Py_VISIT (self -> write );
3374
3384
Py_VISIT (self -> pers_func );
3385
+ Py_VISIT (self -> dispatch_table );
3375
3386
Py_VISIT (self -> arg );
3376
3387
Py_VISIT (self -> fast_memo );
3377
3388
return 0 ;
@@ -3383,6 +3394,7 @@ Pickler_clear(PicklerObject *self)
3383
3394
Py_CLEAR (self -> output_buffer );
3384
3395
Py_CLEAR (self -> write );
3385
3396
Py_CLEAR (self -> pers_func );
3397
+ Py_CLEAR (self -> dispatch_table );
3386
3398
Py_CLEAR (self -> arg );
3387
3399
Py_CLEAR (self -> fast_memo );
3388
3400
@@ -3427,6 +3439,7 @@ Pickler_init(PicklerObject *self, PyObject *args, PyObject *kwds)
3427
3439
PyObject * proto_obj = NULL ;
3428
3440
PyObject * fix_imports = Py_True ;
3429
3441
_Py_IDENTIFIER (persistent_id );
3442
+ _Py_IDENTIFIER (dispatch_table );
3430
3443
3431
3444
if (!PyArg_ParseTupleAndKeywords (args , kwds , "O|OO:Pickler" ,
3432
3445
kwlist , & file , & proto_obj , & fix_imports ))
@@ -3468,6 +3481,13 @@ Pickler_init(PicklerObject *self, PyObject *args, PyObject *kwds)
3468
3481
if (self -> pers_func == NULL )
3469
3482
return -1 ;
3470
3483
}
3484
+ self -> dispatch_table = NULL ;
3485
+ if (_PyObject_HasAttrId ((PyObject * )self , & PyId_dispatch_table )) {
3486
+ self -> dispatch_table = _PyObject_GetAttrId ((PyObject * )self ,
3487
+ & PyId_dispatch_table );
3488
+ if (self -> dispatch_table == NULL )
3489
+ return -1 ;
3490
+ }
3471
3491
return 0 ;
3472
3492
}
3473
3493
@@ -3749,6 +3769,7 @@ Pickler_set_persid(PicklerObject *self, PyObject *value)
3749
3769
static PyMemberDef Pickler_members [] = {
3750
3770
{"bin" , T_INT , offsetof(PicklerObject , bin )},
3751
3771
{"fast" , T_INT , offsetof(PicklerObject , fast )},
3772
+ {"dispatch_table" , T_OBJECT_EX , offsetof(PicklerObject , dispatch_table )},
3752
3773
{NULL }
3753
3774
};
3754
3775
0 commit comments