diff options
Diffstat (limited to 'Objects/exceptions.c')
-rw-r--r-- | Objects/exceptions.c | 937 |
1 files changed, 692 insertions, 245 deletions
diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 9daa12a..9e10b7e 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -10,6 +10,20 @@ #include "osdefs.h" +/* Compatibility aliases */ +PyObject *PyExc_EnvironmentError = NULL; +PyObject *PyExc_IOError = NULL; +#ifdef MS_WINDOWS +PyObject *PyExc_WindowsError = NULL; +#endif +#ifdef __VMS +PyObject *PyExc_VMSError = NULL; +#endif + +/* The dict map from errno codes to OSError subclasses */ +static PyObject *errnomap = NULL; + + /* NOTE: If the exception class hierarchy changes, don't forget to update * Lib/test/exception_hierarchy.txt */ @@ -28,6 +42,7 @@ BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /* the dict is created on the fly in PyObject_GenericSetAttr */ self->dict = NULL; self->traceback = self->cause = self->context = NULL; + self->suppress_context = 0; self->args = PyTuple_New(0); if (!self->args) { @@ -44,7 +59,7 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1; - Py_DECREF(self->args); + Py_XDECREF(self->args); self->args = args; Py_INCREF(self->args); @@ -163,36 +178,6 @@ static PyMethodDef BaseException_methods[] = { {NULL, NULL, 0, NULL}, }; - -static PyObject * -BaseException_get_dict(PyBaseExceptionObject *self) -{ - if (self->dict == NULL) { - self->dict = PyDict_New(); - if (!self->dict) - return NULL; - } - Py_INCREF(self->dict); - return self->dict; -} - -static int -BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val) -{ - if (val == NULL) { - PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); - return -1; - } - if (!PyDict_Check(val)) { - PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); - return -1; - } - Py_CLEAR(self->dict); - Py_INCREF(val); - self->dict = val; - return 0; -} - static PyObject * BaseException_get_args(PyBaseExceptionObject *self) { @@ -306,7 +291,7 @@ BaseException_set_cause(PyObject *self, PyObject *arg) { static PyGetSetDef BaseException_getset[] = { - {"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict}, + {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, {"__traceback__", (getter)BaseException_get_tb, (setter)BaseException_set_tb}, {"__context__", (getter)BaseException_get_context, @@ -342,6 +327,7 @@ void PyException_SetCause(PyObject *self, PyObject *cause) { PyObject *old_cause = ((PyBaseExceptionObject *)self)->cause; ((PyBaseExceptionObject *)self)->cause = cause; + ((PyBaseExceptionObject *)self)->suppress_context = 1; Py_XDECREF(old_cause); } @@ -361,6 +347,13 @@ PyException_SetContext(PyObject *self, PyObject *context) { } +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*/ @@ -391,7 +384,7 @@ static PyTypeObject _PyExc_BaseException = { 0, /* tp_iter */ 0, /* tp_iternext */ BaseException_methods, /* tp_methods */ - 0, /* tp_members */ + BaseException_members, /* tp_members */ BaseException_getset, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ @@ -436,11 +429,13 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \ 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, BaseException_new,\ + (initproc)EXCSTORE ## _init, 0, 0, \ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME -#define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDEALLOC, EXCMETHODS, EXCMEMBERS, EXCSTR, EXCDOC) \ +#define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCNEW, \ + EXCMETHODS, EXCMEMBERS, EXCGETSET, \ + EXCSTR, EXCDOC) \ static PyTypeObject _PyExc_ ## EXCNAME = { \ PyVarObject_HEAD_INIT(NULL, 0) \ # EXCNAME, \ @@ -450,9 +445,9 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \ 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, 0, &_ ## EXCBASE, \ + EXCMEMBERS, EXCGETSET, &_ ## EXCBASE, \ 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ - (initproc)EXCSTORE ## _init, 0, BaseException_new,\ + (initproc)EXCSTORE ## _init, 0, EXCNEW,\ }; \ PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME @@ -474,8 +469,70 @@ SimpleExtendsException(PyExc_Exception, TypeError, /* * StopIteration extends Exception */ -SimpleExtendsException(PyExc_Exception, StopIteration, - "Signal the end from iterator.__next__()."); + +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); +} + +PyObject * +PyStopIteration_Create(PyObject *value) +{ + return PyObject_CallFunctionObjArgs(PyExc_StopIteration, value, NULL); +} + +ComplexExtendsException( + PyExc_Exception, /* base */ + StopIteration, /* name */ + StopIteration, /* prefix for *_init, etc */ + 0, /* new */ + 0, /* methods */ + StopIteration_members, /* members */ + 0, /* getset */ + 0, /* str */ + "Signal the end from iterator.__next__()." +); /* @@ -502,7 +559,7 @@ SystemExit_init(PySystemExitObject *self, PyObject *args, PyObject *kwds) Py_CLEAR(self->code); if (size == 1) self->code = PyTuple_GET_ITEM(args, 0); - else if (size > 1) + else /* size > 1 */ self->code = args; Py_INCREF(self->code); return 0; @@ -537,7 +594,7 @@ static PyMemberDef SystemExit_members[] = { }; ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, - SystemExit_dealloc, 0, SystemExit_members, 0, + 0, 0, SystemExit_members, 0, 0, "Request to exit from the interpreter."); /* @@ -550,129 +607,435 @@ SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, /* * ImportError extends Exception */ -SimpleExtendsException(PyExc_Exception, ImportError, - "Import can't find module, or can't find name in module."); +static int +ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *msg = NULL; + PyObject *name = NULL; + PyObject *path = NULL; + +/* Macro replacement doesn't allow ## to start the first line of a macro, + so we move the assignment and NULL check into the if-statement. */ +#define GET_KWD(kwd) { \ + kwd = PyDict_GetItemString(kwds, #kwd); \ + if (kwd) { \ + Py_CLEAR(self->kwd); \ + self->kwd = kwd; \ + Py_INCREF(self->kwd);\ + if (PyDict_DelItemString(kwds, #kwd)) \ + return -1; \ + } \ + } + + if (kwds) { + GET_KWD(name); + GET_KWD(path); + } + + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + if (PyTuple_GET_SIZE(args) != 1) + return 0; + if (!PyArg_UnpackTuple(args, "ImportError", 1, 1, &msg)) + return -1; + + Py_CLEAR(self->msg); /* replacing */ + self->msg = msg; + Py_INCREF(self->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) { + Py_INCREF(self->msg); + return self->msg; + } + else { + return BaseException_str((PyBaseExceptionObject *)self); + } +} + +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[] = { + {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."); /* - * EnvironmentError extends Exception + * 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 IOError, (errno, strerror): + * 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. */ + +/* This function doesn't cleanup on error, the caller should */ static int -EnvironmentError_init(PyEnvironmentErrorObject *self, PyObject *args, - PyObject *kwds) +oserror_parse_args(PyObject **p_args, + PyObject **myerrno, PyObject **strerror, + PyObject **filename +#ifdef MS_WINDOWS + , PyObject **winerror +#endif + ) { - PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL; - PyObject *subslice = NULL; + Py_ssize_t nargs; + PyObject *args = *p_args; - if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) - return -1; + nargs = PyTuple_GET_SIZE(args); - if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3) { - return 0; +#ifdef MS_WINDOWS + if (nargs >= 2 && nargs <= 4) { + if (!PyArg_UnpackTuple(args, "OSError", 2, 4, + myerrno, strerror, filename, winerror)) + return -1; + 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; + /* Set errno to the corresponding POSIX errno (overriding + first argument). Windows Socket error codes (>= 10000) + have the same value as their POSIX counterparts. + */ + if (winerrcode < 10000) + errcode = winerror_to_errno(winerrcode); + else + errcode = 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; + } } +#else + if (nargs >= 2 && nargs <= 3) { + if (!PyArg_UnpackTuple(args, "OSError", 2, 3, + myerrno, strerror, filename)) + return -1; + } +#endif - if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, - &myerrno, &strerror, &filename)) { - return -1; + return 0; +} + +static int +oserror_init(PyOSErrorObject *self, PyObject **p_args, + PyObject *myerrno, PyObject *strerror, + PyObject *filename +#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_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 (nargs >= 2 && nargs <= 3) { + /* filename is 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_CLEAR(self->myerrno); /* replacing */ + Py_XINCREF(myerrno); self->myerrno = myerrno; - Py_INCREF(self->myerrno); - Py_CLEAR(self->strerror); /* replacing */ + Py_XINCREF(strerror); self->strerror = strerror; - Py_INCREF(self->strerror); - /* self->filename will remain Py_None otherwise */ - if (filename != NULL) { - Py_CLEAR(self->filename); /* replacing */ - self->filename = filename; - Py_INCREF(self->filename); +#ifdef MS_WINDOWS + Py_XINCREF(winerror); + self->winerror = winerror; +#endif - subslice = PyTuple_GetSlice(args, 0, 2); - if (!subslice) - return -1; + /* Steals the reference to args */ + self->args = 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 a 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 overriden 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, *filename = NULL; +#ifdef MS_WINDOWS + PyObject *winerror = NULL; +#endif + + if (!oserror_use_init(type)) { + if (!_PyArg_NoKeywords(type->tp_name, kwds)) + return NULL; + + Py_INCREF(args); + if (oserror_parse_args(&args, &myerrno, &strerror, &filename +#ifdef MS_WINDOWS + , &winerror +#endif + )) + goto error; + + if (myerrno && PyLong_Check(myerrno) && + errnomap && (PyObject *) type == PyExc_OSError) { + PyObject *newtype; + newtype = PyDict_GetItem(errnomap, myerrno); + if (newtype) { + assert(PyType_Check(newtype)); + type = (PyTypeObject *) newtype; + } + else if (PyErr_Occurred()) + goto error; + } + } + + self = (PyOSErrorObject *) type->tp_alloc(type, 0); + if (!self) + goto error; - Py_DECREF(self->args); /* replacing args */ - self->args = subslice; + 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 +#ifdef MS_WINDOWS + , winerror +#endif + )) + goto error; } + + 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, *filename = 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 +#ifdef MS_WINDOWS + , &winerror +#endif + )) + goto error; + + if (oserror_init(self, &args, myerrno, strerror, filename +#ifdef MS_WINDOWS + , winerror +#endif + )) + goto error; + return 0; + +error: + Py_XDECREF(args); + return -1; } static int -EnvironmentError_clear(PyEnvironmentErrorObject *self) +OSError_clear(PyOSErrorObject *self) { Py_CLEAR(self->myerrno); Py_CLEAR(self->strerror); Py_CLEAR(self->filename); +#ifdef MS_WINDOWS + Py_CLEAR(self->winerror); +#endif return BaseException_clear((PyBaseExceptionObject *)self); } static void -EnvironmentError_dealloc(PyEnvironmentErrorObject *self) +OSError_dealloc(PyOSErrorObject *self) { _PyObject_GC_UNTRACK(self); - EnvironmentError_clear(self); + OSError_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); } static int -EnvironmentError_traverse(PyEnvironmentErrorObject *self, visitproc visit, +OSError_traverse(PyOSErrorObject *self, visitproc visit, void *arg) { Py_VISIT(self->myerrno); Py_VISIT(self->strerror); Py_VISIT(self->filename); +#ifdef MS_WINDOWS + Py_VISIT(self->winerror); +#endif return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); } static PyObject * -EnvironmentError_str(PyEnvironmentErrorObject *self) +OSError_str(PyOSErrorObject *self) { +#ifdef MS_WINDOWS + /* If available, winerror has the priority over myerrno */ + if (self->winerror && self->filename) + return PyUnicode_FromFormat("[Error %S] %S: %R", + self->winerror ? self->winerror: Py_None, + self->strerror ? self->strerror: Py_None, + self->filename); + if (self->winerror && self->strerror) + return PyUnicode_FromFormat("[Error %S] %S", + self->winerror ? self->winerror: Py_None, + self->strerror ? self->strerror: Py_None); +#endif if (self->filename) return PyUnicode_FromFormat("[Errno %S] %S: %R", self->myerrno ? self->myerrno: Py_None, self->strerror ? self->strerror: Py_None, self->filename); - else if (self->myerrno && self->strerror) + if (self->myerrno && self->strerror) return PyUnicode_FromFormat("[Errno %S] %S", self->myerrno ? self->myerrno: Py_None, self->strerror ? self->strerror: Py_None); - else - return BaseException_str((PyBaseExceptionObject *)self); + return BaseException_str((PyBaseExceptionObject *)self); } -static PyMemberDef EnvironmentError_members[] = { - {"errno", T_OBJECT, offsetof(PyEnvironmentErrorObject, myerrno), 0, - PyDoc_STR("exception errno")}, - {"strerror", T_OBJECT, offsetof(PyEnvironmentErrorObject, strerror), 0, - PyDoc_STR("exception strerror")}, - {"filename", T_OBJECT, offsetof(PyEnvironmentErrorObject, filename), 0, - PyDoc_STR("exception filename")}, - {NULL} /* Sentinel */ -}; - - static PyObject * -EnvironmentError_reduce(PyEnvironmentErrorObject *self) +OSError_reduce(PyOSErrorObject *self) { 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 EnvironmentError. */ + * file name given to OSError. */ if (PyTuple_GET_SIZE(args) == 2 && self->filename) { args = PyTuple_New(3); if (!args) @@ -699,144 +1062,93 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self) return res; } - -static PyMethodDef EnvironmentError_methods[] = { - {"__reduce__", (PyCFunction)EnvironmentError_reduce, METH_NOARGS}, - {NULL} -}; - -ComplexExtendsException(PyExc_Exception, EnvironmentError, - EnvironmentError, EnvironmentError_dealloc, - EnvironmentError_methods, EnvironmentError_members, - EnvironmentError_str, - "Base class for I/O related errors."); - - -/* - * IOError extends EnvironmentError - */ -MiddlingExtendsException(PyExc_EnvironmentError, IOError, - EnvironmentError, "I/O operation failed."); - - -/* - * OSError extends EnvironmentError - */ -MiddlingExtendsException(PyExc_EnvironmentError, OSError, - EnvironmentError, "OS system call failed."); - - -/* - * WindowsError extends OSError - */ -#ifdef MS_WINDOWS -#include "errmap.h" - -static int -WindowsError_clear(PyWindowsErrorObject *self) -{ - Py_CLEAR(self->myerrno); - Py_CLEAR(self->strerror); - Py_CLEAR(self->filename); - Py_CLEAR(self->winerror); - return BaseException_clear((PyBaseExceptionObject *)self); -} - -static void -WindowsError_dealloc(PyWindowsErrorObject *self) -{ - _PyObject_GC_UNTRACK(self); - WindowsError_clear(self); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -static int -WindowsError_traverse(PyWindowsErrorObject *self, visitproc visit, void *arg) +static PyObject * +OSError_written_get(PyOSErrorObject *self, void *context) { - Py_VISIT(self->myerrno); - Py_VISIT(self->strerror); - Py_VISIT(self->filename); - Py_VISIT(self->winerror); - return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); + if (self->written == -1) { + PyErr_SetString(PyExc_AttributeError, "characters_written"); + return NULL; + } + return PyLong_FromSsize_t(self->written); } static int -WindowsError_init(PyWindowsErrorObject *self, PyObject *args, PyObject *kwds) +OSError_written_set(PyOSErrorObject *self, PyObject *arg, void *context) { - PyObject *o_errcode = NULL; - long errcode; - long posix_errno; - - if (EnvironmentError_init((PyEnvironmentErrorObject *)self, args, kwds) - == -1) + Py_ssize_t n; + n = PyNumber_AsSsize_t(arg, PyExc_ValueError); + if (n == -1 && PyErr_Occurred()) return -1; - - if (self->myerrno == NULL) - return 0; - - /* Set errno to the POSIX errno, and winerror to the Win32 - error code. */ - errcode = PyLong_AsLong(self->myerrno); - if (errcode == -1 && PyErr_Occurred()) - return -1; - posix_errno = winerror_to_errno(errcode); - - Py_CLEAR(self->winerror); - self->winerror = self->myerrno; - - o_errcode = PyLong_FromLong(posix_errno); - if (!o_errcode) - return -1; - - self->myerrno = o_errcode; - + self->written = n; return 0; } - -static PyObject * -WindowsError_str(PyWindowsErrorObject *self) -{ - if (self->filename) - return PyUnicode_FromFormat("[Error %S] %S: %R", - self->winerror ? self->winerror: Py_None, - self->strerror ? self->strerror: Py_None, - self->filename); - else if (self->winerror && self->strerror) - return PyUnicode_FromFormat("[Error %S] %S", - self->winerror ? self->winerror: Py_None, - self->strerror ? self->strerror: Py_None); - else - return EnvironmentError_str((PyEnvironmentErrorObject *)self); -} - -static PyMemberDef WindowsError_members[] = { - {"errno", T_OBJECT, offsetof(PyWindowsErrorObject, myerrno), 0, +static PyMemberDef OSError_members[] = { + {"errno", T_OBJECT, offsetof(PyOSErrorObject, myerrno), 0, PyDoc_STR("POSIX exception code")}, - {"strerror", T_OBJECT, offsetof(PyWindowsErrorObject, strerror), 0, + {"strerror", T_OBJECT, offsetof(PyOSErrorObject, strerror), 0, PyDoc_STR("exception strerror")}, - {"filename", T_OBJECT, offsetof(PyWindowsErrorObject, filename), 0, + {"filename", T_OBJECT, offsetof(PyOSErrorObject, filename), 0, PyDoc_STR("exception filename")}, - {"winerror", T_OBJECT, offsetof(PyWindowsErrorObject, winerror), 0, +#ifdef MS_WINDOWS + {"winerror", T_OBJECT, offsetof(PyOSErrorObject, winerror), 0, PyDoc_STR("Win32 exception code")}, +#endif {NULL} /* Sentinel */ }; -ComplexExtendsException(PyExc_OSError, WindowsError, WindowsError, - WindowsError_dealloc, 0, WindowsError_members, - WindowsError_str, "MS-Windows OS system call failed."); +static PyMethodDef OSError_methods[] = { + {"__reduce__", (PyCFunction)OSError_reduce, METH_NOARGS}, + {NULL} +}; -#endif /* MS_WINDOWS */ +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."); /* - * VMSError extends OSError (I think) + * Various OSError subclasses */ -#ifdef __VMS -MiddlingExtendsException(PyExc_OSError, VMSError, EnvironmentError, - "OpenVMS OS system call failed."); -#endif - +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 @@ -967,21 +1279,23 @@ SyntaxError_traverse(PySyntaxErrorObject *self, visitproc visit, void *arg) static PyObject* my_basename(PyObject *name) { - Py_UNICODE *unicode; Py_ssize_t i, size, offset; + int kind; + void *data; - unicode = PyUnicode_AS_UNICODE(name); - size = PyUnicode_GET_SIZE(name); + 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 (unicode[i] == SEP) + if (PyUnicode_READ(kind, data, i) == SEP) offset = i + 1; } - if (offset != 0) { - return PyUnicode_FromUnicode( - PyUnicode_AS_UNICODE(name) + offset, - size - offset); - } else { + if (offset != 0) + return PyUnicode_Substring(name, offset, size); + else { Py_INCREF(name); return name; } @@ -1049,7 +1363,7 @@ static PyMemberDef SyntaxError_members[] = { }; ComplexExtendsException(PyExc_Exception, SyntaxError, SyntaxError, - SyntaxError_dealloc, 0, SyntaxError_members, + 0, 0, SyntaxError_members, 0, SyntaxError_str, "Invalid syntax."); @@ -1103,7 +1417,7 @@ KeyError_str(PyBaseExceptionObject *self) } ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, - 0, 0, 0, KeyError_str, "Mapping key not found."); + 0, 0, 0, 0, KeyError_str, "Mapping key not found."); /* @@ -1202,7 +1516,7 @@ PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start) if (!obj) return -1; *start = ((PyUnicodeErrorObject *)exc)->start; - size = PyUnicode_GET_SIZE(obj); + size = PyUnicode_GET_LENGTH(obj); if (*start<0) *start = 0; /*XXX check for values <0*/ if (*start>=size) @@ -1270,7 +1584,7 @@ PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end) if (!obj) return -1; *end = ((PyUnicodeErrorObject *)exc)->end; - size = PyUnicode_GET_SIZE(obj); + size = PyUnicode_GET_LENGTH(obj); if (*end<1) *end = 1; if (*end>size) @@ -1442,6 +1756,11 @@ UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) return -1; } + if (PyUnicode_READY(err->object) < -1) { + err->encoding = NULL; + return -1; + } + Py_INCREF(err->encoding); Py_INCREF(err->object); Py_INCREF(err->reason); @@ -1466,8 +1785,8 @@ UnicodeEncodeError_str(PyObject *self) if (encoding_str == NULL) goto done; - if (uself->start < PyUnicode_GET_SIZE(uself->object) && uself->end == uself->start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(uself->object)[uself->start]; + 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"; @@ -1478,7 +1797,7 @@ UnicodeEncodeError_str(PyObject *self) result = PyUnicode_FromFormat( fmt, encoding_str, - badchar, + (int)badchar, uself->start, reason_str); } @@ -1675,8 +1994,8 @@ UnicodeTranslateError_str(PyObject *self) if (reason_str == NULL) goto done; - if (uself->start < PyUnicode_GET_SIZE(uself->object) && uself->end == uself->start+1) { - int badchar = (int)PyUnicode_AS_UNICODE(uself->object)[uself->start]; + 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"; @@ -1686,7 +2005,7 @@ UnicodeTranslateError_str(PyObject *self) fmt = "can't translate character '\\U%08x' in position %zd: %U"; result = PyUnicode_FromFormat( fmt, - badchar, + (int)badchar, uself->start, reason_str ); @@ -1717,6 +2036,7 @@ static PyTypeObject _PyExc_UnicodeTranslateError = { }; PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError; +/* Deprecated. */ PyObject * PyUnicodeTranslateError_Create( const Py_UNICODE *object, Py_ssize_t length, @@ -1726,6 +2046,14 @@ PyUnicodeTranslateError_Create( object, length, start, end, reason); } +PyObject * +_PyUnicodeTranslateError_Create( + PyObject *object, + Py_ssize_t start, Py_ssize_t end, const char *reason) +{ + return PyObject_CallFunction(PyExc_UnicodeTranslateError, "Ons", + object, start, end, reason); +} /* * AssertionError extends Exception @@ -1975,11 +2303,80 @@ PyObject *PyExc_RecursionErrorInst = NULL; if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \ Py_FatalError("Module dictionary insertion problem."); +#define INIT_ALIAS(NAME, TYPE) Py_INCREF(PyExc_ ## TYPE); \ + Py_XDECREF(PyExc_ ## NAME); \ + PyExc_ ## NAME = PyExc_ ## TYPE; \ + if (PyDict_SetItemString(bdict, # NAME, PyExc_ ## NAME)) \ + Py_FatalError("Module dictionary insertion problem."); + +#define ADD_ERRNO(TYPE, CODE) { \ + PyObject *_code = PyLong_FromLong(CODE); \ + assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ + if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) \ + Py_FatalError("errmap insertion problem."); \ + Py_DECREF(_code); \ + } + +#ifdef MS_WINDOWS +#include <Winsock2.h> +/* 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 */ void -_PyExc_Init(void) +_PyExc_Init(PyObject *bltinmod) { - PyObject *bltinmod, *bdict; + PyObject *bdict; PRE_INIT(BaseException) PRE_INIT(Exception) @@ -1989,15 +2386,7 @@ _PyExc_Init(void) PRE_INIT(SystemExit) PRE_INIT(KeyboardInterrupt) PRE_INIT(ImportError) - PRE_INIT(EnvironmentError) - PRE_INIT(IOError) PRE_INIT(OSError) -#ifdef MS_WINDOWS - PRE_INIT(WindowsError) -#endif -#ifdef __VMS - PRE_INIT(VMSError) -#endif PRE_INIT(EOFError) PRE_INIT(RuntimeError) PRE_INIT(NotImplementedError) @@ -2037,9 +2426,24 @@ _PyExc_Init(void) PRE_INIT(BytesWarning) PRE_INIT(ResourceWarning) - bltinmod = PyImport_ImportModule("builtins"); - if (bltinmod == NULL) - Py_FatalError("exceptions bootstrapping error."); + /* OSError subclasses */ + PRE_INIT(ConnectionError); + + PRE_INIT(BlockingIOError); + PRE_INIT(BrokenPipeError); + PRE_INIT(ChildProcessError); + PRE_INIT(ConnectionAbortedError); + PRE_INIT(ConnectionRefusedError); + PRE_INIT(ConnectionResetError); + PRE_INIT(FileExistsError); + PRE_INIT(FileNotFoundError); + PRE_INIT(IsADirectoryError); + PRE_INIT(NotADirectoryError); + PRE_INIT(InterruptedError); + PRE_INIT(PermissionError); + PRE_INIT(ProcessLookupError); + PRE_INIT(TimeoutError); + bdict = PyModule_GetDict(bltinmod); if (bdict == NULL) Py_FatalError("exceptions bootstrapping error."); @@ -2052,14 +2456,14 @@ _PyExc_Init(void) POST_INIT(SystemExit) POST_INIT(KeyboardInterrupt) POST_INIT(ImportError) - POST_INIT(EnvironmentError) - POST_INIT(IOError) POST_INIT(OSError) + INIT_ALIAS(EnvironmentError, OSError) + INIT_ALIAS(IOError, OSError) #ifdef MS_WINDOWS - POST_INIT(WindowsError) + INIT_ALIAS(WindowsError, OSError) #endif #ifdef __VMS - POST_INIT(VMSError) + INIT_ALIAS(VMSError, OSError) #endif POST_INIT(EOFError) POST_INIT(RuntimeError) @@ -2100,6 +2504,49 @@ _PyExc_Init(void) POST_INIT(BytesWarning) POST_INIT(ResourceWarning) + if (!errnomap) { + errnomap = PyDict_New(); + if (!errnomap) + Py_FatalError("Cannot allocate map from errnos to OSError subclasses"); + } + + /* OSError subclasses */ + POST_INIT(ConnectionError); + + POST_INIT(BlockingIOError); + ADD_ERRNO(BlockingIOError, EAGAIN); + ADD_ERRNO(BlockingIOError, EALREADY); + ADD_ERRNO(BlockingIOError, EINPROGRESS); + ADD_ERRNO(BlockingIOError, EWOULDBLOCK); + POST_INIT(BrokenPipeError); + ADD_ERRNO(BrokenPipeError, EPIPE); + ADD_ERRNO(BrokenPipeError, ESHUTDOWN); + POST_INIT(ChildProcessError); + ADD_ERRNO(ChildProcessError, ECHILD); + POST_INIT(ConnectionAbortedError); + ADD_ERRNO(ConnectionAbortedError, ECONNABORTED); + POST_INIT(ConnectionRefusedError); + ADD_ERRNO(ConnectionRefusedError, ECONNREFUSED); + POST_INIT(ConnectionResetError); + ADD_ERRNO(ConnectionResetError, ECONNRESET); + POST_INIT(FileExistsError); + ADD_ERRNO(FileExistsError, EEXIST); + POST_INIT(FileNotFoundError); + ADD_ERRNO(FileNotFoundError, ENOENT); + POST_INIT(IsADirectoryError); + ADD_ERRNO(IsADirectoryError, EISDIR); + POST_INIT(NotADirectoryError); + ADD_ERRNO(NotADirectoryError, ENOTDIR); + POST_INIT(InterruptedError); + ADD_ERRNO(InterruptedError, EINTR); + POST_INIT(PermissionError); + ADD_ERRNO(PermissionError, EACCES); + ADD_ERRNO(PermissionError, EPERM); + POST_INIT(ProcessLookupError); + ADD_ERRNO(ProcessLookupError, ESRCH); + POST_INIT(TimeoutError); + ADD_ERRNO(TimeoutError, ETIMEDOUT); + preallocate_memerrors(); if (!PyExc_RecursionErrorInst) { @@ -2126,7 +2573,6 @@ _PyExc_Init(void) Py_DECREF(args_tuple); } } - Py_DECREF(bltinmod); } void @@ -2134,4 +2580,5 @@ _PyExc_Fini(void) { Py_CLEAR(PyExc_RecursionErrorInst); free_preallocated_memerrors(); + Py_CLEAR(errnomap); } |