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.
This commit is contained in:
Brett Cannon 2006-03-01 04:25:17 +00:00
parent 762467475d
commit bf36409e2a
16 changed files with 570 additions and 232 deletions

View File

@ -26,9 +26,32 @@ PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *);
PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *);
PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
/* */
#define PyExceptionClass_Check(x) \
(PyClass_Check((x)) \
|| (PyType_Check((x)) && PyType_IsSubtype( \
(PyTypeObject*)(x), (PyTypeObject*)PyExc_BaseException)))
#define PyExceptionInstance_Check(x) \
(PyInstance_Check((x)) || \
(PyType_IsSubtype((x)->ob_type, (PyTypeObject*)PyExc_BaseException)))
#define PyExceptionClass_Name(x) \
(PyClass_Check((x)) \
? PyString_AS_STRING(((PyClassObject*)(x))->cl_name) \
: (char *)(((PyTypeObject*)(x))->tp_name))
#define PyExceptionInstance_Class(x) \
((PyInstance_Check((x)) \
? (PyObject*)((PyInstanceObject*)(x))->in_class \
: (PyObject*)((x)->ob_type)))
/* Predefined exceptions */ /* Predefined exceptions */
PyAPI_DATA(PyObject *) PyExc_BaseException;
PyAPI_DATA(PyObject *) PyExc_Exception; PyAPI_DATA(PyObject *) PyExc_Exception;
PyAPI_DATA(PyObject *) PyExc_StopIteration; PyAPI_DATA(PyObject *) PyExc_StopIteration;
PyAPI_DATA(PyObject *) PyExc_GeneratorExit; PyAPI_DATA(PyObject *) PyExc_GeneratorExit;

View File

@ -0,0 +1,46 @@
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- Exception
+-- GeneratorExit
+-- StopIteration
+-- StandardError
| +-- ArithmeticError
| | +-- FloatingPointError
| | +-- OverflowError
| | +-- ZeroDivisionError
| +-- AssertionError
| +-- AttributeError
| +-- EnvironmentError
| | +-- IOError
| | +-- OSError
| | +-- WindowsError (Windows)
| +-- EOFError
| +-- ImportError
| +-- LookupError
| | +-- IndexError
| | +-- KeyError
| +-- MemoryError
| +-- NameError
| | +-- UnboundLocalError
| +-- ReferenceError
| +-- RuntimeError
| | +-- NotImplementedError
| +-- SyntaxError
| | +-- IndentationError
| | +-- TabError
| +-- SystemError
| +-- TypeError
| +-- ValueError
| | +-- UnicodeError
| | +-- UnicodeDecodeError
| | +-- UnicodeEncodeError
| | +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- OverflowWarning [not generated by the interpreter]

View File

@ -488,12 +488,12 @@ INFO:a.b.c.d:Info 5
-- log_test4 begin --------------------------------------------------- -- log_test4 begin ---------------------------------------------------
config0: ok. config0: ok.
config1: ok. config1: ok.
config2: exceptions.AttributeError config2: <class 'exceptions.AttributeError'>
config3: exceptions.KeyError config3: <class 'exceptions.KeyError'>
-- log_test4 end --------------------------------------------------- -- log_test4 end ---------------------------------------------------
-- log_test5 begin --------------------------------------------------- -- log_test5 begin ---------------------------------------------------
ERROR:root:just testing ERROR:root:just testing
exceptions.KeyError... Don't panic! <class 'exceptions.KeyError'>... Don't panic!
-- log_test5 end --------------------------------------------------- -- log_test5 end ---------------------------------------------------
-- logrecv output begin --------------------------------------------------- -- logrecv output begin ---------------------------------------------------
ERR -> CRITICAL: Message 0 (via logrecv.tcp.ERR) ERR -> CRITICAL: Message 0 (via logrecv.tcp.ERR)

View File

@ -96,7 +96,7 @@ def do_infix_binops():
x = eval('a %s b' % op) x = eval('a %s b' % op)
except: except:
error = sys.exc_info()[:2] error = sys.exc_info()[:2]
print '... %s' % error[0] print '... %s.%s' % (error[0].__module__, error[0].__name__)
else: else:
print '=', format_result(x) print '=', format_result(x)
try: try:
@ -108,7 +108,7 @@ def do_infix_binops():
exec('z %s= b' % op) exec('z %s= b' % op)
except: except:
error = sys.exc_info()[:2] error = sys.exc_info()[:2]
print '... %s' % error[0] print '... %s.%s' % (error[0].__module__, error[0].__name__)
else: else:
print '=>', format_result(z) print '=>', format_result(z)
@ -121,7 +121,7 @@ def do_prefix_binops():
x = eval('%s(a, b)' % op) x = eval('%s(a, b)' % op)
except: except:
error = sys.exc_info()[:2] error = sys.exc_info()[:2]
print '... %s' % error[0] print '... %s.%s' % (error[0].__module__, error[0].__name__)
else: else:
print '=', format_result(x) print '=', format_result(x)

View File

