diff options
author | Brett Cannon <bcannon@gmail.com> | 2006-03-01 04:25:17 (GMT) |
---|---|---|
committer | Brett Cannon <bcannon@gmail.com> | 2006-03-01 04:25:17 (GMT) |
commit | bf36409e2a8171b441d5e0a2f1c9e02d31a35ae8 (patch) | |
tree | 7456cf3d197d6f0dc017b0f851878bcaf6024f6c /Python/exceptions.c | |
parent | 762467475d944f67ac20bf23c6c5144a6e39feae (diff) | |
download | cpython-bf36409e2a8171b441d5e0a2f1c9e02d31a35ae8.zip cpython-bf36409e2a8171b441d5e0a2f1c9e02d31a35ae8.tar.gz cpython-bf36409e2a8171b441d5e0a2f1c9e02d31a35ae8.tar.bz2 |
PEP 352 implementation. Creates a new base class, BaseException, which has an
added message attribute compared to the previous version of Exception. It is
also a new-style class, making all exceptions now new-style. KeyboardInterrupt
and SystemExit inherit from BaseException directly. String exceptions now
raise DeprecationWarning.
Applies patch 1104669, and closes bugs 1012952 and 518846.
Diffstat (limited to 'Python/exceptions.c')
-rw-r--r-- | Python/exceptions.c | 398 |
1 files changed, 245 insertions, 153 deletions
diff --git a/Python/exceptions.c b/Python/exceptions.c index c9e516f..59f2091 100644 --- a/Python/exceptions.c +++ b/Python/exceptions.c @@ -11,6 +11,7 @@ * 98-08-19 fl created (for pyexe) * 00-02-08 fl updated for 1.5.2 * 26-May-2000 baw vetted for Python 1.6 + * XXX * * written by Fredrik Lundh * modifications, additions, cleanups, and proofreading by Barry Warsaw @@ -33,99 +34,19 @@ PyDoc_STRVAR(module__doc__, "Python's standard exception class hierarchy.\n\ \n\ -Before Python 1.5, the standard exceptions were all simple string objects.\n\ -In Python 1.5, the standard exceptions were converted to classes organized\n\ -into a relatively flat hierarchy. String-based standard exceptions were\n\ -optional, or used as a fallback if some problem occurred while importing\n\ -the exception module. With Python 1.6, optional string-based standard\n\ -exceptions were removed (along with the -X command line flag).\n\ -\n\ -The class exceptions were implemented in such a way as to be almost\n\ -completely backward compatible. Some tricky uses of IOError could\n\ -potentially have broken, but by Python 1.6, all of these should have\n\ -been fixed. As of Python 1.6, the class-based standard exceptions are\n\ -now implemented in C, and are guaranteed to exist in the Python\n\ -interpreter.\n\ -\n\ -Here is a rundown of the class hierarchy. The classes found here are\n\ -inserted into both the exceptions module and the `built-in' module. It is\n\ -recommended that user defined class based exceptions be derived from the\n\ -`Exception' class, although this is currently not enforced.\n" +Exceptions found here are defined both in the exceptions module and the \n\ +built-in namespace. It is recommended that user-defined exceptions inherit \n\ +from Exception.\n\ +" + /* keep string pieces "small" */ -"\n\ -Exception\n\ - |\n\ - +-- SystemExit\n\ - +-- StopIteration\n\ - +-- GeneratorExit\n\ - +-- StandardError\n\ - | |\n\ - | +-- KeyboardInterrupt\n\ - | +-- ImportError\n\ - | +-- EnvironmentError\n\ - | | |\n\ - | | +-- IOError\n\ - | | +-- OSError\n\ - | | |\n\ - | | +-- WindowsError\n\ - | | +-- VMSError\n\ - | |\n\ - | +-- EOFError\n\ - | +-- RuntimeError\n\ - | | |\n\ - | | +-- NotImplementedError\n\ - | |\n\ - | +-- NameError\n\ - | | |\n\ - | | +-- UnboundLocalError\n\ - | |\n\ - | +-- AttributeError\n\ - | +-- SyntaxError\n\ - | | |\n\ - | | +-- IndentationError\n\ - | | |\n\ - | | +-- TabError\n\ - | |\n\ - | +-- TypeError\n\ - | +-- AssertionError\n\ - | +-- LookupError\n\ - | | |\n\ - | | +-- IndexError\n\ - | | +-- KeyError\n\ - | |\n\ - | +-- ArithmeticError\n\ - | | |\n\ - | | +-- OverflowError\n\ - | | +-- ZeroDivisionError\n\ - | | +-- FloatingPointError\n\ - | |\n\ - | +-- ValueError\n\ - | | |\n\ - | | +-- UnicodeError\n\ - | | |\n\ - | | +-- UnicodeEncodeError\n\ - | | +-- UnicodeDecodeError\n\ - | | +-- UnicodeTranslateError\n\ - | |\n\ - | +-- ReferenceError\n\ - | +-- SystemError\n\ - | +-- MemoryError\n\ - |\n\ - +---Warning\n\ - |\n\ - +-- UserWarning\n\ - +-- DeprecationWarning\n\ - +-- PendingDeprecationWarning\n\ - +-- SyntaxWarning\n\ - +-- OverflowWarning\n\ - +-- RuntimeWarning\n\ - +-- FutureWarning" +/* XXX exception hierarchy from Lib/test/exception_hierarchy.txt */ ); /* Helper function for populating a dictionary with method wrappers. */ static int -populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) +populate_methods(PyObject *klass, PyMethodDef *methods) { PyObject *module; int status = -1; @@ -151,7 +72,7 @@ populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) } /* add method to dictionary */ - status = PyDict_SetItemString(dict, methods->ml_name, meth); + status = PyObject_SetAttrString(klass, methods->ml_name, meth); Py_DECREF(meth); Py_DECREF(func); @@ -196,7 +117,7 @@ make_class(PyObject **klass, PyObject *base, if (!(*klass = PyErr_NewException(name, base, dict))) goto finally; - if (populate_methods(*klass, dict, methods)) { + if (populate_methods(*klass, methods)) { Py_DECREF(*klass); *klass = NULL; goto finally; @@ -232,47 +153,81 @@ get_self(PyObject *args) /* Notes on bootstrapping the exception classes. * * First thing we create is the base class for all exceptions, called - * appropriately enough: Exception. Creation of this class makes no + * appropriately BaseException. Creation of this class makes no * assumptions about the existence of any other exception class -- except * for TypeError, which can conditionally exist. * - * Next, StandardError is created (which is quite simple) followed by + * Next, Exception is created since it is the common subclass for the rest of + * the needed exceptions for this bootstrapping to work. StandardError is + * created (which is quite simple) followed by * TypeError, because the instantiation of other exceptions can potentially * throw a TypeError. Once these exceptions are created, all the others * can be created in any order. See the static exctable below for the * explicit bootstrap order. * - * All classes after Exception can be created using PyErr_NewException(). + * All classes after BaseException can be created using PyErr_NewException(). */ -PyDoc_STRVAR(Exception__doc__, "Common base class for all exceptions."); +PyDoc_STRVAR(BaseException__doc__, "Common base class for all exceptions"); +/* + Set args and message attributes. -static PyObject * -Exception__init__(PyObject *self, PyObject *args) + Assumes self and args have already been set properly with set_self, etc. +*/ +static int +set_args_and_message(PyObject *self, PyObject *args) { - int status; + PyObject *message_val; + Py_ssize_t args_len = PySequence_Length(args); + + if (args_len < 0) + return 0; + + /* set args */ + if (PyObject_SetAttrString(self, "args", args) < 0) + return 0; + + /* set message */ + if (args_len == 1) + message_val = PySequence_GetItem(args, 0); + else + message_val = PyString_FromString(""); + if (!message_val) + return 0; + + if (PyObject_SetAttrString(self, "message", message_val) < 0) { + Py_DECREF(message_val); + return 0; + } + + Py_DECREF(message_val); + return 1; +} +static PyObject * +BaseException__init__(PyObject *self, PyObject *args) +{ if (!(self = get_self(args))) return NULL; - /* set args attribute */ - /* XXX size is only a hint */ - args = PySequence_GetSlice(args, 1, PySequence_Size(args)); + /* set args and message attribute */ + args = PySequence_GetSlice(args, 1, PySequence_Length(args)); if (!args) return NULL; - status = PyObject_SetAttrString(self, "args", args); - Py_DECREF(args); - if (status < 0) - return NULL; - Py_INCREF(Py_None); - return Py_None; + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; + } + + Py_DECREF(args); + Py_RETURN_NONE; } static PyObject * -Exception__str__(PyObject *self, PyObject *args) +BaseException__str__(PyObject *self, PyObject *args) { PyObject *out; @@ -310,9 +265,116 @@ Exception__str__(PyObject *self, PyObject *args) return out; } +#ifdef Py_USING_UNICODE +static PyObject * +BaseException__unicode__(PyObject *self, PyObject *args) +{ + Py_ssize_t args_len; + + if (!PyArg_ParseTuple(args, "O:__unicode__", &self)) + return NULL; + + args = PyObject_GetAttrString(self, "args"); + if (!args) + return NULL; + + args_len = PySequence_Size(args); + if (args_len < 0) { + Py_DECREF(args); + return NULL; + } + + if (args_len == 0) { + Py_DECREF(args); + return PyUnicode_FromUnicode(NULL, 0); + } + else if (args_len == 1) { + PyObject *temp = PySequence_GetItem(args, 0); + if (!temp) { + Py_DECREF(args); + return NULL; + } + Py_DECREF(args); + return PyObject_Unicode(temp); + } + else { + Py_DECREF(args); + return PyObject_Unicode(args); + } +} +#endif /* Py_USING_UNICODE */ + +static PyObject * +BaseException__repr__(PyObject *self, PyObject *args) +{ + PyObject *args_attr; + Py_ssize_t args_len; + PyObject *repr_suffix; + PyObject *repr; + + if (!PyArg_ParseTuple(args, "O:__repr__", &self)) + return NULL; + + args_attr = PyObject_GetAttrString(self, "args"); + if (!args_attr) + return NULL; + + args_len = PySequence_Length(args_attr); + if (args_len < 0) { + Py_DECREF(args_attr); + return NULL; + } + + if (args_len == 0) { + Py_DECREF(args_attr); + repr_suffix = PyString_FromString("()"); + if (!repr_suffix) + return NULL; + } + else { + PyObject *args_repr; + /*PyObject *right_paren; + + repr_suffix = PyString_FromString("(*"); + if (!repr_suffix) { + Py_DECREF(args_attr); + return NULL; + }*/ + + args_repr = PyObject_Repr(args_attr); + Py_DECREF(args_attr); + if (!args_repr) + return NULL; + + repr_suffix = args_repr; + + /*PyString_ConcatAndDel(&repr_suffix, args_repr); + if (!repr_suffix) + return NULL; + + right_paren = PyString_FromString(")"); + if (!right_paren) { + Py_DECREF(repr_suffix); + return NULL; + } + + PyString_ConcatAndDel(&repr_suffix, right_paren); + if (!repr_suffix) + return NULL;*/ + } + + repr = PyString_FromString(self->ob_type->tp_name); + if (!repr) { + Py_DECREF(repr_suffix); + return NULL; + } + + PyString_ConcatAndDel(&repr, repr_suffix); + return repr; +} static PyObject * -Exception__getitem__(PyObject *self, PyObject *args) +BaseException__getitem__(PyObject *self, PyObject *args) { PyObject *out; PyObject *index; @@ -331,21 +393,27 @@ Exception__getitem__(PyObject *self, PyObject *args) static PyMethodDef -Exception_methods[] = { - /* methods for the Exception class */ - { "__getitem__", Exception__getitem__, METH_VARARGS}, - { "__str__", Exception__str__, METH_VARARGS}, - { "__init__", Exception__init__, METH_VARARGS}, - { NULL, NULL } +BaseException_methods[] = { + /* methods for the BaseException class */ + {"__getitem__", BaseException__getitem__, METH_VARARGS}, + {"__repr__", BaseException__repr__, METH_VARARGS}, + {"__str__", BaseException__str__, METH_VARARGS}, +#ifdef Py_USING_UNICODE + {"__unicode__", BaseException__unicode__, METH_VARARGS}, +#endif /* Py_USING_UNICODE */ + {"__init__", BaseException__init__, METH_VARARGS}, + {NULL, NULL } }; static int -make_Exception(char *modulename) +make_BaseException(char *modulename) { PyObject *dict = PyDict_New(); PyObject *str = NULL; PyObject *name = NULL; + PyObject *emptytuple = NULL; + PyObject *argstuple = NULL; int status = -1; if (!dict) @@ -360,20 +428,28 @@ make_Exception(char *modulename) if (PyDict_SetItemString(dict, "__module__", str)) goto finally; Py_DECREF(str); - if (!(str = PyString_FromString(Exception__doc__))) + + if (!(str = PyString_FromString(BaseException__doc__))) goto finally; if (PyDict_SetItemString(dict, "__doc__", str)) goto finally; - if (!(name = PyString_FromString("Exception"))) + if (!(name = PyString_FromString("BaseException"))) goto finally; - if (!(PyExc_Exception = PyClass_New(NULL, dict, name))) + if (!(emptytuple = PyTuple_New(0))) + goto finally; + + if (!(argstuple = PyTuple_Pack(3, name, emptytuple, dict))) + goto finally; + + if (!(PyExc_BaseException = PyType_Type.tp_new(&PyType_Type, argstuple, + NULL))) goto finally; /* Now populate the dictionary with the method suite */ - if (populate_methods(PyExc_Exception, dict, Exception_methods)) - /* Don't need to reclaim PyExc_Exception here because that'll + if (populate_methods(PyExc_BaseException, BaseException_methods)) + /* Don't need to reclaim PyExc_BaseException here because that'll * happen during interpreter shutdown. */ goto finally; @@ -384,13 +460,18 @@ make_Exception(char *modulename) Py_XDECREF(dict); Py_XDECREF(str); Py_XDECREF(name); + Py_XDECREF(emptytuple); + Py_XDECREF(argstuple); return status; } +PyDoc_STRVAR(Exception__doc__, "Common base class for all non-exit exceptions."); + PyDoc_STRVAR(StandardError__doc__, -"Base class for all standard Python exceptions."); +"Base class for all standard Python exceptions that do not represent" +"interpreter exiting."); PyDoc_STRVAR(TypeError__doc__, "Inappropriate argument type."); @@ -411,14 +492,12 @@ SystemExit__init__(PyObject *self, PyObject *args) if (!(self = get_self(args))) return NULL; - /* Set args attribute. */ if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; - status = PyObject_SetAttrString(self, "args", args); - if (status < 0) { - Py_DECREF(args); - return NULL; + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; } /* set code attribute */ @@ -445,8 +524,7 @@ SystemExit__init__(PyObject *self, PyObject *args) if (status < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -482,8 +560,12 @@ EnvironmentError__init__(PyObject *self, PyObject *args) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; - if (PyObject_SetAttrString(self, "args", args) || - PyObject_SetAttrString(self, "errno", Py_None) || + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; + } + + if (PyObject_SetAttrString(self, "errno", Py_None) || PyObject_SetAttrString(self, "strerror", Py_None) || PyObject_SetAttrString(self, "filename", Py_None)) { @@ -624,9 +706,9 @@ EnvironmentError__str__(PyObject *self, PyObject *args) * return StandardError.__str__(self) * * but there is no StandardError__str__() function; we happen to - * know that's just a pass through to Exception__str__(). + * know that's just a pass through to BaseException__str__(). */ - rtnval = Exception__str__(originalself, args); + rtnval = BaseException__str__(originalself, args); finally: Py_XDECREF(filename); @@ -712,8 +794,10 @@ SyntaxError__init__(PyObject *self, PyObject *args) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; - if (PyObject_SetAttrString(self, "args", args)) - goto finally; + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; + } lenargs = PySequence_Size(args); if (lenargs >= 1) { @@ -879,8 +963,9 @@ KeyError__str__(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O:__str__", &self)) return NULL; - if (!(argsattr = PyObject_GetAttrString(self, "args"))) - return NULL; + argsattr = PyObject_GetAttrString(self, "args"); + if (!argsattr) + return NULL; /* 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 @@ -889,14 +974,14 @@ KeyError__str__(PyObject *self, PyObject *args) 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 Exception__str__(). + If args is anything else, use the default BaseException__str__(). */ if (PyTuple_Check(argsattr) && PyTuple_GET_SIZE(argsattr) == 1) { PyObject *key = PyTuple_GET_ITEM(argsattr, 0); result = PyObject_Repr(key); } else - result = Exception__str__(self, args); + result = BaseException__str__(self, args); Py_DECREF(argsattr); return result; @@ -1193,6 +1278,11 @@ UnicodeError__init__(PyObject *self, PyObject *args, PyTypeObject *objecttype) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; + } + if (!PyArg_ParseTuple(args, "O!O!O!O!O!", &PyString_Type, &encoding, objecttype, &object, @@ -1201,9 +1291,6 @@ UnicodeError__init__(PyObject *self, PyObject *args, PyTypeObject *objecttype) &PyString_Type, &reason)) goto finally; - if (PyObject_SetAttrString(self, "args", args)) - goto finally; - if (PyObject_SetAttrString(self, "encoding", encoding)) goto finally; if (PyObject_SetAttrString(self, "object", object)) @@ -1405,6 +1492,11 @@ UnicodeTranslateError__init__(PyObject *self, PyObject *args) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) return NULL; + if (!set_args_and_message(self, args)) { + Py_DECREF(args); + return NULL; + } + if (!PyArg_ParseTuple(args, "O!O!O!O!", &PyUnicode_Type, &object, &PyInt_Type, &start, @@ -1412,9 +1504,6 @@ UnicodeTranslateError__init__(PyObject *self, PyObject *args) &PyString_Type, &reason)) goto finally; - if (PyObject_SetAttrString(self, "args", args)) - goto finally; - if (PyObject_SetAttrString(self, "object", object)) goto finally; if (PyObject_SetAttrString(self, "start", start)) @@ -1424,8 +1513,8 @@ UnicodeTranslateError__init__(PyObject *self, PyObject *args) if (PyObject_SetAttrString(self, "reason", reason)) goto finally; - Py_INCREF(Py_None); rtnval = Py_None; + Py_INCREF(rtnval); finally: Py_DECREF(args); @@ -1591,6 +1680,7 @@ static PyMethodDef functions[] = { /* Global C API defined exceptions */ +PyObject *PyExc_BaseException; PyObject *PyExc_Exception; PyObject *PyExc_StopIteration; PyObject *PyExc_GeneratorExit; @@ -1636,7 +1726,7 @@ PyObject *PyExc_VMSError; #endif /* Pre-computed MemoryError instance. Best to create this as early as - * possibly and not wait until a MemoryError is actually raised! + * possible and not wait until a MemoryError is actually raised! */ PyObject *PyExc_MemoryErrorInst; @@ -1663,9 +1753,10 @@ static struct { int (*classinit)(PyObject *); } exctable[] = { /* - * The first three classes MUST appear in exactly this order + * The first four classes MUST appear in exactly this order */ - {"Exception", &PyExc_Exception}, + {"BaseException", &PyExc_BaseException}, + {"Exception", &PyExc_Exception, &PyExc_BaseException, Exception__doc__}, {"StopIteration", &PyExc_StopIteration, &PyExc_Exception, StopIteration__doc__}, {"GeneratorExit", &PyExc_GeneratorExit, &PyExc_Exception, @@ -1676,9 +1767,10 @@ static struct { /* * The rest appear in depth-first order of the hierarchy */ - {"SystemExit", &PyExc_SystemExit, &PyExc_Exception, SystemExit__doc__, + {"SystemExit", &PyExc_SystemExit, &PyExc_BaseException, SystemExit__doc__, SystemExit_methods}, - {"KeyboardInterrupt", &PyExc_KeyboardInterrupt, 0, KeyboardInterrupt__doc__}, + {"KeyboardInterrupt", &PyExc_KeyboardInterrupt, &PyExc_BaseException, + KeyboardInterrupt__doc__}, {"ImportError", &PyExc_ImportError, 0, ImportError__doc__}, {"EnvironmentError", &PyExc_EnvironmentError, 0, EnvironmentError__doc__, EnvironmentError_methods}, @@ -1786,11 +1878,11 @@ _PyExc_Init(void) } /* This is the base class of all exceptions, so make it first. */ - if (make_Exception(modulename) || - PyDict_SetItemString(mydict, "Exception", PyExc_Exception) || - PyDict_SetItemString(bdict, "Exception", PyExc_Exception)) + if (make_BaseException(modulename) || + PyDict_SetItemString(mydict, "BaseException", PyExc_BaseException) || + PyDict_SetItemString(bdict, "BaseException", PyExc_BaseException)) { - Py_FatalError("Base class `Exception' could not be created."); + Py_FatalError("Base class `BaseException' could not be created."); } /* Now we can programmatically create all the remaining exceptions. |