/* * New exceptions.c written in Iceland by Richard Jones and Georg Brandl. * * Thanks go to Tim Peters and Michael Hudson for debugging. */ #define PY_SSIZE_T_CLEAN #include #include #include "pycore_ceval.h" // _Py_EnterRecursiveCall #include "pycore_exceptions.h" // struct _Py_exc_state #include "pycore_initconfig.h" #include "pycore_object.h" #include "structmember.h" // PyMemberDef #include "osdefs.h" // SEP /* Compatibility aliases */ PyObject *PyExc_EnvironmentError = NULL; // borrowed ref PyObject *PyExc_IOError = NULL; // borrowed ref #ifdef MS_WINDOWS PyObject *PyExc_WindowsError = NULL; // borrowed ref #endif static struct _Py_exc_state* get_exc_state(void) { PyInterpreterState *interp = _PyInterpreterState_GET(); return &interp->exc_state; } /* NOTE: If the exception class hierarchy changes, don't forget to update * Lib/test/exception_hierarchy.txt */ /* * BaseException */ static PyObject * BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyBaseExceptionObject *self; self = (PyBaseExceptionObject *)type->tp_alloc(type, 0); if (!self) return NULL; /* the dict is created on the fly in PyObject_GenericSetAttr */ self->dict = NULL; self->notes = NULL; self->traceback = self->cause = self->context = NULL; self->suppress_context = 0; if (args) { self->args = args; Py_INCREF(args); return (PyObject *)self; } self->args = PyTuple_New(0); if (!self->args) { Py_DECREF(self); return NULL; } return (PyObject *)self; } static int BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) { if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1; Py_INCREF(args); Py_XSETREF(self->args, args); return 0; } static int BaseException_clear(PyBaseExceptionObject *self) { Py_CLEAR(self->dict); Py_CLEAR(self->args); Py_CLEAR(self->notes); Py_CLEAR(self->traceback); Py_CLEAR(self->cause); Py_CLEAR(self->context); return 0; } static void BaseException_dealloc(PyBaseExceptionObject *self) { PyObject_GC_UnTrack(self); // bpo-44348: The trashcan mechanism prevents stack overflow when deleting // long chains of exceptions. For example, exceptions can be chained // through the __context__ attributes or the __traceback__ attribute. Py_TRASHCAN_BEGIN(self, BaseException_dealloc) BaseException_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } static int BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg) { Py_VISIT(self->dict); Py_VISIT(self->args); Py_VISIT(self->notes); Py_VISIT(self->traceback); Py_VISIT(self->cause); Py_VISIT(self->context); return 0; } static PyObject * BaseException_str(PyBaseExceptionObject *self) { switch (PyTuple_GET_SIZE(self->args)) { case 0: return PyUnicode_FromString(""); case 1: return PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); default: return PyObject_Str(self->args); } } static PyObject * BaseException_repr(PyBaseExceptionObject *self) { const char *name = _PyType_Name(Py_TYPE(self)); if (PyTuple_GET_SIZE(self->args) == 1) return PyUnicode_FromFormat("%s(%R)", name, PyTuple_GET_ITEM(self->args, 0)); else return PyUnicode_FromFormat("%s%R", name, self->args); } /* Pickling support */ static PyObject * BaseException_reduce(PyBaseExceptionObject *self, PyObject *Py_UNUSED(ignored)) { if (self->args && self->dict) return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); else return PyTuple_Pack(2, Py_TYPE(self), self->args); } /* * Needed for backward compatibility, since exceptions used to store * all their attributes in the __dict__. Code is taken from cPickle's * load_build function. */ static PyObject * BaseException_setstate(PyObject *self, PyObject *state) { PyObject *d_key, *d_value; Py_ssize_t i = 0; if (state != Py_None) { if (!PyDict_Check(state)) { PyErr_SetString(PyExc_TypeError, "state is not a dictionary"); return NULL; } while (PyDict_Next(state, &i, &d_key, &d_value)) { if (PyObject_SetAttr(self, d_key, d_value) < 0) return NULL; } } Py_RETURN_NONE; } static PyObject * BaseException_with_traceback(PyObject *self, PyObject *tb) { if (PyException_SetTraceback(self, tb)) return NULL; Py_INCREF(self); return self; } PyDoc_STRVAR(with_traceback_doc, "Exception.with_traceback(tb) --\n\ set self.__traceback__ to tb and return self."); static inline PyBaseExceptionObject* _PyBaseExceptionObject_cast(PyObject *exc) { assert(PyExceptionInstance_Check(exc)); return (PyBaseExceptionObject *)exc; } static PyObject * BaseException_add_note(PyObject *self, PyObject *note) { if (!PyUnicode_Check(note)) { PyErr_Format(PyExc_TypeError, "note must be a str, not '%s'", Py_TYPE(note)->tp_name); return NULL; } if (!PyObject_HasAttr(self, &_Py_ID(__notes__))) { PyObject *new_notes = PyList_New(0); if (new_notes == NULL) { return NULL; } if (PyObject_SetAttr(self, &_Py_ID(__notes__), new_notes) < 0) { Py_DECREF(new_notes); return NULL; } Py_DECREF(new_notes); } PyObject *notes = PyObject_GetAttr(self, &_Py_ID(__notes__)); if (notes == NULL) { return NULL; } if (!PyList_Check(notes)) { Py_DECREF(notes); PyErr_SetString(PyExc_TypeError, "Cannot add note: __notes__ is not a list"); return NULL; } if (PyList_Append(notes, note) < 0) { Py_DECREF(notes); return NULL; } Py_DECREF(notes); Py_RETURN_NONE; } PyDoc_STRVAR(add_note_doc, "Exception.add_note(note) --\n\ add a note to the exception"); static PyMethodDef BaseException_methods[] = { {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, {"with_traceback", (PyCFunction)BaseException_with_traceback, METH_O, with_traceback_doc}, {"add_note", (PyCFunction)BaseException_add_note, METH_O, add_note_doc}, {NULL, NULL, 0, NULL}, }; static PyObject * BaseException_get_args(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) { if (self->args == NULL) { Py_RETURN_NONE; } Py_INCREF(self->args); return self->args; } static int BaseException_set_args(PyBaseExceptionObject *self, PyObject *val, void *Py_UNUSED(ignored)) { PyObject *seq; if (val == NULL) { PyErr_SetString(PyExc_TypeError, "args may not be deleted"); return -1; } seq = PySequence_Tuple(val); if (!seq) return -1; Py_XSETREF(self->args, seq); return 0; } static PyObject * BaseException_get_tb(PyBaseExceptionObject *self, void *Py_UNUSED(ignored)) { if (self->traceback == NULL) { Py_RETURN_NONE; } Py_INCREF(self->traceback); return self->traceback; } static int BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(ignored)) { if (tb == NULL) { PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted"); return -1; } else if (!(tb == Py_None || PyTraceBack_Check(tb))) { PyErr_SetString(PyExc_TypeError, "__traceback__ must be a traceback or None"); return -1; } Py_INCREF(tb); Py_XSETREF(self->traceback, tb); return 0; } static PyObject * BaseException_get_context(PyObject *self, void *Py_UNUSED(ignored)) { PyObject *res = PyException_GetContext(self); if (res) return res; /* new reference already returned above */ Py_RETURN_NONE; } static int BaseException_set_context(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) { if (arg == NULL) { PyErr_SetString(PyExc_TypeError, "__context__ may not be deleted"); return -1; } else if (arg == Py_None) { arg = NULL; } else if (!PyExceptionInstance_Check(arg)) { PyErr_SetString(PyExc_TypeError, "exception context must be None " "or derive from BaseException"); return -1; } else { /* PyException_SetContext steals this reference */ Py_INCREF(arg); } PyException_SetContext(self, arg); return 0; } static PyObject * BaseException_get_cause(PyObject *self, void *Py_UNUSED(ignored)) { PyObject *res = PyException_GetCause(self); if (res) return res; /* new reference already returned above */ Py_RETURN_NONE; } static int BaseException_set_cause(PyObject *self, PyObject *arg, void *Py_UNUSED(ignored)) { if (arg == NULL) { PyErr_SetString(PyExc_TypeError, "__cause__ may not be deleted"); return -1; } else if (arg == Py_None) { arg = NULL; } else if (!PyExceptionInstance_Check(arg)) { PyErr_SetString(PyExc_TypeError, "exception cause must be None " "or derive from BaseException"); return -1; } else { /* PyException_SetCause steals this reference */ Py_INCREF(arg); } PyException_SetCause(self, arg); return 0; } static PyGetSetDef BaseException_getset[] = { {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb}, {"__context__", BaseException_get_context, BaseException_set_context, PyDoc_STR("exception context")}, {"__cause__", BaseException_get_cause, BaseException_set_cause, PyDoc_STR("exception cause")}, {NULL}, }; PyObject * PyException_GetTraceback(PyObject *self) { PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); Py_XINCREF(base_self->traceback); return base_self->traceback; } int PyException_SetTraceback(PyObject *self, PyObject *tb) { return BaseException_set_tb(_PyBaseExceptionObject_cast(self), tb, NULL); } PyObject * PyException_GetCause(PyObject *self) { PyObject *cause = _PyBaseExceptionObject_cast(self)->cause; Py_XINCREF(cause); return cause; } /* Steals a reference to cause */ void PyException_SetCause(PyObject *self, PyObject *cause) { PyBaseExceptionObject *base_self = _PyBaseExceptionObject_cast(self); base_self->suppress_context = 1; Py_XSETREF(base_self->cause, cause); } PyObject * PyException_GetContext(PyObject *self) { PyObject *context = _PyBaseExceptionObject_cast(self)->context; Py_XINCREF(context); return context; } /* Steals a reference to context */ void PyException_SetContext(PyObject *self, PyObject *context) { Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context); } const char * PyExceptionClass_Name(PyObject *ob) { assert(PyExceptionClass_Check(ob)); return ((PyTypeObject*)ob)->tp_name; } static struct PyMemberDef BaseException_members[] = { {"__suppress_context__", T_BOOL, offsetof(PyBaseExceptionObject, suppress_context)}, {NULL} }; static PyTypeObject _PyExc_BaseException = { PyVarObject_HEAD_INIT(NULL, 0) "BaseException", /*tp_name*/ sizeof(PyBaseExceptionObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ (destructor)BaseException_dealloc, /*tp_dealloc*/ 0, /*tp_vectorcall_offset*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_as_async*/ (reprfunc)BaseException_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash */ 0, /*tp_call*/ (reprfunc)BaseException_str, /*tp_str*/ PyObject_GenericGetAttr, /*tp_getattro*/ PyObject_GenericSetAttr, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASE_EXC_SUBCLASS, /*tp_flags*/ PyDoc_STR("Common base class for all exceptions"), /* tp_doc */ (traverseproc)BaseException_traverse, /* tp_traverse */ (inquiry)BaseException_clear, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ BaseException_methods, /* tp_methods */ BaseException_members, /* tp_members */ BaseException_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(PyBaseExceptionObject, dict), /* tp_dictoffset */ (initproc)BaseException_init, /* tp_init */ 0, /* tp_alloc */ BaseException_new, /* tp_new */ }; /* the CPython API expects exceptions to be (PyObject *) - both a hold-over from the previous implementation and also allowing Python objects to be used in the API */ PyObject *PyExc_BaseException = (PyObject *)&_PyExc_BaseException; /* note these macros omit the last semicolon so the macro invocation may * include it and not look strange. */ #define SimpleExtendsException(EXCBASE, EXCNAME, EXCDOC) \ static PyTypeObject _PyExc_ ## EXCNAME = { \ PyVarObject_HEAD_INIT(NULL, 0) \ # EXCNAME, \ sizeof(PyBaseExceptionObject), \ 0, (destructor)BaseException_dealloc, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \ (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ 0, 0, 0, offsetof(PyBaseExceptionObject, dict), \ (initproc)BaseException_init, 0, BaseException_new,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME #define MiddlingExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDOC) \ static PyTypeObject _PyExc_ ## EXCNAME = { \ PyVarObject_HEAD_INIT(NULL, 0) \ # EXCNAME, \ sizeof(Py ## EXCSTORE ## Object), \ 0, (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ 0, 0, 0, 0, 0, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ (initproc)EXCSTORE ## _init, 0, 0, \ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME #define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCNEW, \ EXCMETHODS, EXCMEMBERS, EXCGETSET, \ EXCSTR, EXCDOC) \ static PyTypeObject _PyExc_ ## EXCNAME = { \ PyVarObject_HEAD_INIT(NULL, 0) \ # EXCNAME, \ sizeof(Py ## EXCSTORE ## Object), 0, \ (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ (reprfunc)EXCSTR, 0, 0, 0, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \ EXCMEMBERS, EXCGETSET, &_ ## EXCBASE, \ 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ (initproc)EXCSTORE ## _init, 0, EXCNEW,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME /* * Exception extends BaseException */ SimpleExtendsException(PyExc_BaseException, Exception, "Common base class for all non-exit exceptions."); /* * TypeError extends Exception */ SimpleExtendsException(PyExc_Exception, TypeError, "Inappropriate argument type."); /* * StopAsyncIteration extends Exception */ SimpleExtendsException(PyExc_Exception, StopAsyncIteration, "Signal the end from iterator.__anext__()."); /* * StopIteration extends Exception */ static PyMemberDef StopIteration_members[] = { {"value", T_OBJECT, offsetof(PyStopIterationObject, value), 0, PyDoc_STR("generator return value")}, {NULL} /* Sentinel */ }; static int StopIteration_init(PyStopIterationObject *self, PyObject *args, PyObject *kwds) { Py_ssize_t size = PyTuple_GET_SIZE(args); PyObject *value; if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; Py_CLEAR(self->value); if (size > 0) value = PyTuple_GET_ITEM(args, 0); else value = Py_None; Py_INCREF(value); self->value = value; return 0; } static int StopIteration_clear(PyStopIterationObject *self) { Py_CLEAR(self->value); return BaseException_clear((PyBaseExceptionObject *)self); } static void StopIteration_dealloc(PyStopIterationObject *self) { PyObject_GC_UnTrack(self); StopIteration_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int StopIteration_traverse(PyStopIterationObject *self, visitproc visit, void *arg) { Py_VISIT(self->value); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } ComplexExtendsException(PyExc_Exception, StopIteration, StopIteration, 0, 0, StopIteration_members, 0, 0, "Signal the end from iterator.__next__()."); /* * GeneratorExit extends BaseException */ SimpleExtendsException(PyExc_BaseException, GeneratorExit, "Request that a generator exit."); /* * SystemExit extends BaseException */ static int SystemExit_init(PySystemExitObject *self, PyObject *args, PyObject *kwds) { Py_ssize_t size = PyTuple_GET_SIZE(args); if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; if (size == 0) return 0; if (size == 1) { Py_INCREF(PyTuple_GET_ITEM(args, 0)); Py_XSETREF(self->code, PyTuple_GET_ITEM(args, 0)); } else { /* size > 1 */ Py_INCREF(args); Py_XSETREF(self->code, args); } return 0; } static int SystemExit_clear(PySystemExitObject *self) { Py_CLEAR(self->code); return BaseException_clear((PyBaseExceptionObject *)self); } static void SystemExit_dealloc(PySystemExitObject *self) { _PyObject_GC_UNTRACK(self); SystemExit_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int SystemExit_traverse(PySystemExitObject *self, visitproc visit, void *arg) { Py_VISIT(self->code); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyMemberDef SystemExit_members[] = { {"code", T_OBJECT, offsetof(PySystemExitObject, code), 0, PyDoc_STR("exception code")}, {NULL} /* Sentinel */ }; ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, 0, 0, SystemExit_members, 0, 0, "Request to exit from the interpreter."); /* * BaseExceptionGroup extends BaseException * ExceptionGroup extends BaseExceptionGroup and Exception */ static inline PyBaseExceptionGroupObject* _PyBaseExceptionGroupObject_cast(PyObject *exc) { assert(_PyBaseExceptionGroup_Check(exc)); return (PyBaseExceptionGroupObject *)exc; } static PyObject * BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { struct _Py_exc_state *state = get_exc_state(); PyTypeObject *PyExc_ExceptionGroup = (PyTypeObject*)state->PyExc_ExceptionGroup; PyObject *message = NULL; PyObject *exceptions = NULL; if (!PyArg_ParseTuple(args, "UO:BaseExceptionGroup.__new__", &message, &exceptions)) { return NULL; } if (!PySequence_Check(exceptions)) { PyErr_SetString( PyExc_TypeError, "second argument (exceptions) must be a sequence"); return NULL; } exceptions = PySequence_Tuple(exceptions); if (!exceptions) { return NULL; } /* We are now holding a ref to the exceptions tuple */ Py_ssize_t numexcs = PyTuple_GET_SIZE(exceptions); if (numexcs == 0) { PyErr_SetString( PyExc_ValueError, "second argument (exceptions) must be a non-empty sequence"); goto error; } bool nested_base_exceptions = false; for (Py_ssize_t i = 0; i < numexcs; i++) { PyObject *exc = PyTuple_GET_ITEM(exceptions, i); if (!exc) { goto error; } if (!PyExceptionInstance_Check(exc)) { PyErr_Format( PyExc_ValueError, "Item %d of second argument (exceptions) is not an exception", i); goto error; } int is_nonbase_exception = PyObject_IsInstance(exc, PyExc_Exception); if (is_nonbase_exception < 0) { goto error; } else if (is_nonbase_exception == 0) { nested_base_exceptions = true; } } PyTypeObject *cls = type; if (cls == PyExc_ExceptionGroup) { if (nested_base_exceptions) { PyErr_SetString(PyExc_TypeError, "Cannot nest BaseExceptions in an ExceptionGroup"); goto error; } } else if (cls == (PyTypeObject*)PyExc_BaseExceptionGroup) { if (!nested_base_exceptions) { /* All nested exceptions are Exception subclasses, * wrap them in an ExceptionGroup */ cls = PyExc_ExceptionGroup; } } else { /* Do nothing - we don't interfere with subclasses */ } if (!cls) { /* Don't crash during interpreter shutdown * (PyExc_ExceptionGroup may have been cleared) */ cls = (PyTypeObject*)PyExc_BaseExceptionGroup; } PyBaseExceptionGroupObject *self = _PyBaseExceptionGroupObject_cast(BaseException_new(cls, args, kwds)); if (!self) { goto error; } self->msg = Py_NewRef(message); self->excs = exceptions; return (PyObject*)self; error: Py_DECREF(exceptions); return NULL; } PyObject * _PyExc_CreateExceptionGroup(const char *msg_str, PyObject *excs) { PyObject *msg = PyUnicode_FromString(msg_str); if (!msg) { return NULL; } PyObject *args = PyTuple_Pack(2, msg, excs); Py_DECREF(msg); if (!args) { return NULL; } PyObject *result = PyObject_CallObject(PyExc_BaseExceptionGroup, args); Py_DECREF(args); return result; } static int BaseExceptionGroup_init(PyBaseExceptionGroupObject *self, PyObject *args, PyObject *kwds) { if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) { return -1; } if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) { return -1; } return 0; } static int BaseExceptionGroup_clear(PyBaseExceptionGroupObject *self) { Py_CLEAR(self->msg); Py_CLEAR(self->excs); return BaseException_clear((PyBaseExceptionObject *)self); } static void BaseExceptionGroup_dealloc(PyBaseExceptionGroupObject *self) { _PyObject_GC_UNTRACK(self); BaseExceptionGroup_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int BaseExceptionGroup_traverse(PyBaseExceptionGroupObject *self, visitproc visit, void *arg) { Py_VISIT(self->msg); Py_VISIT(self->excs); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyObject * BaseExceptionGroup_str(PyBaseExceptionGroupObject *self) { assert(self->msg); assert(PyUnicode_Check(self->msg)); assert(PyTuple_CheckExact(self->excs)); Py_ssize_t num_excs = PyTuple_Size(self->excs); return PyUnicode_FromFormat( "%S (%zd sub-exception%s)", self->msg, num_excs, num_excs > 1 ? "s" : ""); } static PyObject * BaseExceptionGroup_derive(PyObject *self_, PyObject *args) { PyBaseExceptionGroupObject *self = _PyBaseExceptionGroupObject_cast(self_); PyObject *excs = NULL; if (!PyArg_ParseTuple(args, "O", &excs)) { return NULL; } PyObject *init_args = PyTuple_Pack(2, self->msg, excs); if (!init_args) { return NULL; } PyObject *eg = PyObject_CallObject( PyExc_BaseExceptionGroup, init_args); Py_DECREF(init_args); return eg; } static int exceptiongroup_subset( PyBaseExceptionGroupObject *_orig, PyObject *excs, PyObject **result) { /* Sets *result to an ExceptionGroup wrapping excs with metadata from * _orig. If excs is empty, sets *result to NULL. * Returns 0 on success and -1 on error. * This function is used by split() to construct the match/rest parts, * so excs is the matching or non-matching sub-sequence of orig->excs * (this function does not verify that it is a subsequence). */ PyObject *orig = (PyObject *)_orig; *result = NULL; Py_ssize_t num_excs = PySequence_Size(excs); if (num_excs < 0) { return -1; } else if (num_excs == 0) { return 0; } PyObject *eg = PyObject_CallMethod( orig, "derive", "(O)", excs); if (!eg) { return -1; } if (!_PyBaseExceptionGroup_Check(eg)) { PyErr_SetString(PyExc_TypeError, "derive must return an instance of BaseExceptionGroup"); goto error; } /* Now we hold a reference to the new eg */ PyObject *tb = PyException_GetTraceback(orig); if (tb) { int res = PyException_SetTraceback(eg, tb); Py_DECREF(tb); if (res < 0) { goto error; } } PyException_SetContext(eg, PyException_GetContext(orig)); PyException_SetCause(eg, PyException_GetCause(orig)); if (PyObject_HasAttr(orig, &_Py_ID(__notes__))) { PyObject *notes = PyObject_GetAttr(orig, &_Py_ID(__notes__)); if (notes == NULL) { goto error; } if (PySequence_Check(notes)) { /* Make a copy so the parts have independent notes lists. */ PyObject *notes_copy = PySequence_List(notes); Py_DECREF(notes); if (notes_copy == NULL) { goto error; } int res = PyObject_SetAttr(eg, &_Py_ID(__notes__), notes_copy); Py_DECREF(notes_copy); if (res < 0) { goto error; } } else { /* __notes__ is supposed to be a list, and split() is not a * good place to report earlier user errors, so we just ignore * notes of non-sequence type. */ Py_DECREF(notes); } } *result = eg; return 0; error: Py_DECREF(eg); return -1; } typedef enum { /* Exception type or tuple of thereof */ EXCEPTION_GROUP_MATCH_BY_TYPE = 0, /* A PyFunction returning True for matching exceptions */ EXCEPTION_GROUP_MATCH_BY_PREDICATE = 1, /* A set of leaf exceptions to include in the result. * This matcher type is used internally by the interpreter * to construct reraised exceptions. */ EXCEPTION_GROUP_MATCH_INSTANCES = 2 } _exceptiongroup_split_matcher_type; static int get_matcher_type(PyObject *value, _exceptiongroup_split_matcher_type *type) { assert(value); if (PyFunction_Check(value)) { *type = EXCEPTION_GROUP_MATCH_BY_PREDICATE; return 0; } if (PyExceptionClass_Check(value)) { *type = EXCEPTION_GROUP_MATCH_BY_TYPE; return 0; } if (PyTuple_CheckExact(value)) { Py_ssize_t n = PyTuple_GET_SIZE(value); for (Py_ssize_t i=0; imatch = NULL; result->rest = NULL; int is_match = exceptiongroup_split_check_match( exc, matcher_type, matcher_value); if (is_match < 0) { return -1; } if (is_match) { /* Full match */ result->match = Py_NewRef(exc); return 0; } else if (!_PyBaseExceptionGroup_Check(exc)) { /* Leaf exception and no match */ if (construct_rest) { result->rest = Py_NewRef(exc); } return 0; } /* Partial match */ PyBaseExceptionGroupObject *eg = _PyBaseExceptionGroupObject_cast(exc); assert(PyTuple_CheckExact(eg->excs)); Py_ssize_t num_excs = PyTuple_Size(eg->excs); if (num_excs < 0) { return -1; } assert(num_excs > 0); /* checked in constructor, and excs is read-only */ int retval = -1; PyObject *match_list = PyList_New(0); if (!match_list) { return -1; } PyObject *rest_list = NULL; if (construct_rest) { rest_list = PyList_New(0); if (!rest_list) { goto done; } } /* recursive calls */ for (Py_ssize_t i = 0; i < num_excs; i++) { PyObject *e = PyTuple_GET_ITEM(eg->excs, i); _exceptiongroup_split_result rec_result; if (_Py_EnterRecursiveCall(" in exceptiongroup_split_recursive")) { goto done; } if (exceptiongroup_split_recursive( e, matcher_type, matcher_value, construct_rest, &rec_result) < 0) { assert(!rec_result.match); assert(!rec_result.rest); _Py_LeaveRecursiveCall(); goto done; } _Py_LeaveRecursiveCall(); if (rec_result.match) { assert(PyList_CheckExact(match_list)); if (PyList_Append(match_list, rec_result.match) < 0) { Py_DECREF(rec_result.match); Py_XDECREF(rec_result.rest); goto done; } Py_DECREF(rec_result.match); } if (rec_result.rest) { assert(construct_rest); assert(PyList_CheckExact(rest_list)); if (PyList_Append(rest_list, rec_result.rest) < 0) { Py_DECREF(rec_result.rest); goto done; } Py_DECREF(rec_result.rest); } } /* construct result */ if (exceptiongroup_subset(eg, match_list, &result->match) < 0) { goto done; } if (construct_rest) { assert(PyList_CheckExact(rest_list)); if (exceptiongroup_subset(eg, rest_list, &result->rest) < 0) { Py_CLEAR(result->match); goto done; } } retval = 0; done: Py_DECREF(match_list); Py_XDECREF(rest_list); if (retval < 0) { Py_CLEAR(result->match); Py_CLEAR(result->rest); } return retval; } static PyObject * BaseExceptionGroup_split(PyObject *self, PyObject *args) { PyObject *matcher_value = NULL; if (!PyArg_UnpackTuple(args, "split", 1, 1, &matcher_value)) { return NULL; } _exceptiongroup_split_matcher_type matcher_type; if (get_matcher_type(matcher_value, &matcher_type) < 0) { return NULL; } _exceptiongroup_split_result split_result; bool construct_rest = true; if (exceptiongroup_split_recursive( self, matcher_type, matcher_value, construct_rest, &split_result) < 0) { return NULL; } PyObject *result = PyTuple_Pack( 2, split_result.match ? split_result.match : Py_None, split_result.rest ? split_result.rest : Py_None); Py_XDECREF(split_result.match); Py_XDECREF(split_result.rest); return result; } static PyObject * BaseExceptionGroup_subgroup(PyObject *self, PyObject *args) { PyObject *matcher_value = NULL; if (!PyArg_UnpackTuple(args, "subgroup", 1, 1, &matcher_value)) { return NULL; } _exceptiongroup_split_matcher_type matcher_type; if (get_matcher_type(matcher_value, &matcher_type) < 0) { return NULL; } _exceptiongroup_split_result split_result; bool construct_rest = false; if (exceptiongroup_split_recursive( self, matcher_type, matcher_value, construct_rest, &split_result) < 0) { return NULL; } PyObject *result = Py_NewRef( split_result.match ? split_result.match : Py_None); Py_XDECREF(split_result.match); assert(!split_result.rest); return result; } static int collect_exception_group_leaves(PyObject *exc, PyObject *leaves) { if (Py_IsNone(exc)) { return 0; } assert(PyExceptionInstance_Check(exc)); assert(PySet_Check(leaves)); /* Add all leaf exceptions in exc to the leaves set */ if (!_PyBaseExceptionGroup_Check(exc)) { if (PySet_Add(leaves, exc) < 0) { return -1; } return 0; } PyBaseExceptionGroupObject *eg = _PyBaseExceptionGroupObject_cast(exc); Py_ssize_t num_excs = PyTuple_GET_SIZE(eg->excs); /* recursive calls */ for (Py_ssize_t i = 0; i < num_excs; i++) { PyObject *e = PyTuple_GET_ITEM(eg->excs, i); if (_Py_EnterRecursiveCall(" in collect_exception_group_leaves")) { return -1; } int res = collect_exception_group_leaves(e, leaves); _Py_LeaveRecursiveCall(); if (res < 0) { return -1; } } return 0; } /* This function is used by the interpreter to construct reraised * exception groups. It takes an exception group eg and a list * of exception groups keep and returns the sub-exception group * of eg which contains all leaf exceptions that are contained * in any exception group in keep. */ static PyObject * exception_group_projection(PyObject *eg, PyObject *keep) { assert(_PyBaseExceptionGroup_Check(eg)); assert(PyList_CheckExact(keep)); PyObject *leaves = PySet_New(NULL); if (!leaves) { return NULL; } Py_ssize_t n = PyList_GET_SIZE(keep); for (Py_ssize_t i = 0; i < n; i++) { PyObject *e = PyList_GET_ITEM(keep, i); assert(e != NULL); assert(_PyBaseExceptionGroup_Check(e)); if (collect_exception_group_leaves(e, leaves) < 0) { Py_DECREF(leaves); return NULL; } } _exceptiongroup_split_result split_result; bool construct_rest = false; int err = exceptiongroup_split_recursive( eg, EXCEPTION_GROUP_MATCH_INSTANCES, leaves, construct_rest, &split_result); Py_DECREF(leaves); if (err < 0) { return NULL; } PyObject *result = split_result.match ? split_result.match : Py_NewRef(Py_None); assert(split_result.rest == NULL); return result; } static bool is_same_exception_metadata(PyObject *exc1, PyObject *exc2) { assert(PyExceptionInstance_Check(exc1)); assert(PyExceptionInstance_Check(exc2)); PyBaseExceptionObject *e1 = (PyBaseExceptionObject *)exc1; PyBaseExceptionObject *e2 = (PyBaseExceptionObject *)exc2; return (e1->notes == e2->notes && e1->traceback == e2->traceback && e1->cause == e2->cause && e1->context == e2->context); } /* This function is used by the interpreter to calculate the exception group to be raised at the end of a try-except* construct. orig: the original except that was caught. excs: a list of exceptions that were raised/reraised in the except* clauses. Calculates an exception group to raise. It contains all exceptions in excs, where those that were reraised have same nesting structure as in orig, and those that were raised (if any) are added as siblings in a new EG. Returns NULL and sets an exception on failure. */ PyObject * _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs) { assert(PyExceptionInstance_Check(orig)); assert(PyList_Check(excs)); Py_ssize_t numexcs = PyList_GET_SIZE(excs); if (numexcs == 0) { return Py_NewRef(Py_None); } if (!_PyBaseExceptionGroup_Check(orig)) { /* a naked exception was caught and wrapped. Only one except* clause * could have executed,so there is at most one exception to raise. */ assert(numexcs == 1 || (numexcs == 2 && PyList_GET_ITEM(excs, 1) == Py_None)); PyObject *e = PyList_GET_ITEM(excs, 0); assert(e != NULL); return Py_NewRef(e); } PyObject *raised_list = PyList_New(0); if (raised_list == NULL) { return NULL; } PyObject* reraised_list = PyList_New(0); if (reraised_list == NULL) { Py_DECREF(raised_list); return NULL; } /* Now we are holding refs to raised_list and reraised_list */ PyObject *result = NULL; /* Split excs into raised and reraised by comparing metadata with orig */ for (Py_ssize_t i = 0; i < numexcs; i++) { PyObject *e = PyList_GET_ITEM(excs, i); assert(e != NULL); if (Py_IsNone(e)) { continue; } bool is_reraise = is_same_exception_metadata(e, orig); PyObject *append_list = is_reraise ? reraised_list : raised_list; if (PyList_Append(append_list, e) < 0) { goto done; } } PyObject *reraised_eg = exception_group_projection(orig, reraised_list); if (reraised_eg == NULL) { goto done; } if (!Py_IsNone(reraised_eg)) { assert(is_same_exception_metadata(reraised_eg, orig)); } Py_ssize_t num_raised = PyList_GET_SIZE(raised_list); if (num_raised == 0) { result = reraised_eg; } else if (num_raised > 0) { int res = 0; if (!Py_IsNone(reraised_eg)) { res = PyList_Append(raised_list, reraised_eg); } Py_DECREF(reraised_eg); if (res < 0) { goto done; } result = _PyExc_CreateExceptionGroup("", raised_list); if (result == NULL) { goto done; } } done: Py_XDECREF(raised_list); Py_XDECREF(reraised_list); return result; } static PyMemberDef BaseExceptionGroup_members[] = { {"message", T_OBJECT, offsetof(PyBaseExceptionGroupObject, msg), READONLY, PyDoc_STR("exception message")}, {"exceptions", T_OBJECT, offsetof(PyBaseExceptionGroupObject, excs), READONLY, PyDoc_STR("nested exceptions")}, {NULL} /* Sentinel */ }; static PyMethodDef BaseExceptionGroup_methods[] = { {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, {"derive", (PyCFunction)BaseExceptionGroup_derive, METH_VARARGS}, {"split", (PyCFunction)BaseExceptionGroup_split, METH_VARARGS}, {"subgroup", (PyCFunction)BaseExceptionGroup_subgroup, METH_VARARGS}, {NULL} }; ComplexExtendsException(PyExc_BaseException, BaseExceptionGroup, BaseExceptionGroup, BaseExceptionGroup_new /* new */, BaseExceptionGroup_methods, BaseExceptionGroup_members, 0 /* getset */, BaseExceptionGroup_str, "A combination of multiple unrelated exceptions."); /* * ExceptionGroup extends BaseExceptionGroup, Exception */ static PyObject* create_exception_group_class(void) { struct _Py_exc_state *state = get_exc_state(); PyObject *bases = PyTuple_Pack( 2, PyExc_BaseExceptionGroup, PyExc_Exception); if (bases == NULL) { return NULL; } assert(!state->PyExc_ExceptionGroup); state->PyExc_ExceptionGroup = PyErr_NewException( "builtins.ExceptionGroup", bases, NULL); Py_DECREF(bases); return state->PyExc_ExceptionGroup; } /* * KeyboardInterrupt extends BaseException */ SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, "Program interrupted by user."); /* * ImportError extends Exception */ static int ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", "path", 0}; PyObject *empty_tuple; PyObject *msg = NULL; PyObject *name = NULL; PyObject *path = NULL; if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) return -1; empty_tuple = PyTuple_New(0); if (!empty_tuple) return -1; if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OO:ImportError", kwlist, &name, &path)) { Py_DECREF(empty_tuple); return -1; } Py_DECREF(empty_tuple); Py_XINCREF(name); Py_XSETREF(self->name, name); Py_XINCREF(path); Py_XSETREF(self->path, path); if (PyTuple_GET_SIZE(args) == 1) { msg = PyTuple_GET_ITEM(args, 0); Py_INCREF(msg); } Py_XSETREF(self->msg, msg); return 0; } static int ImportError_clear(PyImportErrorObject *self) { Py_CLEAR(self->msg); Py_CLEAR(self->name); Py_CLEAR(self->path); return BaseException_clear((PyBaseExceptionObject *)self); } static void ImportError_dealloc(PyImportErrorObject *self) { _PyObject_GC_UNTRACK(self); ImportError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int ImportError_traverse(PyImportErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->msg); Py_VISIT(self->name); Py_VISIT(self->path); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyObject * ImportError_str(PyImportErrorObject *self) { if (self->msg && PyUnicode_CheckExact(self->msg)) { Py_INCREF(self->msg); return self->msg; } else { return BaseException_str((PyBaseExceptionObject *)self); } } static PyObject * ImportError_getstate(PyImportErrorObject *self) { PyObject *dict = ((PyBaseExceptionObject *)self)->dict; if (self->name || self->path) { dict = dict ? PyDict_Copy(dict) : PyDict_New(); if (dict == NULL) return NULL; if (self->name && PyDict_SetItem(dict, &_Py_ID(name), self->name) < 0) { Py_DECREF(dict); return NULL; } if (self->path && PyDict_SetItem(dict, &_Py_ID(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 *Py_UNUSED(ignored)) { 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")}, {"name", T_OBJECT, offsetof(PyImportErrorObject, name), 0, PyDoc_STR("module name")}, {"path", T_OBJECT, offsetof(PyImportErrorObject, path), 0, PyDoc_STR("module path")}, {NULL} /* Sentinel */ }; static PyMethodDef ImportError_methods[] = { {"__reduce__", (PyCFunction)ImportError_reduce, METH_NOARGS}, {NULL} }; ComplexExtendsException(PyExc_Exception, ImportError, ImportError, 0 /* new */, ImportError_methods, ImportError_members, 0 /* getset */, ImportError_str, "Import can't find module, or can't find name in " "module."); /* * ModuleNotFoundError extends ImportError */ MiddlingExtendsException(PyExc_ImportError, ModuleNotFoundError, ImportError, "Module not found."); /* * OSError extends Exception */ #ifdef MS_WINDOWS #include "errmap.h" #endif /* Where a function has a single filename, such as open() or some * of the os module functions, PyErr_SetFromErrnoWithFilename() is * called, giving a third argument which is the filename. But, so * that old code using in-place unpacking doesn't break, e.g.: * * except OSError, (errno, strerror): * * we hack args so that it only contains two items. This also * means we need our own __str__() which prints out the filename * when it was supplied. * * (If a function has two filenames, such as rename(), symlink(), * or copy(), PyErr_SetFromErrnoWithFilenameObjects() is called, * which allows passing in a second filename.) */ /* This function doesn't cleanup on error, the caller should */ static int oserror_parse_args(PyObject **p_args, PyObject **myerrno, PyObject **strerror, PyObject **filename, PyObject **filename2 #ifdef MS_WINDOWS , PyObject **winerror #endif ) { Py_ssize_t nargs; PyObject *args = *p_args; #ifndef MS_WINDOWS /* * ignored on non-Windows platforms, * but parsed so OSError has a consistent signature */ PyObject *_winerror = NULL; PyObject **winerror = &_winerror; #endif /* MS_WINDOWS */ nargs = PyTuple_GET_SIZE(args); if (nargs >= 2 && nargs <= 5) { if (!PyArg_UnpackTuple(args, "OSError", 2, 5, myerrno, strerror, filename, winerror, filename2)) return -1; #ifdef MS_WINDOWS if (*winerror && PyLong_Check(*winerror)) { long errcode, winerrcode; PyObject *newargs; Py_ssize_t i; winerrcode = PyLong_AsLong(*winerror); if (winerrcode == -1 && PyErr_Occurred()) return -1; errcode = winerror_to_errno(winerrcode); *myerrno = PyLong_FromLong(errcode); if (!*myerrno) return -1; newargs = PyTuple_New(nargs); if (!newargs) return -1; PyTuple_SET_ITEM(newargs, 0, *myerrno); for (i = 1; i < nargs; i++) { PyObject *val = PyTuple_GET_ITEM(args, i); Py_INCREF(val); PyTuple_SET_ITEM(newargs, i, val); } Py_DECREF(args); args = *p_args = newargs; } #endif /* MS_WINDOWS */ } return 0; } static int oserror_init(PyOSErrorObject *self, PyObject **p_args, PyObject *myerrno, PyObject *strerror, PyObject *filename, PyObject *filename2 #ifdef MS_WINDOWS , PyObject *winerror #endif ) { PyObject *args = *p_args; Py_ssize_t nargs = PyTuple_GET_SIZE(args); /* self->filename will remain Py_None otherwise */ if (filename && filename != Py_None) { if (Py_IS_TYPE(self, (PyTypeObject *) PyExc_BlockingIOError) && PyNumber_Check(filename)) { /* BlockingIOError's 3rd argument can be the number of * characters written. */ self->written = PyNumber_AsSsize_t(filename, PyExc_ValueError); if (self->written == -1 && PyErr_Occurred()) return -1; } else { Py_INCREF(filename); self->filename = filename; if (filename2 && filename2 != Py_None) { Py_INCREF(filename2); self->filename2 = filename2; } if (nargs >= 2 && nargs <= 5) { /* filename, filename2, and winerror are removed from the args tuple (for compatibility purposes, see test_exceptions.py) */ PyObject *subslice = PyTuple_GetSlice(args, 0, 2); if (!subslice) return -1; Py_DECREF(args); /* replacing args */ *p_args = args = subslice; } } } Py_XINCREF(myerrno); self->myerrno = myerrno; Py_XINCREF(strerror); self->strerror = strerror; #ifdef MS_WINDOWS Py_XINCREF(winerror); self->winerror = winerror; #endif /* Steals the reference to args */ Py_XSETREF(self->args, args); *p_args = args = NULL; return 0; } static PyObject * OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static int OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds); static int oserror_use_init(PyTypeObject *type) { /* When __init__ is defined in an OSError subclass, we want any extraneous argument to __new__ to be ignored. The only reasonable solution, given __new__ takes a variable number of arguments, is to defer arg parsing and initialization to __init__. But when __new__ is overridden as well, it should call our __new__ with the right arguments. (see http://bugs.python.org/issue12555#msg148829 ) */ if (type->tp_init != (initproc) OSError_init && type->tp_new == (newfunc) OSError_new) { assert((PyObject *) type != PyExc_OSError); return 1; } return 0; } static PyObject * OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyOSErrorObject *self = NULL; PyObject *myerrno = NULL, *strerror = NULL; PyObject *filename = NULL, *filename2 = NULL; #ifdef MS_WINDOWS PyObject *winerror = NULL; #endif Py_INCREF(args); if (!oserror_use_init(type)) { if (!_PyArg_NoKeywords(type->tp_name, kwds)) goto error; if (oserror_parse_args(&args, &myerrno, &strerror, &filename, &filename2 #ifdef MS_WINDOWS , &winerror #endif )) goto error; struct _Py_exc_state *state = get_exc_state(); if (myerrno && PyLong_Check(myerrno) && state->errnomap && (PyObject *) type == PyExc_OSError) { PyObject *newtype; newtype = PyDict_GetItemWithError(state->errnomap, myerrno); if (newtype) { type = _PyType_CAST(newtype); } else if (PyErr_Occurred()) goto error; } } self = (PyOSErrorObject *) type->tp_alloc(type, 0); if (!self) goto error; self->dict = NULL; self->traceback = self->cause = self->context = NULL; self->written = -1; if (!oserror_use_init(type)) { if (oserror_init(self, &args, myerrno, strerror, filename, filename2 #ifdef MS_WINDOWS , winerror #endif )) goto error; } else { self->args = PyTuple_New(0); if (self->args == NULL) goto error; } Py_XDECREF(args); return (PyObject *) self; error: Py_XDECREF(args); Py_XDECREF(self); return NULL; } static int OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds) { PyObject *myerrno = NULL, *strerror = NULL; PyObject *filename = NULL, *filename2 = NULL; #ifdef MS_WINDOWS PyObject *winerror = NULL; #endif if (!oserror_use_init(Py_TYPE(self))) /* Everything already done in OSError_new */ return 0; if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1; Py_INCREF(args); if (oserror_parse_args(&args, &myerrno, &strerror, &filename, &filename2 #ifdef MS_WINDOWS , &winerror #endif )) goto error; if (oserror_init(self, &args, myerrno, strerror, filename, filename2 #ifdef MS_WINDOWS , winerror #endif )) goto error; return 0; error: Py_DECREF(args); return -1; } static int OSError_clear(PyOSErrorObject *self) { Py_CLEAR(self->myerrno); Py_CLEAR(self->strerror); Py_CLEAR(self->filename); Py_CLEAR(self->filename2); #ifdef MS_WINDOWS Py_CLEAR(self->winerror); #endif return BaseException_clear((PyBaseExceptionObject *)self); } static void OSError_dealloc(PyOSErrorObject *self) { _PyObject_GC_UNTRACK(self); OSError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int OSError_traverse(PyOSErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->myerrno); Py_VISIT(self->strerror); Py_VISIT(self->filename); Py_VISIT(self->filename2); #ifdef MS_WINDOWS Py_VISIT(self->winerror); #endif return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyObject * OSError_str(PyOSErrorObject *self) { #define OR_NONE(x) ((x)?(x):Py_None) #ifdef MS_WINDOWS /* If available, winerror has the priority over myerrno */ if (self->winerror && self->filename) { if (self->filename2) { return PyUnicode_FromFormat("[WinError %S] %S: %R -> %R", OR_NONE(self->winerror), OR_NONE(self->strerror), self->filename, self->filename2); } else { return PyUnicode_FromFormat("[WinError %S] %S: %R", OR_NONE(self->winerror), OR_NONE(self->strerror), self->filename); } } if (self->winerror && self->strerror) return PyUnicode_FromFormat("[WinError %S] %S", self->winerror ? self->winerror: Py_None, self->strerror ? self->strerror: Py_None); #endif if (self->filename) { if (self->filename2) { return PyUnicode_FromFormat("[Errno %S] %S: %R -> %R", OR_NONE(self->myerrno), OR_NONE(self->strerror), self->filename, self->filename2); } else { return PyUnicode_FromFormat("[Errno %S] %S: %R", OR_NONE(self->myerrno), OR_NONE(self->strerror), self->filename); } } if (self->myerrno && self->strerror) return PyUnicode_FromFormat("[Errno %S] %S", self->myerrno, self->strerror); return BaseException_str((PyBaseExceptionObject *)self); } static PyObject * OSError_reduce(PyOSErrorObject *self, PyObject *Py_UNUSED(ignored)) { PyObject *args = self->args; PyObject *res = NULL, *tmp; /* self->args is only the first two real arguments if there was a * file name given to OSError. */ if (PyTuple_GET_SIZE(args) == 2 && self->filename) { Py_ssize_t size = self->filename2 ? 5 : 3; args = PyTuple_New(size); if (!args) return NULL; tmp = PyTuple_GET_ITEM(self->args, 0); Py_INCREF(tmp); PyTuple_SET_ITEM(args, 0, tmp); tmp = PyTuple_GET_ITEM(self->args, 1); Py_INCREF(tmp); PyTuple_SET_ITEM(args, 1, tmp); Py_INCREF(self->filename); PyTuple_SET_ITEM(args, 2, self->filename); if (self->filename2) { /* * This tuple is essentially used as OSError(*args). * So, to recreate filename2, we need to pass in * winerror as well. */ Py_INCREF(Py_None); PyTuple_SET_ITEM(args, 3, Py_None); /* filename2 */ Py_INCREF(self->filename2); PyTuple_SET_ITEM(args, 4, self->filename2); } } else Py_INCREF(args); if (self->dict) res = PyTuple_Pack(3, Py_TYPE(self), args, self->dict); else res = PyTuple_Pack(2, Py_TYPE(self), args); Py_DECREF(args); return res; } static PyObject * OSError_written_get(PyOSErrorObject *self, void *context) { if (self->written == -1) { PyErr_SetString(PyExc_AttributeError, "characters_written"); return NULL; } return PyLong_FromSsize_t(self->written); } static int OSError_written_set(PyOSErrorObject *self, PyObject *arg, void *context) { if (arg == NULL) { if (self->written == -1) { PyErr_SetString(PyExc_AttributeError, "characters_written"); return -1; } self->written = -1; return 0; } Py_ssize_t n; n = PyNumber_AsSsize_t(arg, PyExc_ValueError); if (n == -1 && PyErr_Occurred()) return -1; self->written = n; return 0; } static PyMemberDef OSError_members[] = { {"errno", T_OBJECT, offsetof(PyOSErrorObject, myerrno), 0, PyDoc_STR("POSIX exception code")}, {"strerror", T_OBJECT, offsetof(PyOSErrorObject, strerror), 0, PyDoc_STR("exception strerror")}, {"filename", T_OBJECT, offsetof(PyOSErrorObject, filename), 0, PyDoc_STR("exception filename")}, {"filename2", T_OBJECT, offsetof(PyOSErrorObject, filename2), 0, PyDoc_STR("second exception filename")}, #ifdef MS_WINDOWS {"winerror", T_OBJECT, offsetof(PyOSErrorObject, winerror), 0, PyDoc_STR("Win32 exception code")}, #endif {NULL} /* Sentinel */ }; static PyMethodDef OSError_methods[] = { {"__reduce__", (PyCFunction)OSError_reduce, METH_NOARGS}, {NULL} }; static PyGetSetDef OSError_getset[] = { {"characters_written", (getter) OSError_written_get, (setter) OSError_written_set, NULL}, {NULL} }; ComplexExtendsException(PyExc_Exception, OSError, OSError, OSError_new, OSError_methods, OSError_members, OSError_getset, OSError_str, "Base class for I/O related errors."); /* * Various OSError subclasses */ MiddlingExtendsException(PyExc_OSError, BlockingIOError, OSError, "I/O operation would block."); MiddlingExtendsException(PyExc_OSError, ConnectionError, OSError, "Connection error."); MiddlingExtendsException(PyExc_OSError, ChildProcessError, OSError, "Child process error."); MiddlingExtendsException(PyExc_ConnectionError, BrokenPipeError, OSError, "Broken pipe."); MiddlingExtendsException(PyExc_ConnectionError, ConnectionAbortedError, OSError, "Connection aborted."); MiddlingExtendsException(PyExc_ConnectionError, ConnectionRefusedError, OSError, "Connection refused."); MiddlingExtendsException(PyExc_ConnectionError, ConnectionResetError, OSError, "Connection reset."); MiddlingExtendsException(PyExc_OSError, FileExistsError, OSError, "File already exists."); MiddlingExtendsException(PyExc_OSError, FileNotFoundError, OSError, "File not found."); MiddlingExtendsException(PyExc_OSError, IsADirectoryError, OSError, "Operation doesn't work on directories."); MiddlingExtendsException(PyExc_OSError, NotADirectoryError, OSError, "Operation only works on directories."); MiddlingExtendsException(PyExc_OSError, InterruptedError, OSError, "Interrupted by signal."); MiddlingExtendsException(PyExc_OSError, PermissionError, OSError, "Not enough permissions."); MiddlingExtendsException(PyExc_OSError, ProcessLookupError, OSError, "Process not found."); MiddlingExtendsException(PyExc_OSError, TimeoutError, OSError, "Timeout expired."); /* * EOFError extends Exception */ SimpleExtendsException(PyExc_Exception, EOFError, "Read beyond end of file."); /* * RuntimeError extends Exception */ SimpleExtendsException(PyExc_Exception, RuntimeError, "Unspecified run-time error."); /* * RecursionError extends RuntimeError */ SimpleExtendsException(PyExc_RuntimeError, RecursionError, "Recursion limit exceeded."); /* * NotImplementedError extends RuntimeError */ SimpleExtendsException(PyExc_RuntimeError, NotImplementedError, "Method or function hasn't been implemented yet."); /* * NameError extends Exception */ static int NameError_init(PyNameErrorObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", NULL}; PyObject *name = NULL; if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) { return -1; } PyObject *empty_tuple = PyTuple_New(0); if (!empty_tuple) { return -1; } if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$O:NameError", kwlist, &name)) { Py_DECREF(empty_tuple); return -1; } Py_DECREF(empty_tuple); Py_XINCREF(name); Py_XSETREF(self->name, name); return 0; } static int NameError_clear(PyNameErrorObject *self) { Py_CLEAR(self->name); return BaseException_clear((PyBaseExceptionObject *)self); } static void NameError_dealloc(PyNameErrorObject *self) { _PyObject_GC_UNTRACK(self); NameError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int NameError_traverse(PyNameErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->name); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyMemberDef NameError_members[] = { {"name", T_OBJECT, offsetof(PyNameErrorObject, name), 0, PyDoc_STR("name")}, {NULL} /* Sentinel */ }; static PyMethodDef NameError_methods[] = { {NULL} /* Sentinel */ }; ComplexExtendsException(PyExc_Exception, NameError, NameError, 0, NameError_methods, NameError_members, 0, BaseException_str, "Name not found globally."); /* * UnboundLocalError extends NameError */ MiddlingExtendsException(PyExc_NameError, UnboundLocalError, NameError, "Local name referenced but not bound to a value."); /* * AttributeError extends Exception */ static int AttributeError_init(PyAttributeErrorObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", "obj", NULL}; PyObject *name = NULL; PyObject *obj = NULL; if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) { return -1; } PyObject *empty_tuple = PyTuple_New(0); if (!empty_tuple) { return -1; } if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OO:AttributeError", kwlist, &name, &obj)) { Py_DECREF(empty_tuple); return -1; } Py_DECREF(empty_tuple); Py_XINCREF(name); Py_XSETREF(self->name, name); Py_XINCREF(obj); Py_XSETREF(self->obj, obj); return 0; } static int AttributeError_clear(PyAttributeErrorObject *self) { Py_CLEAR(self->obj); Py_CLEAR(self->name); return BaseException_clear((PyBaseExceptionObject *)self); } static void AttributeError_dealloc(PyAttributeErrorObject *self) { _PyObject_GC_UNTRACK(self); AttributeError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->obj); Py_VISIT(self->name); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } 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")}, {NULL} /* Sentinel */ }; static PyMethodDef AttributeError_methods[] = { {NULL} /* Sentinel */ }; ComplexExtendsException(PyExc_Exception, AttributeError, AttributeError, 0, AttributeError_methods, AttributeError_members, 0, BaseException_str, "Attribute not found."); /* * SyntaxError extends Exception */ static int SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) { PyObject *info = NULL; Py_ssize_t lenargs = PyTuple_GET_SIZE(args); if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; if (lenargs >= 1) { Py_INCREF(PyTuple_GET_ITEM(args, 0)); Py_XSETREF(self->msg, PyTuple_GET_ITEM(args, 0)); } if (lenargs == 2) { info = PyTuple_GET_ITEM(args, 1); info = PySequence_Tuple(info); if (!info) { return -1; } self->end_lineno = NULL; self->end_offset = NULL; if (!PyArg_ParseTuple(info, "OOOO|OO", &self->filename, &self->lineno, &self->offset, &self->text, &self->end_lineno, &self->end_offset)) { Py_DECREF(info); return -1; } Py_INCREF(self->filename); Py_INCREF(self->lineno); Py_INCREF(self->offset); Py_INCREF(self->text); Py_XINCREF(self->end_lineno); Py_XINCREF(self->end_offset); Py_DECREF(info); if (self->end_lineno != NULL && self->end_offset == NULL) { PyErr_SetString(PyExc_TypeError, "end_offset must be provided when end_lineno is provided"); return -1; } } return 0; } static int SyntaxError_clear(PySyntaxErrorObject *self) { Py_CLEAR(self->msg); Py_CLEAR(self->filename); Py_CLEAR(self->lineno); Py_CLEAR(self->offset); Py_CLEAR(self->end_lineno); Py_CLEAR(self->end_offset); Py_CLEAR(self->text); Py_CLEAR(self->print_file_and_line); return BaseException_clear((PyBaseExceptionObject *)self); } static void SyntaxError_dealloc(PySyntaxErrorObject *self) { _PyObject_GC_UNTRACK(self); SyntaxError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int SyntaxError_traverse(PySyntaxErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->msg); Py_VISIT(self->filename); Py_VISIT(self->lineno); Py_VISIT(self->offset); Py_VISIT(self->end_lineno); Py_VISIT(self->end_offset); Py_VISIT(self->text); Py_VISIT(self->print_file_and_line); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } /* This is called "my_basename" instead of just "basename" to avoid name conflicts with glibc; basename is already prototyped if _GNU_SOURCE is defined, and Python does define that. */ static PyObject* my_basename(PyObject *name) { Py_ssize_t i, size, offset; int kind; const void *data; if (PyUnicode_READY(name)) return NULL; kind = PyUnicode_KIND(name); data = PyUnicode_DATA(name); size = PyUnicode_GET_LENGTH(name); offset = 0; for(i=0; i < size; i++) { if (PyUnicode_READ(kind, data, i) == SEP) { offset = i + 1; } } if (offset != 0) { return PyUnicode_Substring(name, offset, size); } else { Py_INCREF(name); return name; } } static PyObject * SyntaxError_str(PySyntaxErrorObject *self) { int have_lineno = 0; PyObject *filename; PyObject *result; /* Below, we always ignore overflow errors, just printing -1. Still, we cannot allow an OverflowError to be raised, so we need to call PyLong_AsLongAndOverflow. */ int overflow; /* XXX -- do all the additional formatting with filename and lineno here */ if (self->filename && PyUnicode_Check(self->filename)) { filename = my_basename(self->filename); if (filename == NULL) return NULL; } else { filename = NULL; } have_lineno = (self->lineno != NULL) && PyLong_CheckExact(self->lineno); if (!filename && !have_lineno) return PyObject_Str(self->msg ? self->msg : Py_None); if (filename && have_lineno) result = PyUnicode_FromFormat("%S (%U, line %ld)", self->msg ? self->msg : Py_None, filename, PyLong_AsLongAndOverflow(self->lineno, &overflow)); else if (filename) result = PyUnicode_FromFormat("%S (%U)", self->msg ? self->msg : Py_None, filename); else /* only have_lineno */ result = PyUnicode_FromFormat("%S (line %ld)", self->msg ? self->msg : Py_None, PyLong_AsLongAndOverflow(self->lineno, &overflow)); Py_XDECREF(filename); return result; } static PyMemberDef SyntaxError_members[] = { {"msg", T_OBJECT, offsetof(PySyntaxErrorObject, msg), 0, PyDoc_STR("exception msg")}, {"filename", T_OBJECT, offsetof(PySyntaxErrorObject, filename), 0, PyDoc_STR("exception filename")}, {"lineno", T_OBJECT, offsetof(PySyntaxErrorObject, lineno), 0, PyDoc_STR("exception lineno")}, {"offset", T_OBJECT, offsetof(PySyntaxErrorObject, offset), 0, PyDoc_STR("exception offset")}, {"text", T_OBJECT, offsetof(PySyntaxErrorObject, text), 0, PyDoc_STR("exception text")}, {"end_lineno", T_OBJECT, offsetof(PySyntaxErrorObject, end_lineno), 0, PyDoc_STR("exception end lineno")}, {"end_offset", T_OBJECT, offsetof(PySyntaxErrorObject, end_offset), 0, PyDoc_STR("exception end offset")}, {"print_file_and_line", T_OBJECT, offsetof(PySyntaxErrorObject, print_file_and_line), 0, PyDoc_STR("exception print_file_and_line")}, {NULL} /* Sentinel */ }; ComplexExtendsException(PyExc_Exception, SyntaxError, SyntaxError, 0, 0, SyntaxError_members, 0, SyntaxError_str, "Invalid syntax."); /* * IndentationError extends SyntaxError */ MiddlingExtendsException(PyExc_SyntaxError, IndentationError, SyntaxError, "Improper indentation."); /* * TabError extends IndentationError */ MiddlingExtendsException(PyExc_IndentationError, TabError, SyntaxError, "Improper mixture of spaces and tabs."); /* * LookupError extends Exception */ SimpleExtendsException(PyExc_Exception, LookupError, "Base class for lookup errors."); /* * IndexError extends LookupError */ SimpleExtendsException(PyExc_LookupError, IndexError, "Sequence index out of range."); /* * KeyError extends LookupError */ static PyObject * KeyError_str(PyBaseExceptionObject *self) { /* If args is a tuple of exactly one item, apply repr to args[0]. This is done so that e.g. the exception raised by {}[''] prints KeyError: '' rather than the confusing KeyError alone. The downside is that if KeyError is raised with an explanatory string, that string will be displayed in quotes. Too bad. If args is anything else, use the default BaseException__str__(). */ if (PyTuple_GET_SIZE(self->args) == 1) { return PyObject_Repr(PyTuple_GET_ITEM(self->args, 0)); } return BaseException_str(self); } ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, 0, 0, 0, 0, KeyError_str, "Mapping key not found."); /* * ValueError extends Exception */ SimpleExtendsException(PyExc_Exception, ValueError, "Inappropriate argument value (of correct type)."); /* * UnicodeError extends ValueError */ SimpleExtendsException(PyExc_ValueError, UnicodeError, "Unicode related error."); static PyObject * get_string(PyObject *attr, const char *name) { if (!attr) { PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); return NULL; } if (!PyBytes_Check(attr)) { PyErr_Format(PyExc_TypeError, "%.200s attribute must be bytes", name); return NULL; } Py_INCREF(attr); return attr; } static PyObject * get_unicode(PyObject *attr, const char *name) { if (!attr) { PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); return NULL; } if (!PyUnicode_Check(attr)) { PyErr_Format(PyExc_TypeError, "%.200s attribute must be unicode", name); return NULL; } Py_INCREF(attr); return attr; } static int set_unicodefromstring(PyObject **attr, const char *value) { PyObject *obj = PyUnicode_FromString(value); if (!obj) return -1; Py_XSETREF(*attr, obj); return 0; } PyObject * PyUnicodeEncodeError_GetEncoding(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); } PyObject * PyUnicodeDecodeError_GetEncoding(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); } PyObject * PyUnicodeEncodeError_GetObject(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); } PyObject * PyUnicodeDecodeError_GetObject(PyObject *exc) { return get_string(((PyUnicodeErrorObject *)exc)->object, "object"); } PyObject * PyUnicodeTranslateError_GetObject(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); } int PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start) { Py_ssize_t size; PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); if (!obj) return -1; *start = ((PyUnicodeErrorObject *)exc)->start; size = PyUnicode_GET_LENGTH(obj); if (*start<0) *start = 0; /*XXX check for values <0*/ if (*start>=size) *start = size-1; Py_DECREF(obj); return 0; } int PyUnicodeDecodeError_GetStart(PyObject *exc, Py_ssize_t *start) { Py_ssize_t size; PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, "object"); if (!obj) return -1; size = PyBytes_GET_SIZE(obj); *start = ((PyUnicodeErrorObject *)exc)->start; if (*start<0) *start = 0; if (*start>=size) *start = size-1; Py_DECREF(obj); return 0; } int PyUnicodeTranslateError_GetStart(PyObject *exc, Py_ssize_t *start) { return PyUnicodeEncodeError_GetStart(exc, start); } int PyUnicodeEncodeError_SetStart(PyObject *exc, Py_ssize_t start) { ((PyUnicodeErrorObject *)exc)->start = start; return 0; } int PyUnicodeDecodeError_SetStart(PyObject *exc, Py_ssize_t start) { ((PyUnicodeErrorObject *)exc)->start = start; return 0; } int PyUnicodeTranslateError_SetStart(PyObject *exc, Py_ssize_t start) { ((PyUnicodeErrorObject *)exc)->start = start; return 0; } int PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end) { Py_ssize_t size; PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); if (!obj) return -1; *end = ((PyUnicodeErrorObject *)exc)->end; size = PyUnicode_GET_LENGTH(obj); if (*end<1) *end = 1; if (*end>size) *end = size; Py_DECREF(obj); return 0; } int PyUnicodeDecodeError_GetEnd(PyObject *exc, Py_ssize_t *end) { Py_ssize_t size; PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, "object"); if (!obj) return -1; size = PyBytes_GET_SIZE(obj); *end = ((PyUnicodeErrorObject *)exc)->end; if (*end<1) *end = 1; if (*end>size) *end = size; Py_DECREF(obj); return 0; } int PyUnicodeTranslateError_GetEnd(PyObject *exc, Py_ssize_t *end) { return PyUnicodeEncodeError_GetEnd(exc, end); } int PyUnicodeEncodeError_SetEnd(PyObject *exc, Py_ssize_t end) { ((PyUnicodeErrorObject *)exc)->end = end; return 0; } int PyUnicodeDecodeError_SetEnd(PyObject *exc, Py_ssize_t end) { ((PyUnicodeErrorObject *)exc)->end = end; return 0; } int PyUnicodeTranslateError_SetEnd(PyObject *exc, Py_ssize_t end) { ((PyUnicodeErrorObject *)exc)->end = end; return 0; } PyObject * PyUnicodeEncodeError_GetReason(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->reason, "reason"); } PyObject * PyUnicodeDecodeError_GetReason(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->reason, "reason"); } PyObject * PyUnicodeTranslateError_GetReason(PyObject *exc) { return get_unicode(((PyUnicodeErrorObject *)exc)->reason, "reason"); } int PyUnicodeEncodeError_SetReason(PyObject *exc, const char *reason) { return set_unicodefromstring(&((PyUnicodeErrorObject *)exc)->reason, reason); } int PyUnicodeDecodeError_SetReason(PyObject *exc, const char *reason) { return set_unicodefromstring(&((PyUnicodeErrorObject *)exc)->reason, reason); } int PyUnicodeTranslateError_SetReason(PyObject *exc, const char *reason) { return set_unicodefromstring(&((PyUnicodeErrorObject *)exc)->reason, reason); } static int UnicodeError_clear(PyUnicodeErrorObject *self) { Py_CLEAR(self->encoding); Py_CLEAR(self->object); Py_CLEAR(self->reason); return BaseException_clear((PyBaseExceptionObject *)self); } static void UnicodeError_dealloc(PyUnicodeErrorObject *self) { _PyObject_GC_UNTRACK(self); UnicodeError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int UnicodeError_traverse(PyUnicodeErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->encoding); Py_VISIT(self->object); Py_VISIT(self->reason); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyMemberDef UnicodeError_members[] = { {"encoding", T_OBJECT, offsetof(PyUnicodeErrorObject, encoding), 0, PyDoc_STR("exception encoding")}, {"object", T_OBJECT, offsetof(PyUnicodeErrorObject, object), 0, PyDoc_STR("exception object")}, {"start", T_PYSSIZET, offsetof(PyUnicodeErrorObject, start), 0, PyDoc_STR("exception start")}, {"end", T_PYSSIZET, offsetof(PyUnicodeErrorObject, end), 0, PyDoc_STR("exception end")}, {"reason", T_OBJECT, offsetof(PyUnicodeErrorObject, reason), 0, PyDoc_STR("exception reason")}, {NULL} /* Sentinel */ }; /* * UnicodeEncodeError extends UnicodeError */ static int UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) { PyUnicodeErrorObject *err; if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; err = (PyUnicodeErrorObject *)self; Py_CLEAR(err->encoding); Py_CLEAR(err->object); Py_CLEAR(err->reason); if (!PyArg_ParseTuple(args, "UUnnU", &err->encoding, &err->object, &err->start, &err->end, &err->reason)) { err->encoding = err->object = err->reason = NULL; return -1; } Py_INCREF(err->encoding); Py_INCREF(err->object); Py_INCREF(err->reason); return 0; } static PyObject * UnicodeEncodeError_str(PyObject *self) { PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; if (!uself->object) /* Not properly initialized. */ return PyUnicode_FromString(""); /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ reason_str = PyObject_Str(uself->reason); if (reason_str == NULL) goto done; encoding_str = PyObject_Str(uself->encoding); if (encoding_str == NULL) goto done; if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); const char *fmt; if (badchar <= 0xff) fmt = "'%U' codec can't encode character '\\x%02x' in position %zd: %U"; else if (badchar <= 0xffff) fmt = "'%U' codec can't encode character '\\u%04x' in position %zd: %U"; else fmt = "'%U' codec can't encode character '\\U%08x' in position %zd: %U"; result = PyUnicode_FromFormat( fmt, encoding_str, (int)badchar, uself->start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't encode characters in position %zd-%zd: %U", encoding_str, uself->start, uself->end-1, reason_str); } done: Py_XDECREF(reason_str); Py_XDECREF(encoding_str); return result; } static PyTypeObject _PyExc_UnicodeEncodeError = { PyVarObject_HEAD_INIT(NULL, 0) "UnicodeEncodeError", sizeof(PyUnicodeErrorObject), 0, (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)UnicodeEncodeError_str, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), (initproc)UnicodeEncodeError_init, 0, BaseException_new, }; PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError; /* * UnicodeDecodeError extends UnicodeError */ static int UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) { PyUnicodeErrorObject *ude; if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; ude = (PyUnicodeErrorObject *)self; Py_CLEAR(ude->encoding); Py_CLEAR(ude->object); Py_CLEAR(ude->reason); if (!PyArg_ParseTuple(args, "UOnnU", &ude->encoding, &ude->object, &ude->start, &ude->end, &ude->reason)) { ude->encoding = ude->object = ude->reason = NULL; return -1; } Py_INCREF(ude->encoding); Py_INCREF(ude->object); Py_INCREF(ude->reason); if (!PyBytes_Check(ude->object)) { Py_buffer view; if (PyObject_GetBuffer(ude->object, &view, PyBUF_SIMPLE) != 0) goto error; Py_XSETREF(ude->object, PyBytes_FromStringAndSize(view.buf, view.len)); PyBuffer_Release(&view); if (!ude->object) goto error; } return 0; error: Py_CLEAR(ude->encoding); Py_CLEAR(ude->object); Py_CLEAR(ude->reason); return -1; } static PyObject * UnicodeDecodeError_str(PyObject *self) { PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; PyObject *encoding_str = NULL; if (!uself->object) /* Not properly initialized. */ return PyUnicode_FromString(""); /* Get reason and encoding as strings, which they might not be if they've been modified after we were constructed. */ reason_str = PyObject_Str(uself->reason); if (reason_str == NULL) goto done; encoding_str = PyObject_Str(uself->encoding); if (encoding_str == NULL) goto done; if (uself->start < PyBytes_GET_SIZE(uself->object) && uself->end == uself->start+1) { int byte = (int)(PyBytes_AS_STRING(((PyUnicodeErrorObject *)self)->object)[uself->start]&0xff); result = PyUnicode_FromFormat( "'%U' codec can't decode byte 0x%02x in position %zd: %U", encoding_str, byte, uself->start, reason_str); } else { result = PyUnicode_FromFormat( "'%U' codec can't decode bytes in position %zd-%zd: %U", encoding_str, uself->start, uself->end-1, reason_str ); } done: Py_XDECREF(reason_str); Py_XDECREF(encoding_str); return result; } static PyTypeObject _PyExc_UnicodeDecodeError = { PyVarObject_HEAD_INIT(NULL, 0) "UnicodeDecodeError", sizeof(PyUnicodeErrorObject), 0, (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)UnicodeDecodeError_str, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), (initproc)UnicodeDecodeError_init, 0, BaseException_new, }; PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError; PyObject * PyUnicodeDecodeError_Create( const char *encoding, const char *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason) { return PyObject_CallFunction(PyExc_UnicodeDecodeError, "sy#nns", encoding, object, length, start, end, reason); } /* * UnicodeTranslateError extends UnicodeError */ static int UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, PyObject *kwds) { if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) return -1; Py_CLEAR(self->object); Py_CLEAR(self->reason); if (!PyArg_ParseTuple(args, "UnnU", &self->object, &self->start, &self->end, &self->reason)) { self->object = self->reason = NULL; return -1; } Py_INCREF(self->object); Py_INCREF(self->reason); return 0; } static PyObject * UnicodeTranslateError_str(PyObject *self) { PyUnicodeErrorObject *uself = (PyUnicodeErrorObject *)self; PyObject *result = NULL; PyObject *reason_str = NULL; if (!uself->object) /* Not properly initialized. */ return PyUnicode_FromString(""); /* Get reason as a string, which it might not be if it's been modified after we were constructed. */ reason_str = PyObject_Str(uself->reason); if (reason_str == NULL) goto done; if (uself->start < PyUnicode_GET_LENGTH(uself->object) && uself->end == uself->start+1) { Py_UCS4 badchar = PyUnicode_ReadChar(uself->object, uself->start); const char *fmt; if (badchar <= 0xff) fmt = "can't translate character '\\x%02x' in position %zd: %U"; else if (badchar <= 0xffff) fmt = "can't translate character '\\u%04x' in position %zd: %U"; else fmt = "can't translate character '\\U%08x' in position %zd: %U"; result = PyUnicode_FromFormat( fmt, (int)badchar, uself->start, reason_str ); } else { result = PyUnicode_FromFormat( "can't translate characters in position %zd-%zd: %U", uself->start, uself->end-1, reason_str ); } done: Py_XDECREF(reason_str); return result; } static PyTypeObject _PyExc_UnicodeTranslateError = { PyVarObject_HEAD_INIT(NULL, 0) "UnicodeTranslateError", sizeof(PyUnicodeErrorObject), 0, (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (reprfunc)UnicodeTranslateError_str, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse, (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), (initproc)UnicodeTranslateError_init, 0, BaseException_new, }; PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError; PyObject * _PyUnicodeTranslateError_Create( PyObject *object, Py_ssize_t start, Py_ssize_t end, const char *reason) { return PyObject_CallFunction(PyExc_UnicodeTranslateError, "Onns", object, start, end, reason); } /* * AssertionError extends Exception */ SimpleExtendsException(PyExc_Exception, AssertionError, "Assertion failed."); /* * ArithmeticError extends Exception */ SimpleExtendsException(PyExc_Exception, ArithmeticError, "Base class for arithmetic errors."); /* * FloatingPointError extends ArithmeticError */ SimpleExtendsException(PyExc_ArithmeticError, FloatingPointError, "Floating point operation failed."); /* * OverflowError extends ArithmeticError */ SimpleExtendsException(PyExc_ArithmeticError, OverflowError, "Result too large to be represented."); /* * ZeroDivisionError extends ArithmeticError */ SimpleExtendsException(PyExc_ArithmeticError, ZeroDivisionError, "Second argument to a division or modulo operation was zero."); /* * SystemError extends Exception */ SimpleExtendsException(PyExc_Exception, SystemError, "Internal error in the Python interpreter.\n" "\n" "Please report this to the Python maintainer, along with the traceback,\n" "the Python version, and the hardware/OS platform and version."); /* * ReferenceError extends Exception */ SimpleExtendsException(PyExc_Exception, ReferenceError, "Weak ref proxy used after referent went away."); /* * MemoryError extends Exception */ #define MEMERRORS_SAVE 16 static PyObject * MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyBaseExceptionObject *self; /* If this is a subclass of MemoryError, don't use the freelist * and just return a fresh object */ if (type != (PyTypeObject *) PyExc_MemoryError) { return BaseException_new(type, args, kwds); } struct _Py_exc_state *state = get_exc_state(); if (state->memerrors_freelist == NULL) { return BaseException_new(type, args, kwds); } /* Fetch object from freelist and revive it */ self = state->memerrors_freelist; self->args = PyTuple_New(0); /* This shouldn't happen since the empty tuple is persistent */ if (self->args == NULL) { return NULL; } state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; state->memerrors_numfree--; self->dict = NULL; _Py_NewReference((PyObject *)self); _PyObject_GC_TRACK(self); return (PyObject *)self; } static void MemoryError_dealloc(PyBaseExceptionObject *self) { _PyObject_GC_UNTRACK(self); BaseException_clear(self); /* If this is a subclass of MemoryError, we don't need to * do anything in the free-list*/ if (!Py_IS_TYPE(self, (PyTypeObject *) PyExc_MemoryError)) { Py_TYPE(self)->tp_free((PyObject *)self); return; } struct _Py_exc_state *state = get_exc_state(); if (state->memerrors_numfree >= MEMERRORS_SAVE) { Py_TYPE(self)->tp_free((PyObject *)self); } else { self->dict = (PyObject *) state->memerrors_freelist; state->memerrors_freelist = self; state->memerrors_numfree++; } } static int preallocate_memerrors(void) { /* We create enough MemoryErrors and then decref them, which will fill up the freelist. */ int i; PyObject *errors[MEMERRORS_SAVE]; for (i = 0; i < MEMERRORS_SAVE; i++) { errors[i] = MemoryError_new((PyTypeObject *) PyExc_MemoryError, NULL, NULL); if (!errors[i]) { return -1; } } for (i = 0; i < MEMERRORS_SAVE; i++) { Py_DECREF(errors[i]); } return 0; } static void free_preallocated_memerrors(struct _Py_exc_state *state) { while (state->memerrors_freelist != NULL) { PyObject *self = (PyObject *) state->memerrors_freelist; state->memerrors_freelist = (PyBaseExceptionObject *)state->memerrors_freelist->dict; Py_TYPE(self)->tp_free((PyObject *)self); } } static PyTypeObject _PyExc_MemoryError = { PyVarObject_HEAD_INIT(NULL, 0) "MemoryError", sizeof(PyBaseExceptionObject), 0, (destructor)MemoryError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, PyDoc_STR("Out of memory."), (traverseproc)BaseException_traverse, (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_PyExc_Exception, 0, 0, 0, offsetof(PyBaseExceptionObject, dict), (initproc)BaseException_init, 0, MemoryError_new }; PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError; /* * BufferError extends Exception */ SimpleExtendsException(PyExc_Exception, BufferError, "Buffer error."); /* Warning category docstrings */ /* * Warning extends Exception */ SimpleExtendsException(PyExc_Exception, Warning, "Base class for warning categories."); /* * UserWarning extends Warning */ SimpleExtendsException(PyExc_Warning, UserWarning, "Base class for warnings generated by user code."); /* * DeprecationWarning extends Warning */ SimpleExtendsException(PyExc_Warning, DeprecationWarning, "Base class for warnings about deprecated features."); /* * PendingDeprecationWarning extends Warning */ SimpleExtendsException(PyExc_Warning, PendingDeprecationWarning, "Base class for warnings about features which will be deprecated\n" "in the future."); /* * SyntaxWarning extends Warning */ SimpleExtendsException(PyExc_Warning, SyntaxWarning, "Base class for warnings about dubious syntax."); /* * RuntimeWarning extends Warning */ SimpleExtendsException(PyExc_Warning, RuntimeWarning, "Base class for warnings about dubious runtime behavior."); /* * FutureWarning extends Warning */ SimpleExtendsException(PyExc_Warning, FutureWarning, "Base class for warnings about constructs that will change semantically\n" "in the future."); /* * ImportWarning extends Warning */ SimpleExtendsException(PyExc_Warning, ImportWarning, "Base class for warnings about probable mistakes in module imports"); /* * UnicodeWarning extends Warning */ SimpleExtendsException(PyExc_Warning, UnicodeWarning, "Base class for warnings about Unicode related problems, mostly\n" "related to conversion problems."); /* * BytesWarning extends Warning */ SimpleExtendsException(PyExc_Warning, BytesWarning, "Base class for warnings about bytes and buffer related problems, mostly\n" "related to conversion from str or comparing to str."); /* * EncodingWarning extends Warning */ SimpleExtendsException(PyExc_Warning, EncodingWarning, "Base class for warnings about encodings."); /* * ResourceWarning extends Warning */ SimpleExtendsException(PyExc_Warning, ResourceWarning, "Base class for warnings about resource usage."); #ifdef MS_WINDOWS #include /* The following constants were added to errno.h in VS2010 but have preferred WSA equivalents. */ #undef EADDRINUSE #undef EADDRNOTAVAIL #undef EAFNOSUPPORT #undef EALREADY #undef ECONNABORTED #undef ECONNREFUSED #undef ECONNRESET #undef EDESTADDRREQ #undef EHOSTUNREACH #undef EINPROGRESS #undef EISCONN #undef ELOOP #undef EMSGSIZE #undef ENETDOWN #undef ENETRESET #undef ENETUNREACH #undef ENOBUFS #undef ENOPROTOOPT #undef ENOTCONN #undef ENOTSOCK #undef EOPNOTSUPP #undef EPROTONOSUPPORT #undef EPROTOTYPE #undef ETIMEDOUT #undef EWOULDBLOCK #if defined(WSAEALREADY) && !defined(EALREADY) #define EALREADY WSAEALREADY #endif #if defined(WSAECONNABORTED) && !defined(ECONNABORTED) #define ECONNABORTED WSAECONNABORTED #endif #if defined(WSAECONNREFUSED) && !defined(ECONNREFUSED) #define ECONNREFUSED WSAECONNREFUSED #endif #if defined(WSAECONNRESET) && !defined(ECONNRESET) #define ECONNRESET WSAECONNRESET #endif #if defined(WSAEINPROGRESS) && !defined(EINPROGRESS) #define EINPROGRESS WSAEINPROGRESS #endif #if defined(WSAESHUTDOWN) && !defined(ESHUTDOWN) #define ESHUTDOWN WSAESHUTDOWN #endif #if defined(WSAETIMEDOUT) && !defined(ETIMEDOUT) #define ETIMEDOUT WSAETIMEDOUT #endif #if defined(WSAEWOULDBLOCK) && !defined(EWOULDBLOCK) #define EWOULDBLOCK WSAEWOULDBLOCK #endif #endif /* MS_WINDOWS */ struct static_exception { PyTypeObject *exc; const char *name; }; static struct static_exception static_exceptions[] = { #define ITEM(NAME) {&_PyExc_##NAME, #NAME} // Level 1 ITEM(BaseException), // Level 2: BaseException subclasses ITEM(BaseExceptionGroup), ITEM(Exception), ITEM(GeneratorExit), ITEM(KeyboardInterrupt), ITEM(SystemExit), // Level 3: Exception(BaseException) subclasses ITEM(ArithmeticError), ITEM(AssertionError), ITEM(AttributeError), ITEM(BufferError), ITEM(EOFError), //ITEM(ExceptionGroup), ITEM(ImportError), ITEM(LookupError), ITEM(MemoryError), ITEM(NameError), ITEM(OSError), ITEM(ReferenceError), ITEM(RuntimeError), ITEM(StopAsyncIteration), ITEM(StopIteration), ITEM(SyntaxError), ITEM(SystemError), ITEM(TypeError), ITEM(ValueError), ITEM(Warning), // Level 4: ArithmeticError(Exception) subclasses ITEM(FloatingPointError), ITEM(OverflowError), ITEM(ZeroDivisionError), // Level 4: Warning(Exception) subclasses ITEM(BytesWarning), ITEM(DeprecationWarning), ITEM(EncodingWarning), ITEM(FutureWarning), ITEM(ImportWarning), ITEM(PendingDeprecationWarning), ITEM(ResourceWarning), ITEM(RuntimeWarning), ITEM(SyntaxWarning), ITEM(UnicodeWarning), ITEM(UserWarning), // Level 4: OSError(Exception) subclasses ITEM(BlockingIOError), ITEM(ChildProcessError), ITEM(ConnectionError), ITEM(FileExistsError), ITEM(FileNotFoundError), ITEM(InterruptedError), ITEM(IsADirectoryError), ITEM(NotADirectoryError), ITEM(PermissionError), ITEM(ProcessLookupError), ITEM(TimeoutError), // Level 4: Other subclasses ITEM(IndentationError), // base: SyntaxError(Exception) ITEM(IndexError), // base: LookupError(Exception) ITEM(KeyError), // base: LookupError(Exception) ITEM(ModuleNotFoundError), // base: ImportError(Exception) ITEM(NotImplementedError), // base: RuntimeError(Exception) ITEM(RecursionError), // base: RuntimeError(Exception) ITEM(UnboundLocalError), // base: NameError(Exception) ITEM(UnicodeError), // base: ValueError(Exception) // Level 5: ConnectionError(OSError) subclasses ITEM(BrokenPipeError), ITEM(ConnectionAbortedError), ITEM(ConnectionRefusedError), ITEM(ConnectionResetError), // Level 5: IndentationError(SyntaxError) subclasses ITEM(TabError), // base: IndentationError // Level 5: UnicodeError(ValueError) subclasses ITEM(UnicodeDecodeError), ITEM(UnicodeEncodeError), ITEM(UnicodeTranslateError), #undef ITEM }; int _PyExc_InitTypes(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { return 0; } for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) { PyTypeObject *exc = static_exceptions[i].exc; if (_PyStaticType_InitBuiltin(exc) < 0) { return -1; } } return 0; } static void _PyExc_FiniTypes(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { return; } for (Py_ssize_t i=Py_ARRAY_LENGTH(static_exceptions) - 1; i >= 0; i--) { PyTypeObject *exc = static_exceptions[i].exc; _PyStaticType_Dealloc(exc); } } PyStatus _PyExc_InitGlobalObjects(PyInterpreterState *interp) { if (!_Py_IsMainInterpreter(interp)) { return _PyStatus_OK(); } if (preallocate_memerrors() < 0) { return _PyStatus_NO_MEMORY(); } return _PyStatus_OK(); } PyStatus _PyExc_InitState(PyInterpreterState *interp) { struct _Py_exc_state *state = &interp->exc_state; #define ADD_ERRNO(TYPE, CODE) \ do { \ PyObject *_code = PyLong_FromLong(CODE); \ assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ if (!_code || PyDict_SetItem(state->errnomap, _code, PyExc_ ## TYPE)) { \ Py_XDECREF(_code); \ return _PyStatus_ERR("errmap insertion problem."); \ } \ Py_DECREF(_code); \ } while (0) /* Add exceptions to errnomap */ assert(state->errnomap == NULL); state->errnomap = PyDict_New(); if (!state->errnomap) { return _PyStatus_NO_MEMORY(); } ADD_ERRNO(BlockingIOError, EAGAIN); ADD_ERRNO(BlockingIOError, EALREADY); ADD_ERRNO(BlockingIOError, EINPROGRESS); ADD_ERRNO(BlockingIOError, EWOULDBLOCK); ADD_ERRNO(BrokenPipeError, EPIPE); #ifdef ESHUTDOWN ADD_ERRNO(BrokenPipeError, ESHUTDOWN); #endif ADD_ERRNO(ChildProcessError, ECHILD); ADD_ERRNO(ConnectionAbortedError, ECONNABORTED); ADD_ERRNO(ConnectionRefusedError, ECONNREFUSED); ADD_ERRNO(ConnectionResetError, ECONNRESET); ADD_ERRNO(FileExistsError, EEXIST); ADD_ERRNO(FileNotFoundError, ENOENT); ADD_ERRNO(IsADirectoryError, EISDIR); ADD_ERRNO(NotADirectoryError, ENOTDIR); ADD_ERRNO(InterruptedError, EINTR); ADD_ERRNO(PermissionError, EACCES); ADD_ERRNO(PermissionError, EPERM); ADD_ERRNO(ProcessLookupError, ESRCH); ADD_ERRNO(TimeoutError, ETIMEDOUT); return _PyStatus_OK(); #undef ADD_ERRNO } /* Add exception types to the builtins module */ int _PyBuiltins_AddExceptions(PyObject *bltinmod) { PyObject *mod_dict = PyModule_GetDict(bltinmod); if (mod_dict == NULL) { return -1; } for (size_t i=0; i < Py_ARRAY_LENGTH(static_exceptions); i++) { struct static_exception item = static_exceptions[i]; if (PyDict_SetItemString(mod_dict, item.name, (PyObject*)item.exc)) { return -1; } } PyObject *PyExc_ExceptionGroup = create_exception_group_class(); if (!PyExc_ExceptionGroup) { return -1; } if (PyDict_SetItemString(mod_dict, "ExceptionGroup", PyExc_ExceptionGroup)) { return -1; } #define INIT_ALIAS(NAME, TYPE) \ do { \ PyExc_ ## NAME = PyExc_ ## TYPE; \ if (PyDict_SetItemString(mod_dict, # NAME, PyExc_ ## TYPE)) { \ return -1; \ } \ } while (0) INIT_ALIAS(EnvironmentError, OSError); INIT_ALIAS(IOError, OSError); #ifdef MS_WINDOWS INIT_ALIAS(WindowsError, OSError); #endif #undef INIT_ALIAS return 0; } void _PyExc_ClearExceptionGroupType(PyInterpreterState *interp) { struct _Py_exc_state *state = &interp->exc_state; Py_CLEAR(state->PyExc_ExceptionGroup); } void _PyExc_Fini(PyInterpreterState *interp) { struct _Py_exc_state *state = &interp->exc_state; free_preallocated_memerrors(state); Py_CLEAR(state->errnomap); _PyExc_FiniTypes(interp); } /* Helper to do the equivalent of "raise X from Y" in C, but always using * the current exception rather than passing one in. * * We currently limit this to *only* exceptions that use the BaseException * tp_init and tp_new methods, since we can be reasonably sure we can wrap * those correctly without losing data and without losing backwards * compatibility. * * We also aim to rule out *all* exceptions that might be storing additional * state, whether by having a size difference relative to BaseException, * additional arguments passed in during construction or by having a * non-empty instance dict. * * We need to be very careful with what we wrap, since changing types to * a broader exception type would be backwards incompatible for * existing codecs, and with different init or new method implementations * may either not support instantiation with PyErr_Format or lose * information when instantiated that way. * * XXX (ncoghlan): This could be made more comprehensive by exploiting the * fact that exceptions are expected to support pickling. If more builtin * exceptions (e.g. AttributeError) start to be converted to rich * exceptions with additional attributes, that's probably a better approach * to pursue over adding special cases for particular stateful subclasses. * * Returns a borrowed reference to the new exception (if any), NULL if the * existing exception was left in place. */ PyObject * _PyErr_TrySetFromCause(const char *format, ...) { PyObject* msg_prefix; PyObject *exc, *val, *tb; PyTypeObject *caught_type; PyObject *instance_args; Py_ssize_t num_args, caught_type_size, base_exc_size; PyObject *new_exc, *new_val, *new_tb; va_list vargs; int same_basic_size; PyErr_Fetch(&exc, &val, &tb); caught_type = (PyTypeObject *)exc; /* Ensure type info indicates no extra state is stored at the C level * and that the type can be reinstantiated using PyErr_Format */ caught_type_size = caught_type->tp_basicsize; base_exc_size = _PyExc_BaseException.tp_basicsize; same_basic_size = ( caught_type_size == base_exc_size || (_PyType_SUPPORTS_WEAKREFS(caught_type) && (caught_type_size == base_exc_size + (Py_ssize_t)sizeof(PyObject *)) ) ); if (caught_type->tp_init != (initproc)BaseException_init || caught_type->tp_new != BaseException_new || !same_basic_size || caught_type->tp_itemsize != _PyExc_BaseException.tp_itemsize) { /* We can't be sure we can wrap this safely, since it may contain * more state than just the exception type. Accordingly, we just * leave it alone. */ PyErr_Restore(exc, val, tb); return NULL; } /* Check the args are empty or contain a single string */ PyErr_NormalizeException(&exc, &val, &tb); instance_args = ((PyBaseExceptionObject *)val)->args; num_args = PyTuple_GET_SIZE(instance_args); if (num_args > 1 || (num_args == 1 && !PyUnicode_CheckExact(PyTuple_GET_ITEM(instance_args, 0)))) { /* More than 1 arg, or the one arg we do have isn't a string */ PyErr_Restore(exc, val, tb); return NULL; } /* Ensure the instance dict is also empty */ if (!_PyObject_IsInstanceDictEmpty(val)) { /* While we could potentially copy a non-empty instance dictionary * to the replacement exception, for now we take the more * conservative path of leaving exceptions with attributes set * alone. */ PyErr_Restore(exc, val, tb); return NULL; } /* For exceptions that we can wrap safely, we chain the original * exception to a new one of the exact same type with an * error message that mentions the additional details and the * original exception. * * It would be nice to wrap OSError and various other exception * types as well, but that's quite a bit trickier due to the extra * state potentially stored on OSError instances. */ /* Ensure the traceback is set correctly on the existing exception */ if (tb != NULL) { PyException_SetTraceback(val, tb); Py_DECREF(tb); } va_start(vargs, format); msg_prefix = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (msg_prefix == NULL) { Py_DECREF(exc); Py_DECREF(val); return NULL; } PyErr_Format(exc, "%U (%s: %S)", msg_prefix, Py_TYPE(val)->tp_name, val); Py_DECREF(exc); Py_DECREF(msg_prefix); PyErr_Fetch(&new_exc, &new_val, &new_tb); PyErr_NormalizeException(&new_exc, &new_val, &new_tb); PyException_SetCause(new_val, val); PyErr_Restore(new_exc, new_val, new_tb); return new_val; }