@ -3355,31 +3355,6 @@ def docdescriptor():
vereq(NewClass.__doc__, 'object=None; type=NewClass') vereq(NewClass.__doc__, 'object=None; type=NewClass')
vereq(NewClass().__doc__, 'object=NewClass instance; type=NewClass') vereq(NewClass().__doc__, 'object=NewClass instance; type=NewClass')
def string_exceptions():
if verbose:
print "Testing string exceptions ..."
# Ensure builtin strings work OK as exceptions.
astring = "An exception string."
try:
raise astring
except astring:
pass
else:
raise TestFailed, "builtin string not usable as exception"
# Ensure string subclass instances do not.
class MyStr(str):
pass
newstring = MyStr("oops -- shouldn't work")
try:
raise newstring
except TypeError:
pass
except:
raise TestFailed, "string subclass allowed as exception"
def copy_setstate(): def copy_setstate():
if verbose: if verbose:
print "Testing that copy.*copy() correctly uses __setstate__..." print "Testing that copy.*copy() correctly uses __setstate__..."
@ -4172,7 +4147,6 @@ def test_main():
funnynew() funnynew()
imulbug() imulbug()
docdescriptor() docdescriptor()
string_exceptions()
copy_setstate() copy_setstate()
slices() slices()
subtype_resurrection() subtype_resurrection()

View File

@ -29,10 +29,7 @@ def test_raise_catch(exc):
def r(thing): def r(thing):
test_raise_catch(thing) test_raise_catch(thing)
if isinstance(thing, ClassType): print getattr(thing, '__name__', thing)
print thing.__name__
else:
print thing
r(AttributeError) r(AttributeError)
import sys import sys

182
Lib/test/test_pep352.py Normal file
View File

@ -0,0 +1,182 @@
import unittest
import __builtin__
import exceptions
import warnings
from test.test_support import run_unittest
import os
from platform import system as platform_system
class ExceptionClassTests(unittest.TestCase):
"""Tests for anything relating to exception objects themselves (e.g.,
inheritance hierarchy)"""
def test_builtins_new_style(self):
self.failUnless(issubclass(Exception, object))
def verify_instance_interface(self, ins):
for attr in ("args", "message", "__str__", "__unicode__", "__repr__",
"__getitem__"):
self.failUnless(hasattr(ins, attr), "%s missing %s attribute" %
(ins.__class__.__name__, attr))
def test_inheritance(self):
# Make sure the inheritance hierarchy matches the documentation
exc_set = set(x for x in dir(exceptions) if not x.startswith('_'))
inheritance_tree = open(os.path.join(os.path.split(__file__)[0],
'exception_hierarchy.txt'))
try:
superclass_name = inheritance_tree.readline().rstrip()
try:
last_exc = getattr(__builtin__, superclass_name)
except AttributeError:
self.fail("base class %s not a built-in" % superclass_name)
self.failUnless(superclass_name in exc_set)
exc_set.discard(superclass_name)
superclasses = [] # Loop will insert base exception
last_depth = 0
for exc_line in inheritance_tree:
exc_line = exc_line.rstrip()
depth = exc_line.rindex('-')
exc_name = exc_line[depth+2:] # Slice past space
if '(' in exc_name:
paren_index = exc_name.index('(')
platform_name = exc_name[paren_index+1:-1]
if platform_system() != platform_name:
exc_set.discard(exc_name)
continue
if '[' in exc_name:
left_bracket = exc_name.index('[')
exc_name = exc_name[:left_bracket-1] # cover space
try:
exc = getattr(__builtin__, exc_name)
except AttributeError:
self.fail("%s not a built-in exception" % exc_name)
if last_depth < depth:
superclasses.append((last_depth, last_exc))
elif last_depth > depth:
while superclasses[-1][0] >= depth:
superclasses.pop()
self.failUnless(issubclass(exc, superclasses[-1][1]),
"%s is not a subclass of %s" % (exc.__name__,
superclasses[-1][1].__name__))
try: # Some exceptions require arguments; just skip them
self.verify_instance_interface(exc())
except TypeError:
pass
self.failUnless(exc_name in exc_set)
exc_set.discard(exc_name)
last_exc = exc
last_depth = depth
finally:
inheritance_tree.close()
self.failUnlessEqual(len(exc_set), 0, "%s not accounted for" % exc_set)
interface_tests = ("length", "args", "message", "str", "unicode", "repr",
"indexing")
def interface_test_driver(self, results):
for test_name, (given, expected) in zip(self.interface_tests, results):
self.failUnlessEqual(given, expected, "%s: %s != %s" % (test_name,
given, expected))
def test_interface_single_arg(self):
# Make sure interface works properly when given a single argument
arg = "spam"
exc = Exception(arg)
results = ([len(exc.args), 1], [exc.args[0], arg], [exc.message, arg],
[str(exc), str(arg)], [unicode(exc), unicode(arg)],
[repr(exc), exc.__class__.__name__ + repr(exc.args)], [exc[0], arg])
self.interface_test_driver(results)
def test_interface_multi_arg(self):
# Make sure interface correct when multiple arguments given
arg_count = 3
args = tuple(range(arg_count))
exc = Exception(*args)
results = ([len(exc.args), arg_count], [exc.args, args],
[exc.message, ''], [str(exc), str(args)],
[unicode(exc), unicode(args)],
[repr(exc), exc.__class__.__name__ + repr(exc.args)],
[exc[-1], args[-1]])
self.interface_test_driver(results)
def test_interface_no_arg(self):
# Make sure that with no args that interface is correct
exc = Exception()
results = ([len(exc.args), 0], [exc.args, tuple()], [exc.message, ''],
[str(exc), ''], [unicode(exc), u''],
[repr(exc), exc.__class__.__name__ + '()'], [True, True])
self.interface_test_driver(results)
class UsageTests(unittest.TestCase):
"""Test usage of exceptions"""
def setUp(self):
self._filters = warnings.filters[:]
def tearDown(self):
warnings.filters = self._filters[:]
def test_raise_classic(self):
class ClassicClass:
pass
try:
raise ClassicClass
except ClassicClass:
pass
except:
self.fail("unable to raise classic class")
try:
raise ClassicClass()
except ClassicClass:
pass
except:
self.fail("unable to raise class class instance")
def test_raise_new_style_non_exception(self):
class NewStyleClass(object):
pass
try:
raise NewStyleClass
except TypeError:
pass
except:
self.fail("unable to raise new-style class")
try:
raise NewStyleClass()
except TypeError:
pass
except:
self.fail("unable to raise new-style class instance")
def test_raise_string(self):
warnings.resetwarnings()
warnings.filterwarnings("error")
try:
raise "spam"
except DeprecationWarning:
pass
except:
self.fail("raising a string did not cause a DeprecationWarning")
def test_catch_string(self):
# Test will be pertinent when catching exceptions raises a
# DeprecationWarning
warnings.filterwarnings("ignore", "raising")
str_exc = "spam"
try:
raise str_exc
except str_exc:
pass
except:
self.fail("catching a string exception failed")
def test_main():
run_unittest(ExceptionClassTests, UsageTests)
if __name__ == '__main__':
test_main()

