bpo-29998: Pickling and copying ImportError now preserves name and path (#1010)

attributes.
This commit is contained in:
Serhiy Storchaka 2017-04-08 09:55:07 +03:00 committed by GitHub
parent b879fe82e7
commit b785396ab4
3 changed files with 71 additions and 0 deletions

View file

@ -1,5 +1,6 @@
# Python test set -- part 5, built-in exceptions
import copy
import os
import sys
import unittest
@ -1126,6 +1127,25 @@ def test_non_str_argument(self):
exc = ImportError(arg)
self.assertEqual(str(arg), str(exc))
def test_copy_pickle(self):
for kwargs in (dict(),
dict(name='somename'),
dict(path='somepath'),
dict(name='somename', path='somepath')):
orig = ImportError('test', **kwargs)
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
exc = pickle.loads(pickle.dumps(orig, proto))
self.assertEqual(exc.args, ('test',))
self.assertEqual(exc.msg, 'test')
self.assertEqual(exc.name, orig.name)
self.assertEqual(exc.path, orig.path)
for c in copy.copy, copy.deepcopy:
exc = c(orig)
self.assertEqual(exc.args, ('test',))
self.assertEqual(exc.msg, 'test')
self.assertEqual(exc.name, orig.name)
self.assertEqual(exc.path, orig.path)
if __name__ == '__main__':
unittest.main()

View file

@ -307,6 +307,9 @@ Extension Modules
Library
-------
- bpo-29998: Pickling and copying ImportError now preserves name and path
attributes.
- bpo-29962: Add math.remainder operation, implementing remainder
as specified in IEEE 754.

View file

@ -682,6 +682,53 @@ ImportError_str(PyImportErrorObject *self)
}
}
static PyObject *
ImportError_getstate(PyImportErrorObject *self)
{
PyObject *dict = ((PyBaseExceptionObject *)self)->dict;
if (self->name || self->path) {
_Py_IDENTIFIER(name);
_Py_IDENTIFIER(path);
dict = dict ? PyDict_Copy(dict) : PyDict_New();
if (dict == NULL)
return NULL;
if (self->name && _PyDict_SetItemId(dict, &PyId_name, self->name) < 0) {
Py_DECREF(dict);
return NULL;
}
if (self->path && _PyDict_SetItemId(dict, &PyId_path, self->path) < 0) {
Py_DECREF(dict);
return NULL;
}
return dict;
}
else if (dict) {
Py_INCREF(dict);
return dict;
}
else {
Py_RETURN_NONE;
}
}
/* Pickling support */
static PyObject *
ImportError_reduce(PyImportErrorObject *self)
{
PyObject *res;
PyObject *args;
PyObject *state = ImportError_getstate(self);
if (state == NULL)
return NULL;
args = ((PyBaseExceptionObject *)self)->args;
if (state == Py_None)
res = PyTuple_Pack(2, Py_TYPE(self), args);
else
res = PyTuple_Pack(3, Py_TYPE(self), args, state);
Py_DECREF(state);
return res;
}
static PyMemberDef ImportError_members[] = {
{"msg", T_OBJECT, offsetof(PyImportErrorObject, msg), 0,
PyDoc_STR("exception message")},
@ -693,6 +740,7 @@ static PyMemberDef ImportError_members[] = {
};
static PyMethodDef ImportError_methods[] = {
{"__reduce__", (PyCFunction)ImportError_reduce, METH_NOARGS},
{NULL}
};