cpython: d22c99e77768 (original) (raw)
--- a/Lib/test/test_pep3151.py +++ b/Lib/test/test_pep3151.py @@ -12,6 +12,23 @@ from test import support class SubOSError(OSError): pass +class SubOSErrorWithInit(OSError):
+ +class SubOSErrorWithNew(OSError):
- def new(cls, message, baz):
self = super().__new__(cls, message)[](#l1.14)
self.baz = baz[](#l1.15)
return self[](#l1.16)
+ +class SubOSErrorCombinedInitFirst(SubOSErrorWithInit, SubOSErrorWithNew):
+ +class SubOSErrorCombinedNewFirst(SubOSErrorWithNew, SubOSErrorWithInit):
+ class HierarchyTest(unittest.TestCase): @@ -74,11 +91,6 @@ class HierarchyTest(unittest.TestCase): e = OSError(errcode, "Some message") self.assertIs(type(e), OSError)
- def test_OSError_subclass_mapping(self):
# When constructing an OSError subclass, errno mapping isn't done[](#l1.32)
e = SubOSError(EEXIST, "Bad file descriptor")[](#l1.33)
self.assertIs(type(e), SubOSError)[](#l1.34)
- def test_try_except(self): filename = "some_hopefully_non_existing_file" @@ -144,6 +156,44 @@ class AttributesTest(unittest.TestCase): # XXX VMSError not tested +class ExplicitSubclassingTest(unittest.TestCase): +
- def test_errno_mapping(self):
# When constructing an OSError subclass, errno mapping isn't done[](#l1.46)
e = SubOSError(EEXIST, "Bad file descriptor")[](#l1.47)
self.assertIs(type(e), SubOSError)[](#l1.48)
- def test_init_overriden(self):
e = SubOSErrorWithInit("some message", "baz")[](#l1.51)
self.assertEqual(e.bar, "baz")[](#l1.52)
self.assertEqual(e.args, ("some message",))[](#l1.53)
- def test_init_kwdargs(self):
e = SubOSErrorWithInit("some message", bar="baz")[](#l1.56)
self.assertEqual(e.bar, "baz")[](#l1.57)
self.assertEqual(e.args, ("some message",))[](#l1.58)
- def test_new_overriden(self):
e = SubOSErrorWithNew("some message", "baz")[](#l1.61)
self.assertEqual(e.baz, "baz")[](#l1.62)
self.assertEqual(e.args, ("some message",))[](#l1.63)
- def test_new_kwdargs(self):
e = SubOSErrorWithNew("some message", baz="baz")[](#l1.66)
self.assertEqual(e.baz, "baz")[](#l1.67)
self.assertEqual(e.args, ("some message",))[](#l1.68)
- def test_init_new_overriden(self):
e = SubOSErrorCombinedInitFirst("some message", "baz")[](#l1.71)
self.assertEqual(e.bar, "baz")[](#l1.72)
self.assertEqual(e.baz, "baz")[](#l1.73)
self.assertEqual(e.args, ("some message",))[](#l1.74)
e = SubOSErrorCombinedNewFirst("some message", "baz")[](#l1.75)
self.assertEqual(e.bar, "baz")[](#l1.76)
self.assertEqual(e.baz, "baz")[](#l1.77)
self.assertEqual(e.args, ("some message",))[](#l1.78)
+ + def test_main(): support.run_unittest(name)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1? Core and Builtins ----------------- +- Fix OSError.init and OSError.new so that each of them can be
- Fix the fix for issue #12149: it was incorrect, although it had the side effect of appearing to resolve the issue. Thanks to Mark Shannon for noticing.
--- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -58,7 +58,7 @@ BaseException_init(PyBaseExceptionObject if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds)) return -1;
- Py_XDECREF(self->args); self->args = args; Py_INCREF(self->args); @@ -587,37 +587,34 @@ SimpleExtendsException(PyExc_Exception,
-static PyObject * -OSError_new(PyTypeObject *type, PyObject *args, PyObject kwds) +/ This function doesn't cleanup on error, the caller should */ +static int +oserror_parse_args(PyObject **p_args,
PyObject **myerrno, PyObject **strerror,[](#l3.21)
PyObject **filename[](#l3.22)
, PyObject **winerror[](#l3.24)
)[](#l3.26)
- if (!_PyArg_NoKeywords(type->tp_name, kwds))
return NULL;[](#l3.40)
- Py_INCREF(args); nargs = PyTuple_GET_SIZE(args);
#ifdef MS_WINDOWS if (nargs >= 2 && nargs <= 4) { if (!PyArg_UnpackTuple(args, "OSError", 2, 4,
&myerrno, &strerror, &filename, &winerror))[](#l3.47)
goto error;[](#l3.48)
if (winerror && PyLong_Check(winerror)) {[](#l3.49)
long errcode;[](#l3.50)
myerrno, strerror, filename, winerror))[](#l3.51)
return -1;[](#l3.52)
if (*winerror && PyLong_Check(*winerror)) {[](#l3.53)
long errcode, winerrcode;[](#l3.54) PyObject *newargs;[](#l3.55) Py_ssize_t i;[](#l3.56)
winerrcode = PyLong_AsLong(winerror);[](#l3.58)
winerrcode = PyLong_AsLong(*winerror);[](#l3.59) if (winerrcode == -1 && PyErr_Occurred())[](#l3.60)
goto error;[](#l3.61)
return -1;[](#l3.62) /* Set errno to the corresponding POSIX errno (overriding[](#l3.63) first argument). Windows Socket error codes (>= 10000)[](#l3.64) have the same value as their POSIX counterparts.[](#l3.65)
@@ -626,59 +623,55 @@ OSError_new(PyTypeObject *type, PyObject errcode = winerror_to_errno(winerrcode); else errcode = winerrcode;
myerrno = PyLong_FromLong(errcode);[](#l3.70)
if (!myerrno)[](#l3.71)
goto error;[](#l3.72)
*myerrno = PyLong_FromLong(errcode);[](#l3.73)
if (!*myerrno)[](#l3.74)
return -1;[](#l3.75) newargs = PyTuple_New(nargs);[](#l3.76) if (!newargs)[](#l3.77)
goto error;[](#l3.78)
PyTuple_SET_ITEM(newargs, 0, myerrno);[](#l3.79)
return -1;[](#l3.80)
PyTuple_SET_ITEM(newargs, 0, *myerrno);[](#l3.81) for (i = 1; i < nargs; i++) {[](#l3.82) PyObject *val = PyTuple_GET_ITEM(args, i);[](#l3.83) Py_INCREF(val);[](#l3.84) PyTuple_SET_ITEM(newargs, i, val);[](#l3.85) }[](#l3.86) Py_DECREF(args);[](#l3.87)
args = newargs;[](#l3.88)
#else if (nargs >= 2 && nargs <= 3) { if (!PyArg_UnpackTuple(args, "OSError", 2, 3,
&myerrno, &strerror, &filename))[](#l3.95)
goto error;[](#l3.96)
- if (myerrno && PyLong_Check(myerrno) &&
errnomap && (PyObject *) type == PyExc_OSError) {[](#l3.102)
PyObject *newtype;[](#l3.103)
newtype = PyDict_GetItem(errnomap, myerrno);[](#l3.104)
if (newtype) {[](#l3.105)
assert(PyType_Check(newtype));[](#l3.106)
type = (PyTypeObject *) newtype;[](#l3.107)
}[](#l3.108)
else if (PyErr_Occurred())[](#l3.109)
goto error;[](#l3.110)
- }
+static int +oserror_init(PyOSErrorObject *self, PyObject **p_args,
PyObject *myerrno, PyObject *strerror,[](#l3.125)
PyObject *filename[](#l3.126)
, PyObject *winerror[](#l3.128)
)[](#l3.130)
/* self->filename will remain Py_None otherwise */ if (filename && filename != Py_None) {
if ((PyObject *) type == PyExc_BlockingIOError &&[](#l3.137)
if (Py_TYPE(self) == (PyTypeObject *) PyExc_BlockingIOError &&[](#l3.138) PyNumber_Check(filename)) {[](#l3.139) /* BlockingIOError's 3rd argument can be the number of[](#l3.140) * characters written.[](#l3.141) */[](#l3.142) self->written = PyNumber_AsSsize_t(filename, PyExc_ValueError);[](#l3.143) if (self->written == -1 && PyErr_Occurred())[](#l3.144)
goto error;[](#l3.145)
return -1;[](#l3.146) }[](#l3.147) else {[](#l3.148) Py_INCREF(filename);[](#l3.149)
@@ -687,20 +680,15 @@ OSError_new(PyTypeObject type, PyObject if (nargs >= 2 && nargs <= 3) { / filename is removed from the args tuple (for compatibility purposes, see test_exceptions.py) */
subslice = PyTuple_GetSlice(args, 0, 2);[](#l3.154)
PyObject *subslice = PyTuple_GetSlice(args, 0, 2);[](#l3.155) if (!subslice)[](#l3.156)
goto error;[](#l3.157)
return -1;[](#l3.158)
Py_DECREF(args); /* replacing args */
args = subslice;[](#l3.161)
- Py_XINCREF(myerrno); self->myerrno = myerrno; @@ -712,6 +700,90 @@ OSError_new(PyTypeObject *type, PyObject self->winerror = winerror; #endif
+} + +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[](#l3.194)
solution, given __new__ takes a variable number of arguments,[](#l3.195)
is to defer arg parsing and initialization to __init__.[](#l3.196)
But when __new__ is overriden as well, it should call our __new__[](#l3.198)
with the right arguments.[](#l3.199)
(see http://bugs.python.org/issue12555#msg148829 )[](#l3.201)
- */
- if (type->tp_init != (initproc) OSError_init &&
type->tp_new == (newfunc) OSError_new) {[](#l3.204)
assert((PyObject *) type != PyExc_OSError);[](#l3.205)
return 1;[](#l3.206)
- }
- return 0;
+} + +static PyObject * +OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{
- if (!oserror_use_init(type)) {
if (!_PyArg_NoKeywords(type->tp_name, kwds))[](#l3.221)
return NULL;[](#l3.222)
Py_INCREF(args);[](#l3.224)
if (oserror_parse_args(&args, &myerrno, &strerror, &filename[](#l3.225)
, &winerror[](#l3.227)
))[](#l3.229)
goto error;[](#l3.230)
if (myerrno && PyLong_Check(myerrno) &&[](#l3.232)
errnomap && (PyObject *) type == PyExc_OSError) {[](#l3.233)
PyObject *newtype;[](#l3.234)
newtype = PyDict_GetItem(errnomap, myerrno);[](#l3.235)
if (newtype) {[](#l3.236)
assert(PyType_Check(newtype));[](#l3.237)
type = (PyTypeObject *) newtype;[](#l3.238)
}[](#l3.239)
else if (PyErr_Occurred())[](#l3.240)
goto error;[](#l3.241)
}[](#l3.242)
- }
, winerror[](#l3.256)
+ return (PyObject *) self; error: @@ -721,10 +793,40 @@ error: } static int -OSError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) +OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds) {
- if (!oserror_use_init(Py_TYPE(self)))
/* Everything already done in OSError_new */[](#l3.279)
return 0;[](#l3.280)
, &winerror[](#l3.288)
))[](#l3.290)
goto error;[](#l3.291)
, winerror[](#l3.295)
))[](#l3.297)
goto error;[](#l3.298)