View File

@ -157,7 +157,8 @@ def format_exception_only(etype, value):
which exception occurred is the always last string in the list. which exception occurred is the always last string in the list.
""" """
list = [] list = []
if type(etype) == types.ClassType: if (type(etype) == types.ClassType
or (isinstance(etype, type) and issubclass(etype, Exception))):
stype = etype.__name__ stype = etype.__name__
else: else:
stype = etype stype = etype

View File

@ -145,7 +145,8 @@ def filterwarnings(action, message="", category=Warning, module="", lineno=0,
assert action in ("error", "ignore", "always", "default", "module", assert action in ("error", "ignore", "always", "default", "module",
"once"), "invalid action: %r" % (action,) "once"), "invalid action: %r" % (action,)
assert isinstance(message, basestring), "message must be a string" assert isinstance(message, basestring), "message must be a string"
assert isinstance(category, types.ClassType), "category must be a class" assert isinstance(category, (type, types.ClassType)), \
"category must be a class"
assert issubclass(category, Warning), "category must be a Warning subclass" assert issubclass(category, Warning), "category must be a Warning subclass"
assert isinstance(module, basestring), "module must be a string" assert isinstance(module, basestring), "module must be a string"
assert isinstance(lineno, int) and lineno >= 0, \ assert isinstance(lineno, int) and lineno >= 0, \

View File

@ -12,6 +12,11 @@ What's New in Python 2.5 alpha 1?
Core and builtins Core and builtins
----------------- -----------------
- PEP 352, patch #1104669: Make exceptions new-style objects. Introduced the
new exception base class, BaseException, which has a new message attribute.
KeyboardInterrupt and SystemExit to directly inherit from BaseException now.
Raising a string exception now raises a DeprecationWarning.
- Patch #1438387, PEP 328: relative and absolute imports. Imports can now be - Patch #1438387, PEP 328: relative and absolute imports. Imports can now be
explicitly relative, using 'from .module import name' to mean 'from the same explicitly relative, using 'from .module import name' to mean 'from the same
package as this module is in. Imports without dots still default to the package as this module is in. Imports without dots still default to the

View File

@ -230,11 +230,11 @@ gen_throw(PyGenObject *gen, PyObject *args)
Py_XINCREF(val); Py_XINCREF(val);
Py_XINCREF(tb); Py_XINCREF(tb);
if (PyClass_Check(typ)) { if (PyExceptionClass_Check(typ)) {
PyErr_NormalizeException(&typ, &val, &tb); PyErr_NormalizeException(&typ, &val, &tb);
} }
else if (PyInstance_Check(typ)) { else if (PyExceptionInstance_Check(typ)) {
/* Raising an instance. The value should be a dummy. */ /* Raising an instance. The value should be a dummy. */
if (val && val != Py_None) { if (val && val != Py_None) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -245,7 +245,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
/* Normalize to raise <class>, <instance> */ /* Normalize to raise <class>, <instance> */
Py_XDECREF(val); Py_XDECREF(val);
val = typ; val = typ;
typ = (PyObject*) ((PyInstanceObject*)typ)->in_class; typ = PyExceptionInstance_Class(typ);
Py_INCREF(typ); Py_INCREF(typ);
} }
} }

View File

