diff options
author | Charles Machalow <csm10495@gmail.com> | 2023-05-12 20:33:23 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-12 20:33:23 (GMT) |
commit | 79b17f2cf0e1a2688bd91df02744f461835c4253 (patch) | |
tree | cb576467384cd2f4f2080184472e806af26b37f9 /Objects/exceptions.c | |
parent | cf720acfcbd8c9c25a706a4b6df136465a803992 (diff) | |
download | cpython-79b17f2cf0e1a2688bd91df02744f461835c4253.zip cpython-79b17f2cf0e1a2688bd91df02744f461835c4253.tar.gz cpython-79b17f2cf0e1a2688bd91df02744f461835c4253.tar.bz2 |
gh-103333: Pickle the keyword attributes of AttributeError (#103352)
* Pickle the `name` and `args` attributes of AttributeError when present.
Co-authored-by: Gregory P. Smith <greg@krypto.org>
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
Diffstat (limited to 'Objects/exceptions.c')
-rw-r--r-- | Objects/exceptions.c | 44 |
1 files changed, 43 insertions, 1 deletions
diff --git a/Objects/exceptions.c b/Objects/exceptions.c index ba5ee29..59c63f4 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -2287,6 +2287,46 @@ AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } +/* Pickling support */ +static PyObject * +AttributeError_getstate(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *dict = ((PyAttributeErrorObject *)self)->dict; + if (self->name || self->args) { + dict = dict ? PyDict_Copy(dict) : PyDict_New(); + if (dict == NULL) { + return NULL; + } + if (self->name && PyDict_SetItemString(dict, "name", self->name) < 0) { + Py_DECREF(dict); + return NULL; + } + /* We specifically are not pickling the obj attribute since there are many + cases where it is unlikely to be picklable. See GH-103352. + */ + if (self->args && PyDict_SetItemString(dict, "args", self->args) < 0) { + Py_DECREF(dict); + return NULL; + } + return dict; + } + else if (dict) { + return Py_NewRef(dict); + } + Py_RETURN_NONE; +} + +static PyObject * +AttributeError_reduce(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *state = AttributeError_getstate(self, NULL); + if (state == NULL) { + return NULL; + } + + return PyTuple_Pack(3, Py_TYPE(self), self->args, state); +} + static PyMemberDef AttributeError_members[] = { {"name", T_OBJECT, offsetof(PyAttributeErrorObject, name), 0, PyDoc_STR("attribute name")}, {"obj", T_OBJECT, offsetof(PyAttributeErrorObject, obj), 0, PyDoc_STR("object")}, @@ -2294,7 +2334,9 @@ static PyMemberDef AttributeError_members[] = { }; static PyMethodDef AttributeError_methods[] = { - {NULL} /* Sentinel */ + {"__getstate__", (PyCFunction)AttributeError_getstate, METH_NOARGS}, + {"__reduce__", (PyCFunction)AttributeError_reduce, METH_NOARGS }, + {NULL} }; ComplexExtendsException(PyExc_Exception, AttributeError, |