summaryrefslogtreecommitdiffstats
path: root/Objects/exceptions.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/exceptions.c')
-rw-r--r--Objects/exceptions.c937
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);
}