@ -1685,7 +1685,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throw)
why == WHY_CONTINUE) why == WHY_CONTINUE)
retval = POP(); retval = POP();
} }
else if (PyClass_Check(v) || PyString_Check(v)) { else if (PyExceptionClass_Check(v) || PyString_Check(v)) {
w = POP(); w = POP();
u = POP(); u = POP();
PyErr_Restore(v, w, u); PyErr_Restore(v, w, u);
@ -3026,14 +3026,14 @@ do_raise(PyObject *type, PyObject *value, PyObject *tb)
/* Raising builtin string is deprecated but still allowed -- /* Raising builtin string is deprecated but still allowed --
* do nothing. Raising an instance of a new-style str * do nothing. Raising an instance of a new-style str
* subclass is right out. */ * subclass is right out. */
if (-1 == PyErr_Warn(PyExc_PendingDeprecationWarning, if (PyErr_Warn(PyExc_DeprecationWarning,
"raising a string exception is deprecated")) "raising a string exception is deprecated"))
goto raise_error; goto raise_error;
} }
else if (PyClass_Check(type)) else if (PyExceptionClass_Check(type))
PyErr_NormalizeException(&type, &value, &tb); PyErr_NormalizeException(&type, &value, &tb);
else if (PyInstance_Check(type)) { else if (PyExceptionInstance_Check(type)) {
/* Raising an instance. The value should be a dummy. */ /* Raising an instance. The value should be a dummy. */
if (value != Py_None) { if (value != Py_None) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -3044,7 +3044,7 @@ do_raise(PyObject *type, PyObject *value, PyObject *tb)
/* Normalize to raise <class>, <instance> */ /* Normalize to raise <class>, <instance> */
Py_DECREF(value); Py_DECREF(value);
value = type; value = type;
type = (PyObject*) ((PyInstanceObject*)type)->in_class; type = PyExceptionInstance_Class(type);
Py_INCREF(type); Py_INCREF(type);
} }
} }

View File

@ -448,9 +448,8 @@ static void wrong_exception_type(PyObject *exc)
PyObject *PyCodec_StrictErrors(PyObject *exc) PyObject *PyCodec_StrictErrors(PyObject *exc)
{ {
if (PyInstance_Check(exc)) if (PyExceptionInstance_Check(exc))
PyErr_SetObject((PyObject*)((PyInstanceObject*)exc)->in_class, PyErr_SetObject(PyExceptionInstance_Class(exc), exc);
exc);
else else
PyErr_SetString(PyExc_TypeError, "codec must pass exception instance"); PyErr_SetString(PyExc_TypeError, "codec must pass exception instance");
return NULL; return NULL;

View File

@ -97,11 +97,14 @@ PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
return 0; return 0;
} }
/* err might be an instance, so check its class. */ /* err might be an instance, so check its class. */
if (PyInstance_Check(err)) if (PyExceptionInstance_Check(err))
err = (PyObject*)((PyInstanceObject*)err)->in_class; err = PyExceptionInstance_Class(err);
if (PyClass_Check(err) && PyClass_Check(exc)) if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) {
return PyClass_IsSubclass(err, exc); /* problems here!? not sure PyObject_IsSubclass expects to
be called with an exception pending... */
return PyObject_IsSubclass(err, exc);
}
return err == exc; return err == exc;
} }
@ -138,19 +141,19 @@ PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb)
Py_INCREF(value); Py_INCREF(value);
} }
if (PyInstance_Check(value)) if (PyExceptionInstance_Check(value))
inclass = (PyObject*)((PyInstanceObject*)value)->in_class; inclass = PyExceptionInstance_Class(value);
/* Normalize the exception so that if the type is a class, the /* Normalize the exception so that if the type is a class, the
value will be an instance. value will be an instance.
*/ */
if (PyClass_Check(type)) { if (PyExceptionClass_Check(type)) {
/* if the value was not an instance, or is not an instance /* if the value was not an instance, or is not an instance
whose class is (or is derived from) type, then use the whose class is (or is derived from) type, then use the
value as an argument to instantiation of the type value as an argument to instantiation of the type
class. class.
*/ */
if (!inclass || !PyClass_IsSubclass(inclass, type)) { if (!inclass || !PyObject_IsSubclass(inclass, type)) {
PyObject *args, *res; PyObject *args, *res;
if (value == Py_None) if (value == Py_None)
@ -282,7 +285,7 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
{ {
/* Note that the Win32 errors do not lineup with the /* Note that the Win32 errors do not lineup with the
errno error. So if the error is in the MSVC error errno error. So if the error is in the MSVC error
table, we use it, otherwise we assume it really _is_ table, we use it, otherwise we assume it really _is_
a Win32 error code a Win32 error code
*/ */
if (i > 0 && i < _sys_nerr) { if (i > 0 && i < _sys_nerr) {
@ -302,7 +305,7 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
0, /* size not used */ 0, /* size not used */
NULL); /* no args */ NULL); /* no args */
if (len==0) { if (len==0) {
/* Only ever seen this in out-of-mem /* Only ever seen this in out-of-mem
situations */ situations */
sprintf(s_small_buf, "Windows Error 0x%X", i); sprintf(s_small_buf, "Windows Error 0x%X", i);
s = s_small_buf; s = s_small_buf;
@ -345,8 +348,8 @@ PyErr_SetFromErrnoWithFilename(PyObject *exc, char *filename)
PyObject * PyObject *
PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, Py_UNICODE *filename) PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, Py_UNICODE *filename)
{ {
PyObject *name = filename ? PyObject *name = filename ?
PyUnicode_FromUnicode(filename, wcslen(filename)) : PyUnicode_FromUnicode(filename, wcslen(filename)) :
NULL; NULL;
PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name); PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
Py_XDECREF(name); Py_XDECREF(name);
@ -360,7 +363,7 @@ PyErr_SetFromErrno(PyObject *exc)
return PyErr_SetFromErrnoWithFilenameObject(exc, NULL); return PyErr_SetFromErrnoWithFilenameObject(exc, NULL);
} }
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
/* Windows specific error code handling */ /* Windows specific error code handling */
PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject( PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
PyObject *exc, PyObject *exc,
@ -415,8 +418,8 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename(
const char *filename) const char *filename)
{ {
PyObject *name = filename ? PyString_FromString(filename) : NULL; PyObject *name = filename ? PyString_FromString(filename) : NULL;
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
ierr, ierr,
name); name);
Py_XDECREF(name); Py_XDECREF(name);
return ret; return ret;
@ -428,11 +431,11 @@ PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilename(
int ierr, int ierr,
const Py_UNICODE *filename) const Py_UNICODE *filename)
{ {
PyObject *name = filename ? PyObject *name = filename ?
PyUnicode_FromUnicode(filename, wcslen(filename)) : PyUnicode_FromUnicode(filename, wcslen(filename)) :
NULL; NULL;
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
ierr, ierr,
name); name);
Py_XDECREF(name); Py_XDECREF(name);
return ret; return ret;
@ -466,8 +469,8 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
int ierr, int ierr,
const Py_UNICODE *filename) const Py_UNICODE *filename)
{ {
PyObject *name = filename ? PyObject *name = filename ?
PyUnicode_FromUnicode(filename, wcslen(filename)) : PyUnicode_FromUnicode(filename, wcslen(filename)) :
NULL; NULL;
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject( PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
PyExc_WindowsError, PyExc_WindowsError,
@ -574,7 +577,24 @@ PyErr_WriteUnraisable(PyObject *obj)
if (f != NULL) { if (f != NULL) {
PyFile_WriteString("Exception ", f); PyFile_WriteString("Exception ", f);
if (t) { if (t) {
PyFile_WriteObject(t, f, Py_PRINT_RAW); char* className = PyExceptionClass_Name(t);
PyObject* moduleName =
PyObject_GetAttrString(t, "__module__");
if (moduleName == NULL)
PyFile_WriteString("<unknown>", f);
else {
char* modstr = PyString_AsString(moduleName);
if (modstr)
{
PyFile_WriteString(modstr, f);
PyFile_WriteString(".", f);
}
}
if (className == NULL)
PyFile_WriteString("<unknown>", f);
else
PyFile_WriteString(className, f);
if (v && v != Py_None) { if (v && v != Py_None) {
PyFile_WriteString(": ", f); PyFile_WriteString(": ", f);
PyFile_WriteObject(v, f, 0); PyFile_WriteObject(v, f, 0);
@ -726,7 +746,7 @@ PyErr_SyntaxLocation(const char *filename, int lineno)
/* com_fetch_program_text will attempt to load the line of text that /* com_fetch_program_text will attempt to load the line of text that
the exception refers to. If it fails, it will return NULL but will the exception refers to. If it fails, it will return NULL but will
not set an exception. not set an exception.
XXX The functionality of this function is quite similar to the XXX The functionality of this function is quite similar to the
functionality in tb_displayline() in traceback.c. functionality in tb_displayline() in traceback.c.

View File

@ -11,6 +11,7 @@
* 98-08-19 fl created (for pyexe) * 98-08-19 fl created (for pyexe)
* 00-02-08 fl updated for 1.5.2 * 00-02-08 fl updated for 1.5.2
* 26-May-2000 baw vetted for Python 1.6 * 26-May-2000 baw vetted for Python 1.6
* XXX
* *
* written by Fredrik Lundh * written by Fredrik Lundh
* modifications, additions, cleanups, and proofreading by Barry Warsaw * modifications, additions, cleanups, and proofreading by Barry Warsaw
@ -33,99 +34,19 @@
PyDoc_STRVAR(module__doc__, PyDoc_STRVAR(module__doc__,
"Python's standard exception class hierarchy.\n\ "Python's standard exception class hierarchy.\n\
\n\ \n\
Before Python 1.5, the standard exceptions were all simple string objects.\n\ Exceptions found here are defined both in the exceptions module and the \n\
In Python 1.5, the standard exceptions were converted to classes organized\n\ built-in namespace. It is recommended that user-defined exceptions inherit \n\
into a relatively flat hierarchy. String-based standard exceptions were\n\ from Exception.\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"
/* keep string pieces "small" */ /* keep string pieces "small" */
"\n\ /* XXX exception hierarchy from Lib/test/exception_hierarchy.txt */
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"
); );
/* Helper function for populating a dictionary with method wrappers. */ /* Helper function for populating a dictionary with method wrappers. */
static int static int
populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods) populate_methods(PyObject *klass, PyMethodDef *methods)
{ {
PyObject *module; PyObject *module;
int status = -1; int status = -1;
@ -151,7 +72,7 @@ populate_methods(PyObject *klass, PyObject *dict, PyMethodDef *methods)
} }
/* add method to dictionary */ /* 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(meth);
Py_DECREF(func); Py_DECREF(func);
@ -196,7 +117,7 @@ make_class(PyObject **klass, PyObject *base,
if (!(*klass = PyErr_NewException(name, base, dict))) if (!(*klass = PyErr_NewException(name, base, dict)))
goto finally; goto finally;
if (populate_methods(*klass, dict, methods)) { if (populate_methods(*klass, methods)) {
Py_DECREF(*klass); Py_DECREF(*klass);
*klass = NULL; *klass = NULL;
goto finally; goto finally;
@ -232,47 +153,81 @@ get_self(PyObject *args)
/* Notes on bootstrapping the exception classes. /* Notes on bootstrapping the exception classes.
* *
* First thing we create is the base class for all exceptions, called * 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 * assumptions about the existence of any other exception class -- except
* for TypeError, which can conditionally exist. * 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 * TypeError, because the instantiation of other exceptions can potentially
* throw a TypeError. Once these exceptions are created, all the others * throw a TypeError. Once these exceptions are created, all the others
* can be created in any order. See the static exctable below for the * can be created in any order. See the static exctable below for the
* explicit bootstrap order. * 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.
Assumes self and args have already been set properly with set_self, etc.
*/
static int
set_args_and_message(PyObject *self, PyObject *args)
{
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 * static PyObject *
Exception__init__(PyObject *self, PyObject *args) BaseException__init__(PyObject *self, PyObject *args)
{ {
int status;
if (!(self = get_self(args))) if (!(self = get_self(args)))
return NULL; return NULL;
/* set args attribute */ /* set args and message attribute */
/* XXX size is only a hint */ args = PySequence_GetSlice(args, 1, PySequence_Length(args));
args = PySequence_GetSlice(args, 1, PySequence_Size(args));
if (!args) if (!args)
return NULL; return NULL;
status = PyObject_SetAttrString(self, "args", args);
Py_DECREF(args);
if (status < 0)
return NULL;
Py_INCREF(Py_None); if (!set_args_and_message(self, args)) {
return Py_None; Py_DECREF(args);
return NULL;
}
Py_DECREF(args);
Py_RETURN_NONE;
} }
static PyObject * static PyObject *
Exception__str__(PyObject *self, PyObject *args) BaseException__str__(PyObject *self, PyObject *args)
{ {
PyObject *out; PyObject *out;
@ -310,9 +265,116 @@ Exception__str__(PyObject *self, PyObject *args)
return out; 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 * static PyObject *
Exception__getitem__(PyObject *self, PyObject *args) 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 *
BaseException__getitem__(PyObject *self, PyObject *args)
{ {
PyObject *out; PyObject *out;
PyObject *index; PyObject *index;
@ -331,21 +393,27 @@ Exception__getitem__(PyObject *self, PyObject *args)
static PyMethodDef static PyMethodDef
Exception_methods[] = { BaseException_methods[] = {
/* methods for the Exception class */ /* methods for the BaseException class */
{ "__getitem__", Exception__getitem__, METH_VARARGS}, {"__getitem__", BaseException__getitem__, METH_VARARGS},
{ "__str__", Exception__str__, METH_VARARGS}, {"__repr__", BaseException__repr__, METH_VARARGS},
{ "__init__", Exception__init__, METH_VARARGS}, {"__str__", BaseException__str__, METH_VARARGS},
{ NULL, NULL } #ifdef Py_USING_UNICODE
{"__unicode__", BaseException__unicode__, METH_VARARGS},
#endif /* Py_USING_UNICODE */
{"__init__", BaseException__init__, METH_VARARGS},
{NULL, NULL }
}; };
static int static int
make_Exception(char *modulename) make_BaseException(char *modulename)
{ {
PyObject *dict = PyDict_New(); PyObject *dict = PyDict_New();
PyObject *str = NULL; PyObject *str = NULL;
PyObject *name = NULL; PyObject *name = NULL;
PyObject *emptytuple = NULL;
PyObject *argstuple = NULL;
int status = -1; int status = -1;
if (!dict) if (!dict)
@ -360,20 +428,28 @@ make_Exception(char *modulename)
if (PyDict_SetItemString(dict, "__module__", str)) if (PyDict_SetItemString(dict, "__module__", str))
goto finally; goto finally;
Py_DECREF(str); Py_DECREF(str);
if (!(str = PyString_FromString(Exception__doc__)))
if (!(str = PyString_FromString(BaseException__doc__)))
goto finally; goto finally;
if (PyDict_SetItemString(dict, "__doc__", str)) if (PyDict_SetItemString(dict, "__doc__", str))
goto finally; goto finally;
if (!(name = PyString_FromString("Exception"))) if (!(name = PyString_FromString("BaseException")))
goto finally; 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; goto finally;
/* Now populate the dictionary with the method suite */ /* Now populate the dictionary with the method suite */
if (populate_methods(PyExc_Exception, dict, Exception_methods)) if (populate_methods(PyExc_BaseException, BaseException_methods))
/* Don't need to reclaim PyExc_Exception here because that'll /* Don't need to reclaim PyExc_BaseException here because that'll
* happen during interpreter shutdown. * happen during interpreter shutdown.
*/ */
goto finally; goto finally;
@ -384,13 +460,18 @@ make_Exception(char *modulename)
Py_XDECREF(dict); Py_XDECREF(dict);
Py_XDECREF(str); Py_XDECREF(str);
Py_XDECREF(name); Py_XDECREF(name);
Py_XDECREF(emptytuple);
Py_XDECREF(argstuple);
return status; return status;
} }
PyDoc_STRVAR(Exception__doc__, "Common base class for all non-exit exceptions.");
PyDoc_STRVAR(StandardError__doc__, 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."); PyDoc_STRVAR(TypeError__doc__, "Inappropriate argument type.");
@ -411,14 +492,12 @@ SystemExit__init__(PyObject *self, PyObject *args)
if (!(self = get_self(args))) if (!(self = get_self(args)))
return NULL; return NULL;
/* Set args attribute. */
if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args))))
return NULL; return NULL;
status = PyObject_SetAttrString(self, "args", args); if (!set_args_and_message(self, args)) {
if (status < 0) { Py_DECREF(args);
Py_DECREF(args); return NULL;
return NULL;
} }
/* set code attribute */ /* set code attribute */
@ -445,8 +524,7 @@ SystemExit__init__(PyObject *self, PyObject *args)
if (status < 0) if (status < 0)
return NULL; return NULL;
Py_INCREF(Py_None); Py_RETURN_NONE;
return Py_None;
} }
@ -482,8 +560,12 @@ EnvironmentError__init__(PyObject *self, PyObject *args)
if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args))))
return NULL; return NULL;
if (PyObject_SetAttrString(self, "args", args) || if (!set_args_and_message(self, args)) {
PyObject_SetAttrString(self, "errno", Py_None) || Py_DECREF(args);
return NULL;
}
if (PyObject_SetAttrString(self, "errno", Py_None) ||
PyObject_SetAttrString(self, "strerror", Py_None) || PyObject_SetAttrString(self, "strerror", Py_None) ||
PyObject_SetAttrString(self, "filename", Py_None)) PyObject_SetAttrString(self, "filename", Py_None))
{ {
@ -624,9 +706,9 @@ EnvironmentError__str__(PyObject *self, PyObject *args)
* return StandardError.__str__(self) * return StandardError.__str__(self)
* *
* but there is no StandardError__str__() function; we happen to * 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: finally:
Py_XDECREF(filename); Py_XDECREF(filename);
@ -712,8 +794,10 @@ SyntaxError__init__(PyObject *self, PyObject *args)
if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args))))
return NULL; return NULL;
if (PyObject_SetAttrString(self, "args", args)) if (!set_args_and_message(self, args)) {
goto finally; Py_DECREF(args);
return NULL;
}
lenargs = PySequence_Size(args); lenargs = PySequence_Size(args);
if (lenargs >= 1) { if (lenargs >= 1) {
@ -879,8 +963,9 @@ KeyError__str__(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O:__str__", &self)) if (!PyArg_ParseTuple(args, "O:__str__", &self))
return NULL; return NULL;
if (!(argsattr = PyObject_GetAttrString(self, "args"))) argsattr = PyObject_GetAttrString(self, "args");
return NULL; if (!argsattr)
return NULL;
/* If args is a tuple of exactly one item, apply repr to args[0]. /* 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 This is done so that e.g. the exception raised by {}[''] prints
@ -889,14 +974,14 @@ KeyError__str__(PyObject *self, PyObject *args)
KeyError KeyError
alone. The downside is that if KeyError is raised with an explanatory alone. The downside is that if KeyError is raised with an explanatory
string, that string will be displayed in quotes. Too bad. 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) { if (PyTuple_Check(argsattr) && PyTuple_GET_SIZE(argsattr) == 1) {
PyObject *key = PyTuple_GET_ITEM(argsattr, 0); PyObject *key = PyTuple_GET_ITEM(argsattr, 0);
result = PyObject_Repr(key); result = PyObject_Repr(key);
} }
else else
result = Exception__str__(self, args); result = BaseException__str__(self, args);
Py_DECREF(argsattr); Py_DECREF(argsattr);
return result; return result;
@ -1193,6 +1278,11 @@ UnicodeError__init__(PyObject *self, PyObject *args, PyTypeObject *objecttype)
if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args)))) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args))))
return NULL; return NULL;
if (!set_args_and_message(self, args)) {
Py_DECREF(args);
return NULL;
}
if (!PyArg_ParseTuple(args, "O!O!O!O!O!", if (!PyArg_ParseTuple(args, "O!O!O!O!O!",
&PyString_Type, &encoding, &PyString_Type, &encoding,
objecttype, &object, objecttype, &object,
@ -1201,9 +1291,6 @@ UnicodeError__init__(PyObject *self, PyObject *args, PyTypeObject *objecttype)
&PyString_Type, &reason)) &PyString_Type, &reason))
goto finally; goto finally;
if (PyObject_SetAttrString(self, "args", args))
goto finally;
if (PyObject_SetAttrString(self, "encoding", encoding)) if (PyObject_SetAttrString(self, "encoding", encoding))
goto finally; goto finally;
if (PyObject_SetAttrString(self, "object", object)) 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)))) if (!(args = PySequence_GetSlice(args, 1, PySequence_Size(args))))
return NULL; return NULL;
if (!set_args_and_message(self, args)) {
Py_DECREF(args);
return NULL;
}
if (!PyArg_ParseTuple(args, "O!O!O!O!", if (!PyArg_ParseTuple(args, "O!O!O!O!",
&PyUnicode_Type, &object, &PyUnicode_Type, &object,
&PyInt_Type, &start, &PyInt_Type, &start,
@ -1412,9 +1504,6 @@ UnicodeTranslateError__init__(PyObject *self, PyObject *args)
&PyString_Type, &reason)) &PyString_Type, &reason))
goto finally; goto finally;
if (PyObject_SetAttrString(self, "args", args))
goto finally;
if (PyObject_SetAttrString(self, "object", object)) if (PyObject_SetAttrString(self, "object", object))
goto finally; goto finally;
if (PyObject_SetAttrString(self, "start", start)) if (PyObject_SetAttrString(self, "start", start))
@ -1424,8 +1513,8 @@ UnicodeTranslateError__init__(PyObject *self, PyObject *args)
if (PyObject_SetAttrString(self, "reason", reason)) if (PyObject_SetAttrString(self, "reason", reason))
goto finally; goto finally;
Py_INCREF(Py_None);
rtnval = Py_None; rtnval = Py_None;
Py_INCREF(rtnval);
finally: finally:
Py_DECREF(args); Py_DECREF(args);
@ -1591,6 +1680,7 @@ static PyMethodDef functions[] = {
/* Global C API defined exceptions */ /* Global C API defined exceptions */
PyObject *PyExc_BaseException;
PyObject *PyExc_Exception; PyObject *PyExc_Exception;
PyObject *PyExc_StopIteration; PyObject *PyExc_StopIteration;
PyObject *PyExc_GeneratorExit; PyObject *PyExc_GeneratorExit;
@ -1636,7 +1726,7 @@ PyObject *PyExc_VMSError;
#endif #endif
/* Pre-computed MemoryError instance. Best to create this as early as /* 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; PyObject *PyExc_MemoryErrorInst;
@ -1663,9 +1753,10 @@ static struct {
int (*classinit)(PyObject *); int (*classinit)(PyObject *);
} exctable[] = { } 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", &PyExc_StopIteration, &PyExc_Exception,
StopIteration__doc__}, StopIteration__doc__},
{"GeneratorExit", &PyExc_GeneratorExit, &PyExc_Exception, {"GeneratorExit", &PyExc_GeneratorExit, &PyExc_Exception,
@ -1676,9 +1767,10 @@ static struct {
/* /*
* The rest appear in depth-first order of the hierarchy * 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}, SystemExit_methods},
{"KeyboardInterrupt", &PyExc_KeyboardInterrupt, 0, KeyboardInterrupt__doc__}, {"KeyboardInterrupt", &PyExc_KeyboardInterrupt, &PyExc_BaseException,
KeyboardInterrupt__doc__},
{"ImportError", &PyExc_ImportError, 0, ImportError__doc__}, {"ImportError", &PyExc_ImportError, 0, ImportError__doc__},
{"EnvironmentError", &PyExc_EnvironmentError, 0, EnvironmentError__doc__, {"EnvironmentError", &PyExc_EnvironmentError, 0, EnvironmentError__doc__,
EnvironmentError_methods}, EnvironmentError_methods},
@ -1786,11 +1878,11 @@ _PyExc_Init(void)
} }
/* This is the base class of all exceptions, so make it first. */ /* This is the base class of all exceptions, so make it first. */
if (make_Exception(modulename) || if (make_BaseException(modulename) ||
PyDict_SetItemString(mydict, "Exception", PyExc_Exception) || PyDict_SetItemString(mydict, "BaseException", PyExc_BaseException) ||
PyDict_SetItemString(bdict, "Exception", PyExc_Exception)) 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. /* Now we can programmatically create all the remaining exceptions.

View File

@ -976,7 +976,7 @@ handle_system_exit(void)
fflush(stdout); fflush(stdout);
if (value == NULL || value == Py_None) if (value == NULL || value == Py_None)
goto done; goto done;
if (PyInstance_Check(value)) { if (PyExceptionInstance_Check(value)) {
/* The error code should be in the `code' attribute. */ /* The error code should be in the `code' attribute. */
PyObject *code = PyObject_GetAttrString(value, "code"); PyObject *code = PyObject_GetAttrString(value, "code");
if (code) { if (code) {
@ -1106,11 +1106,10 @@ void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
if (err) { if (err) {
/* Don't do anything else */ /* Don't do anything else */
} }
else if (PyClass_Check(exception)) { else if (PyExceptionClass_Check(exception)) {
PyClassObject* exc = (PyClassObject*)exception; char* className = PyExceptionClass_Name(exception);
PyObject* className = exc->cl_name;
PyObject* moduleName = PyObject* moduleName =
PyDict_GetItemString(exc->cl_dict, "__module__"); PyObject_GetAttrString(exception, "__module__");
if (moduleName == NULL) if (moduleName == NULL)
err = PyFile_WriteString("<unknown>", f); err = PyFile_WriteString("<unknown>", f);
@ -1126,8 +1125,7 @@ void PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb)
if (className == NULL) if (className == NULL)
err = PyFile_WriteString("<unknown>", f); err = PyFile_WriteString("<unknown>", f);
else else
err = PyFile_WriteObject(className, f, err = PyFile_WriteString(className, f);
Py_PRINT_RAW);
} }
} }
else else