PEP 3151 / issue #12555: reworking the OS and IO exception hierarchy.

This commit is contained in:
Antoine Pitrou 2011-10-12 02:54:14 +02:00
parent 983b1434bd
commit 6b4883dec0
21 changed files with 689 additions and 454 deletions

View file

@ -45,18 +45,18 @@ typedef struct {
PyObject *myerrno; PyObject *myerrno;
PyObject *strerror; PyObject *strerror;
PyObject *filename; PyObject *filename;
} PyEnvironmentErrorObject;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
typedef struct {
PyException_HEAD
PyObject *myerrno;
PyObject *strerror;
PyObject *filename;
PyObject *winerror; PyObject *winerror;
} PyWindowsErrorObject;
#endif #endif
Py_ssize_t written; /* only for BlockingIOError, -1 otherwise */
} PyOSErrorObject;
/* Compatibility typedefs */
typedef PyOSErrorObject PyEnvironmentErrorObject;
#ifdef MS_WINDOWS
typedef PyOSErrorObject PyWindowsErrorObject;
#endif #endif
#endif /* !Py_LIMITED_API */
/* Error handling definitions */ /* Error handling definitions */
@ -132,10 +132,9 @@ PyAPI_DATA(PyObject *) PyExc_LookupError;
PyAPI_DATA(PyObject *) PyExc_AssertionError; PyAPI_DATA(PyObject *) PyExc_AssertionError;
PyAPI_DATA(PyObject *) PyExc_AttributeError; PyAPI_DATA(PyObject *) PyExc_AttributeError;
PyAPI_DATA(PyObject *) PyExc_BufferError;
PyAPI_DATA(PyObject *) PyExc_EOFError; PyAPI_DATA(PyObject *) PyExc_EOFError;
PyAPI_DATA(PyObject *) PyExc_FloatingPointError; PyAPI_DATA(PyObject *) PyExc_FloatingPointError;
PyAPI_DATA(PyObject *) PyExc_EnvironmentError;
PyAPI_DATA(PyObject *) PyExc_IOError;
PyAPI_DATA(PyObject *) PyExc_OSError; PyAPI_DATA(PyObject *) PyExc_OSError;
PyAPI_DATA(PyObject *) PyExc_ImportError; PyAPI_DATA(PyObject *) PyExc_ImportError;
PyAPI_DATA(PyObject *) PyExc_IndexError; PyAPI_DATA(PyObject *) PyExc_IndexError;
@ -160,6 +159,27 @@ PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError;
PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError; PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError;
PyAPI_DATA(PyObject *) PyExc_ValueError; PyAPI_DATA(PyObject *) PyExc_ValueError;
PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError; PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError;
PyAPI_DATA(PyObject *) PyExc_BlockingIOError;
PyAPI_DATA(PyObject *) PyExc_BrokenPipeError;
PyAPI_DATA(PyObject *) PyExc_ChildProcessError;
PyAPI_DATA(PyObject *) PyExc_ConnectionError;
PyAPI_DATA(PyObject *) PyExc_ConnectionAbortedError;
PyAPI_DATA(PyObject *) PyExc_ConnectionRefusedError;
PyAPI_DATA(PyObject *) PyExc_ConnectionResetError;
PyAPI_DATA(PyObject *) PyExc_FileExistsError;
PyAPI_DATA(PyObject *) PyExc_FileNotFoundError;
PyAPI_DATA(PyObject *) PyExc_InterruptedError;
PyAPI_DATA(PyObject *) PyExc_IsADirectoryError;
PyAPI_DATA(PyObject *) PyExc_NotADirectoryError;
PyAPI_DATA(PyObject *) PyExc_PermissionError;
PyAPI_DATA(PyObject *) PyExc_ProcessLookupError;
PyAPI_DATA(PyObject *) PyExc_TimeoutError;
/* Compatibility aliases */
PyAPI_DATA(PyObject *) PyExc_EnvironmentError;
PyAPI_DATA(PyObject *) PyExc_IOError;
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
PyAPI_DATA(PyObject *) PyExc_WindowsError; PyAPI_DATA(PyObject *) PyExc_WindowsError;
#endif #endif
@ -167,8 +187,6 @@ PyAPI_DATA(PyObject *) PyExc_WindowsError;
PyAPI_DATA(PyObject *) PyExc_VMSError; PyAPI_DATA(PyObject *) PyExc_VMSError;
#endif #endif
PyAPI_DATA(PyObject *) PyExc_BufferError;
PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst; PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst;
/* Predefined warning categories */ /* Predefined warning categories */

View file

@ -23,16 +23,8 @@ DEFAULT_BUFFER_SIZE = 8 * 1024 # bytes
# defined in io.py. We don't use real inheritance though, because we don't # defined in io.py. We don't use real inheritance though, because we don't
# want to inherit the C implementations. # want to inherit the C implementations.
# Rebind for compatibility
class BlockingIOError(IOError): BlockingIOError = BlockingIOError
"""Exception raised when I/O would block on a non-blocking I/O stream."""
def __init__(self, errno, strerror, characters_written=0):
super().__init__(errno, strerror)
if not isinstance(characters_written, int):
raise TypeError("characters_written must be a integer")
self.characters_written = characters_written
def open(file, mode="r", buffering=-1, encoding=None, errors=None, def open(file, mode="r", buffering=-1, encoding=None, errors=None,

View file

@ -321,7 +321,7 @@ if win32:
firstchunk = overlapped.getbuffer() firstchunk = overlapped.getbuffer()
assert lenfirstchunk == len(firstchunk) assert lenfirstchunk == len(firstchunk)
except IOError as e: except IOError as e:
if e.errno == win32.ERROR_BROKEN_PIPE: if e.winerror == win32.ERROR_BROKEN_PIPE:
raise EOFError raise EOFError
raise raise
buf.write(firstchunk) buf.write(firstchunk)
@ -669,7 +669,7 @@ if sys.platform == 'win32':
try: try:
win32.ConnectNamedPipe(handle, win32.NULL) win32.ConnectNamedPipe(handle, win32.NULL)
except WindowsError as e: except WindowsError as e:
if e.args[0] != win32.ERROR_PIPE_CONNECTED: if e.winerror != win32.ERROR_PIPE_CONNECTED:
raise raise
return PipeConnection(handle) return PipeConnection(handle)
@ -692,8 +692,8 @@ if sys.platform == 'win32':
0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL 0, win32.NULL, win32.OPEN_EXISTING, 0, win32.NULL
) )
except WindowsError as e: except WindowsError as e:
if e.args[0] not in (win32.ERROR_SEM_TIMEOUT, if e.winerror not in (win32.ERROR_SEM_TIMEOUT,
win32.ERROR_PIPE_BUSY) or _check_timeout(t): win32.ERROR_PIPE_BUSY) or _check_timeout(t):
raise raise
else: else:
break break

View file

@ -11,11 +11,6 @@ BaseException
+-- AssertionError +-- AssertionError
+-- AttributeError +-- AttributeError
+-- BufferError +-- BufferError
+-- EnvironmentError
| +-- IOError
| +-- OSError
| +-- WindowsError (Windows)
| +-- VMSError (VMS)
+-- EOFError +-- EOFError
+-- ImportError +-- ImportError
+-- LookupError +-- LookupError
@ -24,6 +19,22 @@ BaseException
+-- MemoryError +-- MemoryError
+-- NameError +-- NameError
| +-- UnboundLocalError | +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError +-- ReferenceError
+-- RuntimeError +-- RuntimeError
| +-- NotImplementedError | +-- NotImplementedError

View file

@ -34,7 +34,7 @@ PENDING_FUTURE = create_future(state=PENDING)
RUNNING_FUTURE = create_future(state=RUNNING) RUNNING_FUTURE = create_future(state=RUNNING)
CANCELLED_FUTURE = create_future(state=CANCELLED) CANCELLED_FUTURE = create_future(state=CANCELLED)
CANCELLED_AND_NOTIFIED_FUTURE = create_future(state=CANCELLED_AND_NOTIFIED) CANCELLED_AND_NOTIFIED_FUTURE = create_future(state=CANCELLED_AND_NOTIFIED)
EXCEPTION_FUTURE = create_future(state=FINISHED, exception=IOError()) EXCEPTION_FUTURE = create_future(state=FINISHED, exception=OSError())
SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42)
@ -501,7 +501,7 @@ class FutureTests(unittest.TestCase):
'<Future at 0x[0-9a-f]+ state=cancelled>') '<Future at 0x[0-9a-f]+ state=cancelled>')
self.assertRegex( self.assertRegex(
repr(EXCEPTION_FUTURE), repr(EXCEPTION_FUTURE),
'<Future at 0x[0-9a-f]+ state=finished raised IOError>') '<Future at 0x[0-9a-f]+ state=finished raised OSError>')
self.assertRegex( self.assertRegex(
repr(SUCCESSFUL_FUTURE), repr(SUCCESSFUL_FUTURE),
'<Future at 0x[0-9a-f]+ state=finished returned int>') '<Future at 0x[0-9a-f]+ state=finished returned int>')
@ -512,7 +512,7 @@ class FutureTests(unittest.TestCase):
f2 = create_future(state=RUNNING) f2 = create_future(state=RUNNING)
f3 = create_future(state=CANCELLED) f3 = create_future(state=CANCELLED)
f4 = create_future(state=CANCELLED_AND_NOTIFIED) f4 = create_future(state=CANCELLED_AND_NOTIFIED)
f5 = create_future(state=FINISHED, exception=IOError()) f5 = create_future(state=FINISHED, exception=OSError())
f6 = create_future(state=FINISHED, result=5) f6 = create_future(state=FINISHED, result=5)
self.assertTrue(f1.cancel()) self.assertTrue(f1.cancel())
@ -566,7 +566,7 @@ class FutureTests(unittest.TestCase):
CANCELLED_FUTURE.result, timeout=0) CANCELLED_FUTURE.result, timeout=0)
self.assertRaises(futures.CancelledError, self.assertRaises(futures.CancelledError,
CANCELLED_AND_NOTIFIED_FUTURE.result, timeout=0) CANCELLED_AND_NOTIFIED_FUTURE.result, timeout=0)
self.assertRaises(IOError, EXCEPTION_FUTURE.result, timeout=0) self.assertRaises(OSError, EXCEPTION_FUTURE.result, timeout=0)
self.assertEqual(SUCCESSFUL_FUTURE.result(timeout=0), 42) self.assertEqual(SUCCESSFUL_FUTURE.result(timeout=0), 42)
def test_result_with_success(self): def test_result_with_success(self):
@ -605,7 +605,7 @@ class FutureTests(unittest.TestCase):
self.assertRaises(futures.CancelledError, self.assertRaises(futures.CancelledError,
CANCELLED_AND_NOTIFIED_FUTURE.exception, timeout=0) CANCELLED_AND_NOTIFIED_FUTURE.exception, timeout=0)
self.assertTrue(isinstance(EXCEPTION_FUTURE.exception(timeout=0), self.assertTrue(isinstance(EXCEPTION_FUTURE.exception(timeout=0),
IOError)) OSError))
self.assertEqual(SUCCESSFUL_FUTURE.exception(timeout=0), None) self.assertEqual(SUCCESSFUL_FUTURE.exception(timeout=0), None)
def test_exception_with_success(self): def test_exception_with_success(self):
@ -614,14 +614,14 @@ class FutureTests(unittest.TestCase):
time.sleep(1) time.sleep(1)
with f1._condition: with f1._condition:
f1._state = FINISHED f1._state = FINISHED
f1._exception = IOError() f1._exception = OSError()
f1._condition.notify_all() f1._condition.notify_all()
f1 = create_future(state=PENDING) f1 = create_future(state=PENDING)
t = threading.Thread(target=notification) t = threading.Thread(target=notification)
t.start() t.start()
self.assertTrue(isinstance(f1.exception(timeout=5), IOError)) self.assertTrue(isinstance(f1.exception(timeout=5), OSError))
@test.support.reap_threads @test.support.reap_threads
def test_main(): def test_main():

View file

@ -46,8 +46,8 @@ class ExceptionTests(unittest.TestCase):
fp.close() fp.close()
unlink(TESTFN) unlink(TESTFN)
self.raise_catch(IOError, "IOError") self.raise_catch(OSError, "OSError")
self.assertRaises(IOError, open, 'this file does not exist', 'r') self.assertRaises(OSError, open, 'this file does not exist', 'r')
self.raise_catch(ImportError, "ImportError") self.raise_catch(ImportError, "ImportError")
self.assertRaises(ImportError, __import__, "undefined_module") self.assertRaises(ImportError, __import__, "undefined_module")
@ -192,11 +192,35 @@ class ExceptionTests(unittest.TestCase):
except NameError: except NameError:
pass pass
else: else:
self.assertEqual(str(WindowsError(1001)), "1001") self.assertIs(WindowsError, OSError)
self.assertEqual(str(WindowsError(1001, "message")), self.assertEqual(str(OSError(1001)), "1001")
"[Error 1001] message") self.assertEqual(str(OSError(1001, "message")),
self.assertEqual(WindowsError(1001, "message").errno, 22) "[Errno 1001] message")
self.assertEqual(WindowsError(1001, "message").winerror, 1001) # POSIX errno (9 aka EBADF) is untranslated
w = OSError(9, 'foo', 'bar')
self.assertEqual(w.errno, 9)
self.assertEqual(w.winerror, None)
self.assertEqual(str(w), "[Errno 9] foo: 'bar'")
# ERROR_PATH_NOT_FOUND (win error 3) becomes ENOENT (2)
w = OSError(0, 'foo', 'bar', 3)
self.assertEqual(w.errno, 2)
self.assertEqual(w.winerror, 3)
self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, 'bar')
self.assertEqual(str(w), "[Error 3] foo: 'bar'")
# Unknown win error becomes EINVAL (22)
w = OSError(0, 'foo', None, 1001)
self.assertEqual(w.errno, 22)
self.assertEqual(w.winerror, 1001)
self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, None)
self.assertEqual(str(w), "[Error 1001] foo")
# Non-numeric "errno"
w = OSError('bar', 'foo')
self.assertEqual(w.errno, 'bar')
self.assertEqual(w.winerror, None)
self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, None)
def testAttributes(self): def testAttributes(self):
# test that exception attributes are happy # test that exception attributes are happy
@ -274,11 +298,12 @@ class ExceptionTests(unittest.TestCase):
'start' : 0, 'end' : 1}), 'start' : 0, 'end' : 1}),
] ]
try: try:
# More tests are in test_WindowsError
exceptionList.append( exceptionList.append(
(WindowsError, (1, 'strErrorStr', 'filenameStr'), (WindowsError, (1, 'strErrorStr', 'filenameStr'),
{'args' : (1, 'strErrorStr'), {'args' : (1, 'strErrorStr'),
'strerror' : 'strErrorStr', 'winerror' : 1, 'strerror' : 'strErrorStr', 'winerror' : None,
'errno' : 22, 'filename' : 'filenameStr'}) 'errno' : 1, 'filename' : 'filenameStr'})
) )
except NameError: except NameError:
pass pass

View file

@ -248,18 +248,19 @@ class FileCookieJarTests(unittest.TestCase):
self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None) self.assertEqual(c._cookies["www.acme.com"]["/"]["boo"].value, None)
def test_bad_magic(self): def test_bad_magic(self):
# IOErrors (eg. file doesn't exist) are allowed to propagate # OSErrors (eg. file doesn't exist) are allowed to propagate
filename = test.support.TESTFN filename = test.support.TESTFN
for cookiejar_class in LWPCookieJar, MozillaCookieJar: for cookiejar_class in LWPCookieJar, MozillaCookieJar:
c = cookiejar_class() c = cookiejar_class()
try: try:
c.load(filename="for this test to work, a file with this " c.load(filename="for this test to work, a file with this "
"filename should not exist") "filename should not exist")
except IOError as exc: except OSError as exc:
# exactly IOError, not LoadError # an OSError subclass (likely FileNotFoundError), but not
self.assertIs(exc.__class__, IOError) # LoadError
self.assertIsNot(exc.__class__, LoadError)
else: else:
self.fail("expected IOError for invalid filename") self.fail("expected OSError for invalid filename")
# Invalid contents of cookies file (eg. bad magic string) # Invalid contents of cookies file (eg. bad magic string)
# causes a LoadError. # causes a LoadError.
try: try:

View file

@ -2643,12 +2643,6 @@ class MiscIOTest(unittest.TestCase):
def test_blockingioerror(self): def test_blockingioerror(self):
# Various BlockingIOError issues # Various BlockingIOError issues
self.assertRaises(TypeError, self.BlockingIOError)
self.assertRaises(TypeError, self.BlockingIOError, 1)
self.assertRaises(TypeError, self.BlockingIOError, 1, 2, 3, 4)
self.assertRaises(TypeError, self.BlockingIOError, 1, "", None)
b = self.BlockingIOError(1, "")
self.assertEqual(b.characters_written, 0)
class C(str): class C(str):
pass pass
c = C("") c = C("")

View file

@ -563,8 +563,7 @@ class MmapTests(unittest.TestCase):
f.close() f.close()
def test_error(self): def test_error(self):
self.assertTrue(issubclass(mmap.error, EnvironmentError)) self.assertIs(mmap.error, OSError)
self.assertIn("mmap.error", str(mmap.error))
def test_io_methods(self): def test_io_methods(self):
data = b"0123456789" data = b"0123456789"

128
Lib/test/test_pep3151.py Normal file
View file

@ -0,0 +1,128 @@
import builtins
import os
import select
import socket
import sys
import unittest
import errno
from errno import EEXIST
from test import support
class SubOSError(OSError):
pass
class HierarchyTest(unittest.TestCase):
def test_builtin_errors(self):
self.assertEqual(OSError.__name__, 'OSError')
self.assertIs(IOError, OSError)
self.assertIs(EnvironmentError, OSError)
def test_socket_errors(self):
self.assertIs(socket.error, IOError)
self.assertIs(socket.gaierror.__base__, OSError)
self.assertIs(socket.herror.__base__, OSError)
self.assertIs(socket.timeout.__base__, OSError)
def test_select_error(self):
self.assertIs(select.error, OSError)
# mmap.error is tested in test_mmap
_pep_map = """
+-- BlockingIOError EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS
+-- ChildProcessError ECHILD
+-- ConnectionError
+-- BrokenPipeError EPIPE, ESHUTDOWN
+-- ConnectionAbortedError ECONNABORTED
+-- ConnectionRefusedError ECONNREFUSED
+-- ConnectionResetError ECONNRESET
+-- FileExistsError EEXIST
+-- FileNotFoundError ENOENT
+-- InterruptedError EINTR
+-- IsADirectoryError EISDIR
+-- NotADirectoryError ENOTDIR
+-- PermissionError EACCES, EPERM
+-- ProcessLookupError ESRCH
+-- TimeoutError ETIMEDOUT
"""
def _make_map(s):
_map = {}
for line in s.splitlines():
line = line.strip('+- ')
if not line:
continue
excname, _, errnames = line.partition(' ')
for errname in filter(None, errnames.strip().split(', ')):
_map[getattr(errno, errname)] = getattr(builtins, excname)
return _map
_map = _make_map(_pep_map)
def test_errno_mapping(self):
# The OSError constructor maps errnos to subclasses
# A sample test for the basic functionality
e = OSError(EEXIST, "Bad file descriptor")
self.assertIs(type(e), FileExistsError)
# Exhaustive testing
for errcode, exc in self._map.items():
e = OSError(errcode, "Some message")
self.assertIs(type(e), exc)
othercodes = set(errno.errorcode) - set(self._map)
for errcode in othercodes:
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
e = SubOSError(EEXIST, "Bad file descriptor")
self.assertIs(type(e), SubOSError)
class AttributesTest(unittest.TestCase):
def test_windows_error(self):
if os.name == "nt":
self.assertIn('winerror', dir(OSError))
else:
self.assertNotIn('winerror', dir(OSError))
def test_posix_error(self):
e = OSError(EEXIST, "File already exists", "foo.txt")
self.assertEqual(e.errno, EEXIST)
self.assertEqual(e.args[0], EEXIST)
self.assertEqual(e.strerror, "File already exists")
self.assertEqual(e.filename, "foo.txt")
if os.name == "nt":
self.assertEqual(e.winerror, None)
@unittest.skipUnless(os.name == "nt", "Windows-specific test")
def test_errno_translation(self):
# ERROR_ALREADY_EXISTS (183) -> EEXIST
e = OSError(0, "File already exists", "foo.txt", 183)
self.assertEqual(e.winerror, 183)
self.assertEqual(e.errno, EEXIST)
self.assertEqual(e.args[0], EEXIST)
self.assertEqual(e.strerror, "File already exists")
self.assertEqual(e.filename, "foo.txt")
def test_blockingioerror(self):
args = ("a", "b", "c", "d", "e")
for n in range(6):
e = BlockingIOError(*args[:n])
with self.assertRaises(AttributeError):
e.characters_written
e = BlockingIOError("a", "b", 3)
self.assertEqual(e.characters_written, 3)
e.characters_written = 5
self.assertEqual(e.characters_written, 5)
# XXX VMSError not tested
def test_main():
support.run_unittest(__name__)
if __name__=="__main__":
test_main()

View file

@ -1339,7 +1339,7 @@ def xinclude_loader(href, parse="xml", encoding=None):
try: try:
data = XINCLUDE[href] data = XINCLUDE[href]
except KeyError: except KeyError:
raise IOError("resource not found") raise OSError("resource not found")
if parse == "xml": if parse == "xml":
from xml.etree.ElementTree import XML from xml.etree.ElementTree import XML
return XML(data) return XML(data)
@ -1404,7 +1404,7 @@ def xinclude():
>>> document = xinclude_loader("C5.xml") >>> document = xinclude_loader("C5.xml")
>>> ElementInclude.include(document, xinclude_loader) >>> ElementInclude.include(document, xinclude_loader)
Traceback (most recent call last): Traceback (most recent call last):
IOError: resource not found OSError: resource not found
>>> # print(serialize(document)) # C5 >>> # print(serialize(document)) # C5
""" """
@ -1611,7 +1611,7 @@ def bug_xmltoolkit55():
class ExceptionFile: class ExceptionFile:
def read(self, x): def read(self, x):
raise IOError raise OSError
def xmltoolkit60(): def xmltoolkit60():
""" """
@ -1619,7 +1619,7 @@ def xmltoolkit60():
Handle crash in stream source. Handle crash in stream source.
>>> tree = ET.parse(ExceptionFile()) >>> tree = ET.parse(ExceptionFile())
Traceback (most recent call last): Traceback (most recent call last):
IOError OSError
""" """

View file

@ -1547,6 +1547,8 @@ class URLopener:
return getattr(self, name)(url) return getattr(self, name)(url)
else: else:
return getattr(self, name)(url, data) return getattr(self, name)(url, data)
except HTTPError:
raise
except socket.error as msg: except socket.error as msg:
raise IOError('socket error', msg).with_traceback(sys.exc_info()[2]) raise IOError('socket error', msg).with_traceback(sys.exc_info()[2])

View file

@ -10,6 +10,8 @@ What's New in Python 3.3 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- PEP 3151 / issue #12555: reworking the OS and IO exception hierarchy.
- Add internal API for static strings (_Py_identifier et.al.). - Add internal API for static strings (_Py_identifier et.al.).
- Issue #13063: the Windows error ERROR_NO_DATA (numbered 232 and described - Issue #13063: the Windows error ERROR_NO_DATA (numbered 232 and described

View file

@ -90,89 +90,6 @@ PyDoc_STRVAR(module_doc,
); );
/*
* BlockingIOError extends IOError
*/
static int
blockingioerror_init(PyBlockingIOErrorObject *self, PyObject *args,
PyObject *kwds)
{
PyObject *myerrno = NULL, *strerror = NULL;
PyObject *baseargs = NULL;
Py_ssize_t written = 0;
assert(PyTuple_Check(args));
self->written = 0;
if (!PyArg_ParseTuple(args, "OO|n:BlockingIOError",
&myerrno, &strerror, &written))
return -1;
baseargs = PyTuple_Pack(2, myerrno, strerror);
if (baseargs == NULL)
return -1;
/* This will take care of initializing of myerrno and strerror members */
if (((PyTypeObject *)PyExc_IOError)->tp_init(
(PyObject *)self, baseargs, kwds) == -1) {
Py_DECREF(baseargs);
return -1;
}
Py_DECREF(baseargs);
self->written = written;
return 0;
}
static PyMemberDef blockingioerror_members[] = {
{"characters_written", T_PYSSIZET, offsetof(PyBlockingIOErrorObject, written), 0},
{NULL} /* Sentinel */
};
static PyTypeObject _PyExc_BlockingIOError = {
PyVarObject_HEAD_INIT(NULL, 0)
"BlockingIOError", /*tp_name*/
sizeof(PyBlockingIOErrorObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare */
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
PyDoc_STR("Exception raised when I/O would block "
"on a non-blocking I/O stream"), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
blockingioerror_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)blockingioerror_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
PyObject *PyExc_BlockingIOError = (PyObject *)&_PyExc_BlockingIOError;
/* /*
* The main open() function * The main open() function
*/ */
@ -694,9 +611,11 @@ PyInit__io(void)
state->unsupported_operation) < 0) state->unsupported_operation) < 0)
goto fail; goto fail;
/* BlockingIOError */ /* BlockingIOError, for compatibility */
_PyExc_BlockingIOError.tp_base = (PyTypeObject *) PyExc_IOError; Py_INCREF(PyExc_BlockingIOError);
ADD_TYPE(&_PyExc_BlockingIOError, "BlockingIOError"); if (PyModule_AddObject(m, "BlockingIOError",
(PyObject *) PyExc_BlockingIOError) < 0)
goto fail;
/* Concrete base types of the IO ABCs. /* Concrete base types of the IO ABCs.
(the ABCs themselves are declared through inheritance in io.py) (the ABCs themselves are declared through inheritance in io.py)

View file

@ -60,15 +60,6 @@ extern Py_ssize_t _PyIO_find_line_ending(
#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */ #define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
typedef struct {
PyException_HEAD
PyObject *myerrno;
PyObject *strerror;
PyObject *filename; /* Not used, but part of the IOError object */
Py_ssize_t written;
} PyBlockingIOErrorObject;
PyAPI_DATA(PyObject *) PyExc_BlockingIOError;
/* /*
* Offset type for positioning. * Offset type for positioning.
*/ */

View file

@ -622,14 +622,14 @@ static Py_ssize_t *
_buffered_check_blocking_error(void) _buffered_check_blocking_error(void)
{ {
PyObject *t, *v, *tb; PyObject *t, *v, *tb;
PyBlockingIOErrorObject *err; PyOSErrorObject *err;
PyErr_Fetch(&t, &v, &tb); PyErr_Fetch(&t, &v, &tb);
if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) { if (v == NULL || !PyErr_GivenExceptionMatches(v, PyExc_BlockingIOError)) {
PyErr_Restore(t, v, tb); PyErr_Restore(t, v, tb);
return NULL; return NULL;
} }
err = (PyBlockingIOErrorObject *) v; err = (PyOSErrorObject *) v;
/* TODO: sanity check (err->written >= 0) */ /* TODO: sanity check (err->written >= 0) */
PyErr_Restore(t, v, tb); PyErr_Restore(t, v, tb);
return &err->written; return &err->written;

View file

@ -78,8 +78,6 @@ my_getpagesize(void)
# define MAP_ANONYMOUS MAP_ANON # define MAP_ANONYMOUS MAP_ANON
#endif #endif
static PyObject *mmap_module_error;
typedef enum typedef enum
{ {
ACCESS_DEFAULT, ACCESS_DEFAULT,
@ -459,7 +457,7 @@ mmap_size_method(mmap_object *self,
{ {
struct stat buf; struct stat buf;
if (-1 == fstat(self->fd, &buf)) { if (-1 == fstat(self->fd, &buf)) {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
#ifdef HAVE_LARGEFILE_SUPPORT #ifdef HAVE_LARGEFILE_SUPPORT
@ -549,7 +547,7 @@ mmap_resize_method(mmap_object *self,
void *newmap; void *newmap;
if (ftruncate(self->fd, self->offset + new_size) == -1) { if (ftruncate(self->fd, self->offset + new_size) == -1) {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
@ -564,7 +562,7 @@ mmap_resize_method(mmap_object *self,
#endif #endif
if (newmap == (void *)-1) if (newmap == (void *)-1)
{ {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
self->data = newmap; self->data = newmap;
@ -605,7 +603,7 @@ mmap_flush_method(mmap_object *self, PyObject *args)
/* XXX semantics of return value? */ /* XXX semantics of return value? */
/* XXX flags for msync? */ /* XXX flags for msync? */
if (-1 == msync(self->data + offset, size, MS_SYNC)) { if (-1 == msync(self->data + offset, size, MS_SYNC)) {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
return PyLong_FromLong(0); return PyLong_FromLong(0);
@ -1205,7 +1203,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
fd = devzero = open("/dev/zero", O_RDWR); fd = devzero = open("/dev/zero", O_RDWR);
if (devzero == -1) { if (devzero == -1) {
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
#endif #endif
@ -1213,7 +1211,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
m_obj->fd = dup(fd); m_obj->fd = dup(fd);
if (m_obj->fd == -1) { if (m_obj->fd == -1) {
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
} }
@ -1229,7 +1227,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
if (m_obj->data == (char *)-1) { if (m_obj->data == (char *)-1) {
m_obj->data = NULL; m_obj->data = NULL;
Py_DECREF(m_obj); Py_DECREF(m_obj);
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
m_obj->access = (access_mode)access; m_obj->access = (access_mode)access;
@ -1310,12 +1308,12 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
if (fileno != -1 && fileno != 0) { if (fileno != -1 && fileno != 0) {
/* Ensure that fileno is within the CRT's valid range */ /* Ensure that fileno is within the CRT's valid range */
if (_PyVerify_fd(fileno) == 0) { if (_PyVerify_fd(fileno) == 0) {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
fh = (HANDLE)_get_osfhandle(fileno); fh = (HANDLE)_get_osfhandle(fileno);
if (fh==(HANDLE)-1) { if (fh==(HANDLE)-1) {
PyErr_SetFromErrno(mmap_module_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
/* Win9x appears to need us seeked to zero */ /* Win9x appears to need us seeked to zero */
@ -1469,11 +1467,7 @@ PyInit_mmap(void)
dict = PyModule_GetDict(module); dict = PyModule_GetDict(module);
if (!dict) if (!dict)
return NULL; return NULL;
mmap_module_error = PyErr_NewException("mmap.error", PyDict_SetItemString(dict, "error", PyExc_OSError);
PyExc_EnvironmentError , NULL);
if (mmap_module_error == NULL)
return NULL;
PyDict_SetItemString(dict, "error", mmap_module_error);
PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type); PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
#ifdef PROT_EXEC #ifdef PROT_EXEC
setint(dict, "PROT_EXEC", PROT_EXEC); setint(dict, "PROT_EXEC", PROT_EXEC);

View file

@ -54,8 +54,6 @@ extern void bzero(void *, int);
# endif # endif
#endif #endif
static PyObject *SelectError;
/* list of Python objects and their file descriptor */ /* list of Python objects and their file descriptor */
typedef struct { typedef struct {
PyObject *obj; /* owned reference */ PyObject *obj; /* owned reference */
@ -274,11 +272,11 @@ select_select(PyObject *self, PyObject *args)
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if (n == SOCKET_ERROR) { if (n == SOCKET_ERROR) {
PyErr_SetExcFromWindowsErr(SelectError, WSAGetLastError()); PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
} }
#else #else
if (n < 0) { if (n < 0) {
PyErr_SetFromErrno(SelectError); PyErr_SetFromErrno(PyExc_OSError);
} }
#endif #endif
else { else {
@ -425,7 +423,7 @@ poll_modify(pollObject *self, PyObject *args)
return NULL; return NULL;
if (PyDict_GetItem(self->dict, key) == NULL) { if (PyDict_GetItem(self->dict, key) == NULL) {
errno = ENOENT; errno = ENOENT;
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
value = PyLong_FromLong(events); value = PyLong_FromLong(events);
@ -524,7 +522,7 @@ poll_poll(pollObject *self, PyObject *args)
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (poll_result < 0) { if (poll_result < 0) {
PyErr_SetFromErrno(SelectError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
@ -764,7 +762,7 @@ newPyEpoll_Object(PyTypeObject *type, int sizehint, SOCKET fd)
} }
if (self->epfd < 0) { if (self->epfd < 0) {
Py_DECREF(self); Py_DECREF(self);
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
return (PyObject *)self; return (PyObject *)self;
@ -797,7 +795,7 @@ pyepoll_close(pyEpoll_Object *self)
{ {
errno = pyepoll_internal_close(self); errno = pyepoll_internal_close(self);
if (errno < 0) { if (errno < 0) {
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
@ -890,7 +888,7 @@ pyepoll_internal_ctl(int epfd, int op, PyObject *pfd, unsigned int events)
} }
if (result < 0) { if (result < 0) {
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
@ -914,7 +912,7 @@ pyepoll_register(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
PyDoc_STRVAR(pyepoll_register_doc, PyDoc_STRVAR(pyepoll_register_doc,
"register(fd[, eventmask]) -> None\n\ "register(fd[, eventmask]) -> None\n\
\n\ \n\
Registers a new fd or raises an IOError if the fd is already registered.\n\ Registers a new fd or raises an OSError if the fd is already registered.\n\
fd is the target file descriptor of the operation.\n\ fd is the target file descriptor of the operation.\n\
events is a bit set composed of the various EPOLL constants; the default\n\ events is a bit set composed of the various EPOLL constants; the default\n\
is EPOLL_IN | EPOLL_OUT | EPOLL_PRI.\n\ is EPOLL_IN | EPOLL_OUT | EPOLL_PRI.\n\
@ -1013,7 +1011,7 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds)
nfds = epoll_wait(self->epfd, evs, maxevents, timeout); nfds = epoll_wait(self->epfd, evs, maxevents, timeout);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (nfds < 0) { if (nfds < 0) {
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
goto error; goto error;
} }
@ -1404,7 +1402,7 @@ newKqueue_Object(PyTypeObject *type, SOCKET fd)
} }
if (self->kqfd < 0) { if (self->kqfd < 0) {
Py_DECREF(self); Py_DECREF(self);
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
return (PyObject *)self; return (PyObject *)self;
@ -1436,7 +1434,7 @@ kqueue_queue_close(kqueue_queue_Object *self)
{ {
errno = kqueue_queue_internal_close(self); errno = kqueue_queue_internal_close(self);
if (errno < 0) { if (errno < 0) {
PyErr_SetFromErrno(PyExc_IOError); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
Py_RETURN_NONE; Py_RETURN_NONE;
@ -1778,9 +1776,8 @@ PyInit_select(void)
if (m == NULL) if (m == NULL)
return NULL; return NULL;
SelectError = PyErr_NewException("select.error", NULL, NULL); Py_INCREF(PyExc_OSError);
Py_INCREF(SelectError); PyModule_AddObject(m, "error", PyExc_OSError);
PyModule_AddObject(m, "error", SelectError);
#ifdef PIPE_BUF #ifdef PIPE_BUF
#ifdef HAVE_BROKEN_PIPE_BUF #ifdef HAVE_BROKEN_PIPE_BUF

View file

@ -457,7 +457,6 @@ dup_socket(SOCKET handle)
/* Global variable holding the exception type for errors detected /* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */ by this module (but not argument type or memory errors, etc.). */
static PyObject *socket_error;
static PyObject *socket_herror; static PyObject *socket_herror;
static PyObject *socket_gaierror; static PyObject *socket_gaierror;
static PyObject *socket_timeout; static PyObject *socket_timeout;
@ -498,7 +497,7 @@ static PyTypeObject sock_type;
static PyObject* static PyObject*
select_error(void) select_error(void)
{ {
PyErr_SetString(socket_error, "unable to select on socket"); PyErr_SetString(PyExc_OSError, "unable to select on socket");
return NULL; return NULL;
} }
@ -525,7 +524,7 @@ set_error(void)
recognizes the error codes used by both GetLastError() and recognizes the error codes used by both GetLastError() and
WSAGetLastError */ WSAGetLastError */
if (err_no) if (err_no)
return PyErr_SetExcFromWindowsErr(socket_error, err_no); return PyErr_SetExcFromWindowsErr(PyExc_OSError, err_no);
#endif #endif
#if defined(PYOS_OS2) && !defined(PYCC_GCC) #if defined(PYOS_OS2) && !defined(PYCC_GCC)
@ -556,7 +555,7 @@ set_error(void)
} }
v = Py_BuildValue("(is)", myerrorcode, outbuf); v = Py_BuildValue("(is)", myerrorcode, outbuf);
if (v != NULL) { if (v != NULL) {
PyErr_SetObject(socket_error, v); PyErr_SetObject(PyExc_OSError, v);
Py_DECREF(v); Py_DECREF(v);
} }
return NULL; return NULL;
@ -564,7 +563,7 @@ set_error(void)
} }
#endif #endif
return PyErr_SetFromErrno(socket_error); return PyErr_SetFromErrno(PyExc_OSError);
} }
@ -883,13 +882,13 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
#endif #endif
default: default:
freeaddrinfo(res); freeaddrinfo(res);
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"unsupported address family"); "unsupported address family");
return -1; return -1;
} }
if (res->ai_next) { if (res->ai_next) {
freeaddrinfo(res); freeaddrinfo(res);
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"wildcard resolved to multiple address"); "wildcard resolved to multiple address");
return -1; return -1;
} }
@ -902,7 +901,7 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) { if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) {
struct sockaddr_in *sin; struct sockaddr_in *sin;
if (af != AF_INET && af != AF_UNSPEC) { if (af != AF_INET && af != AF_UNSPEC) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"address family mismatched"); "address family mismatched");
return -1; return -1;
} }
@ -960,7 +959,7 @@ setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
return 16; return 16;
#endif #endif
default: default:
PyErr_SetString(socket_error, "unknown address family"); PyErr_SetString(PyExc_OSError, "unknown address family");
return -1; return -1;
} }
} }
@ -1009,7 +1008,7 @@ setbdaddr(char *name, bdaddr_t *bdaddr)
bdaddr->b[5] = b5; bdaddr->b[5] = b5;
return 6; return 6;
} else { } else {
PyErr_SetString(socket_error, "bad bluetooth address"); PyErr_SetString(PyExc_OSError, "bad bluetooth address");
return -1; return -1;
} }
} }
@ -1278,7 +1277,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
if (len > 0 && path[0] == 0) { if (len > 0 && path[0] == 0) {
/* Linux abstract namespace extension */ /* Linux abstract namespace extension */
if (len > sizeof addr->sun_path) { if (len > sizeof addr->sun_path) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long"); "AF_UNIX path too long");
return 0; return 0;
} }
@ -1288,7 +1287,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
{ {
/* regular NULL-terminated string */ /* regular NULL-terminated string */
if (len >= sizeof addr->sun_path) { if (len >= sizeof addr->sun_path) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"AF_UNIX path too long"); "AF_UNIX path too long");
return 0; return 0;
} }
@ -1418,7 +1417,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
_BT_L2_MEMB(addr, family) = AF_BLUETOOTH; _BT_L2_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr, if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_L2_MEMB(addr, psm))) { &_BT_L2_MEMB(addr, psm))) {
PyErr_SetString(socket_error, "getsockaddrarg: " PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
"wrong format"); "wrong format");
return 0; return 0;
} }
@ -1437,7 +1436,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
_BT_RC_MEMB(addr, family) = AF_BLUETOOTH; _BT_RC_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "si", &straddr, if (!PyArg_ParseTuple(args, "si", &straddr,
&_BT_RC_MEMB(addr, channel))) { &_BT_RC_MEMB(addr, channel))) {
PyErr_SetString(socket_error, "getsockaddrarg: " PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
"wrong format"); "wrong format");
return 0; return 0;
} }
@ -1455,7 +1454,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
if (straddr == NULL) { if (straddr == NULL) {
PyErr_SetString(socket_error, "getsockaddrarg: " PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
"wrong format"); "wrong format");
return 0; return 0;
} }
@ -1464,7 +1463,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
#else #else
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) { if (!PyArg_ParseTuple(args, "i", &_BT_HCI_MEMB(addr, dev))) {
PyErr_SetString(socket_error, "getsockaddrarg: " PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
"wrong format"); "wrong format");
return 0; return 0;
} }
@ -1481,7 +1480,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
addr = (struct sockaddr_sco *)addr_ret; addr = (struct sockaddr_sco *)addr_ret;
_BT_SCO_MEMB(addr, family) = AF_BLUETOOTH; _BT_SCO_MEMB(addr, family) = AF_BLUETOOTH;
if (!PyBytes_Check(args)) { if (!PyBytes_Check(args)) {
PyErr_SetString(socket_error, "getsockaddrarg: " PyErr_SetString(PyExc_OSError, "getsockaddrarg: "
"wrong format"); "wrong format");
return 0; return 0;
} }
@ -1494,7 +1493,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
} }
#endif #endif
default: default:
PyErr_SetString(socket_error, "getsockaddrarg: unknown Bluetooth protocol"); PyErr_SetString(PyExc_OSError, "getsockaddrarg: unknown Bluetooth protocol");
return 0; return 0;
} }
} }
@ -1633,7 +1632,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0; return 0;
} }
} else { } else {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"AF_CAN interface name too long"); "AF_CAN interface name too long");
Py_DECREF(interfaceName); Py_DECREF(interfaceName);
return 0; return 0;
@ -1647,7 +1646,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 1; return 1;
} }
default: default:
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"getsockaddrarg: unsupported CAN protocol"); "getsockaddrarg: unsupported CAN protocol");
return 0; return 0;
} }
@ -1656,7 +1655,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
/* More cases here... */ /* More cases here... */
default: default:
PyErr_SetString(socket_error, "getsockaddrarg: bad family"); PyErr_SetString(PyExc_OSError, "getsockaddrarg: bad family");
return 0; return 0;
} }
@ -1722,7 +1721,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
return 1; return 1;
#endif #endif
default: default:
PyErr_SetString(socket_error, "getsockaddrlen: " PyErr_SetString(PyExc_OSError, "getsockaddrlen: "
"unknown BT protocol"); "unknown BT protocol");
return 0; return 0;
@ -1757,7 +1756,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
/* More cases here... */ /* More cases here... */
default: default:
PyErr_SetString(socket_error, "getsockaddrlen: bad family"); PyErr_SetString(PyExc_OSError, "getsockaddrlen: bad family");
return 0; return 0;
} }
@ -2098,7 +2097,7 @@ sock_getsockopt(PySocketSockObject *s, PyObject *args)
#else #else
if (buflen <= 0 || buflen > 1024) { if (buflen <= 0 || buflen > 1024) {
#endif #endif
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"getsockopt buflen out of range"); "getsockopt buflen out of range");
return NULL; return NULL;
} }
@ -2926,7 +2925,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
if (cmsg_status < 0) if (cmsg_status < 0)
break; break;
if (cmsgdatalen > PY_SSIZE_T_MAX) { if (cmsgdatalen > PY_SSIZE_T_MAX) {
PyErr_SetString(socket_error, "control message too long"); PyErr_SetString(PyExc_OSError, "control message too long");
goto err_closefds; goto err_closefds;
} }
@ -3087,7 +3086,7 @@ sock_recvmsg_into(PySocketSockObject *s, PyObject *args)
return NULL; return NULL;
nitems = PySequence_Fast_GET_SIZE(fast); nitems = PySequence_Fast_GET_SIZE(fast);
if (nitems > INT_MAX) { if (nitems > INT_MAX) {
PyErr_SetString(socket_error, "recvmsg_into() argument 1 is too long"); PyErr_SetString(PyExc_OSError, "recvmsg_into() argument 1 is too long");
goto finally; goto finally;
} }
@ -3394,7 +3393,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
goto finally; goto finally;
ndataparts = PySequence_Fast_GET_SIZE(data_fast); ndataparts = PySequence_Fast_GET_SIZE(data_fast);
if (ndataparts > INT_MAX) { if (ndataparts > INT_MAX) {
PyErr_SetString(socket_error, "sendmsg() argument 1 is too long"); PyErr_SetString(PyExc_OSError, "sendmsg() argument 1 is too long");
goto finally; goto finally;
} }
msg.msg_iovlen = ndataparts; msg.msg_iovlen = ndataparts;
@ -3426,7 +3425,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
#ifndef CMSG_SPACE #ifndef CMSG_SPACE
if (ncmsgs > 1) { if (ncmsgs > 1) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"sending multiple control messages is not supported " "sending multiple control messages is not supported "
"on this system"); "on this system");
goto finally; goto finally;
@ -3455,12 +3454,12 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
#else #else
if (!get_CMSG_LEN(bufsize, &space)) { if (!get_CMSG_LEN(bufsize, &space)) {
#endif #endif
PyErr_SetString(socket_error, "ancillary data item too large"); PyErr_SetString(PyExc_OSError, "ancillary data item too large");
goto finally; goto finally;
} }
controllen += space; controllen += space;
if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) { if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) {
PyErr_SetString(socket_error, "too much ancillary data"); PyErr_SetString(PyExc_OSError, "too much ancillary data");
goto finally; goto finally;
} }
controllen_last = controllen; controllen_last = controllen;
@ -4000,7 +3999,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
if (h->h_addrtype != af) { if (h->h_addrtype != af) {
/* Let's get real error message to return */ /* Let's get real error message to return */
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
(char *)strerror(EAFNOSUPPORT)); (char *)strerror(EAFNOSUPPORT));
return NULL; return NULL;
@ -4085,7 +4084,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af)
#endif #endif
default: /* can't happen */ default: /* can't happen */
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"unsupported address family"); "unsupported address family");
return NULL; return NULL;
} }
@ -4239,7 +4238,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
break; break;
#endif #endif
default: default:
PyErr_SetString(socket_error, "unsupported address family"); PyErr_SetString(PyExc_OSError, "unsupported address family");
goto finally; goto finally;
} }
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
@ -4295,7 +4294,7 @@ socket_getservbyname(PyObject *self, PyObject *args)
sp = getservbyname(name, proto); sp = getservbyname(name, proto);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (sp == NULL) { if (sp == NULL) {
PyErr_SetString(socket_error, "service/proto not found"); PyErr_SetString(PyExc_OSError, "service/proto not found");
return NULL; return NULL;
} }
return PyLong_FromLong((long) ntohs(sp->s_port)); return PyLong_FromLong((long) ntohs(sp->s_port));
@ -4332,7 +4331,7 @@ socket_getservbyport(PyObject *self, PyObject *args)
sp = getservbyport(htons((short)port), proto); sp = getservbyport(htons((short)port), proto);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (sp == NULL) { if (sp == NULL) {
PyErr_SetString(socket_error, "port/proto not found"); PyErr_SetString(PyExc_OSError, "port/proto not found");
return NULL; return NULL;
} }
return PyUnicode_FromString(sp->s_name); return PyUnicode_FromString(sp->s_name);
@ -4361,7 +4360,7 @@ socket_getprotobyname(PyObject *self, PyObject *args)
sp = getprotobyname(name); sp = getprotobyname(name);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
if (sp == NULL) { if (sp == NULL) {
PyErr_SetString(socket_error, "protocol not found"); PyErr_SetString(PyExc_OSError, "protocol not found");
return NULL; return NULL;
} }
return PyLong_FromLong((long) sp->p_proto); return PyLong_FromLong((long) sp->p_proto);
@ -4616,7 +4615,7 @@ socket_inet_aton(PyObject *self, PyObject *args)
return PyBytes_FromStringAndSize((char *)(&buf), return PyBytes_FromStringAndSize((char *)(&buf),
sizeof(buf)); sizeof(buf));
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"illegal IP address string passed to inet_aton"); "illegal IP address string passed to inet_aton");
return NULL; return NULL;
@ -4637,7 +4636,7 @@ socket_inet_aton(PyObject *self, PyObject *args)
packed_addr = inet_addr(ip_addr); packed_addr = inet_addr(ip_addr);
if (packed_addr == INADDR_NONE) { /* invalid address */ if (packed_addr == INADDR_NONE) { /* invalid address */
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"illegal IP address string passed to inet_aton"); "illegal IP address string passed to inet_aton");
return NULL; return NULL;
} }
@ -4669,7 +4668,7 @@ socket_inet_ntoa(PyObject *self, PyObject *args)
} }
if (addr_len != sizeof(packed_addr)) { if (addr_len != sizeof(packed_addr)) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"packed IP wrong length for inet_ntoa"); "packed IP wrong length for inet_ntoa");
return NULL; return NULL;
} }
@ -4704,7 +4703,7 @@ socket_inet_pton(PyObject *self, PyObject *args)
#if !defined(ENABLE_IPV6) && defined(AF_INET6) #if !defined(ENABLE_IPV6) && defined(AF_INET6)
if(af == AF_INET6) { if(af == AF_INET6) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"can't use AF_INET6, IPv6 is disabled"); "can't use AF_INET6, IPv6 is disabled");
return NULL; return NULL;
} }
@ -4712,10 +4711,10 @@ socket_inet_pton(PyObject *self, PyObject *args)
retval = inet_pton(af, ip, packed); retval = inet_pton(af, ip, packed);
if (retval < 0) { if (retval < 0) {
PyErr_SetFromErrno(socket_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} else if (retval == 0) { } else if (retval == 0) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"illegal IP address string passed to inet_pton"); "illegal IP address string passed to inet_pton");
return NULL; return NULL;
} else if (af == AF_INET) { } else if (af == AF_INET) {
@ -4727,7 +4726,7 @@ socket_inet_pton(PyObject *self, PyObject *args)
sizeof(struct in6_addr)); sizeof(struct in6_addr));
#endif #endif
} else { } else {
PyErr_SetString(socket_error, "unknown address family"); PyErr_SetString(PyExc_OSError, "unknown address family");
return NULL; return NULL;
} }
} }
@ -4779,7 +4778,7 @@ socket_inet_ntop(PyObject *self, PyObject *args)
retval = inet_ntop(af, packed, ip, sizeof(ip)); retval = inet_ntop(af, packed, ip, sizeof(ip));
if (!retval) { if (!retval) {
PyErr_SetFromErrno(socket_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} else { } else {
return PyUnicode_FromString(retval); return PyUnicode_FromString(retval);
@ -4850,7 +4849,7 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
} else if (pobj == Py_None) { } else if (pobj == Py_None) {
pptr = (char *)NULL; pptr = (char *)NULL;
} else { } else {
PyErr_SetString(socket_error, "Int or String expected"); PyErr_SetString(PyExc_OSError, "Int or String expected");
goto err; goto err;
} }
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
@ -4947,7 +4946,7 @@ socket_getnameinfo(PyObject *self, PyObject *args)
goto fail; goto fail;
} }
if (res->ai_next) { if (res->ai_next) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"sockaddr resolved to multiple addresses"); "sockaddr resolved to multiple addresses");
goto fail; goto fail;
} }
@ -4955,7 +4954,7 @@ socket_getnameinfo(PyObject *self, PyObject *args)
case AF_INET: case AF_INET:
{ {
if (PyTuple_GET_SIZE(sa) != 2) { if (PyTuple_GET_SIZE(sa) != 2) {
PyErr_SetString(socket_error, PyErr_SetString(PyExc_OSError,
"IPv4 sockaddr must be 2 tuple"); "IPv4 sockaddr must be 2 tuple");
goto fail; goto fail;
} }
@ -5054,7 +5053,7 @@ socket_if_nameindex(PyObject *self, PyObject *arg)
ni = if_nameindex(); ni = if_nameindex();
if (ni == NULL) { if (ni == NULL) {
PyErr_SetFromErrno(socket_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
@ -5100,7 +5099,7 @@ socket_if_nametoindex(PyObject *self, PyObject *args)
Py_DECREF(oname); Py_DECREF(oname);
if (index == 0) { if (index == 0) {
/* if_nametoindex() doesn't set errno */ /* if_nametoindex() doesn't set errno */
PyErr_SetString(socket_error, "no interface with this name"); PyErr_SetString(PyExc_OSError, "no interface with this name");
return NULL; return NULL;
} }
@ -5123,7 +5122,7 @@ socket_if_indextoname(PyObject *self, PyObject *arg)
return NULL; return NULL;
if (if_indextoname(index, name) == NULL) { if (if_indextoname(index, name) == NULL) {
PyErr_SetFromErrno(socket_error); PyErr_SetFromErrno(PyExc_OSError);
return NULL; return NULL;
} }
@ -5403,27 +5402,24 @@ PyInit__socket(void)
if (m == NULL) if (m == NULL)
return NULL; return NULL;
socket_error = PyErr_NewException("socket.error", Py_INCREF(PyExc_OSError);
PyExc_IOError, NULL); PySocketModuleAPI.error = PyExc_OSError;
if (socket_error == NULL) Py_INCREF(PyExc_OSError);
return NULL; PyModule_AddObject(m, "error", PyExc_OSError);
PySocketModuleAPI.error = socket_error;
Py_INCREF(socket_error);
PyModule_AddObject(m, "error", socket_error);
socket_herror = PyErr_NewException("socket.herror", socket_herror = PyErr_NewException("socket.herror",
socket_error, NULL); PyExc_OSError, NULL);
if (socket_herror == NULL) if (socket_herror == NULL)
return NULL; return NULL;
Py_INCREF(socket_herror); Py_INCREF(socket_herror);
PyModule_AddObject(m, "herror", socket_herror); PyModule_AddObject(m, "herror", socket_herror);
socket_gaierror = PyErr_NewException("socket.gaierror", socket_error, socket_gaierror = PyErr_NewException("socket.gaierror", PyExc_OSError,
NULL); NULL);
if (socket_gaierror == NULL) if (socket_gaierror == NULL)
return NULL; return NULL;
Py_INCREF(socket_gaierror); Py_INCREF(socket_gaierror);
PyModule_AddObject(m, "gaierror", socket_gaierror); PyModule_AddObject(m, "gaierror", socket_gaierror);
socket_timeout = PyErr_NewException("socket.timeout", socket_timeout = PyErr_NewException("socket.timeout",
socket_error, NULL); PyExc_OSError, NULL);
if (socket_timeout == NULL) if (socket_timeout == NULL)
return NULL; return NULL;
PySocketModuleAPI.timeout_error = socket_timeout; PySocketModuleAPI.timeout_error = socket_timeout;

View file

@ -10,6 +10,20 @@
#include "osdefs.h" #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 /* NOTE: If the exception class hierarchy changes, don't forget to update
* Lib/test/exception_hierarchy.txt * Lib/test/exception_hierarchy.txt
*/ */
@ -433,11 +447,13 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \
0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ 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 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 = { \ static PyTypeObject _PyExc_ ## EXCNAME = { \
PyVarObject_HEAD_INIT(NULL, 0) \ PyVarObject_HEAD_INIT(NULL, 0) \
# EXCNAME, \ # EXCNAME, \
@ -447,9 +463,9 @@ static PyTypeObject _PyExc_ ## EXCNAME = { \
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \
PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \
(inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \ (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \
EXCMEMBERS, 0, &_ ## EXCBASE, \ EXCMEMBERS, EXCGETSET, &_ ## EXCBASE, \
0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ 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 PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME
@ -534,7 +550,7 @@ static PyMemberDef SystemExit_members[] = {
}; };
ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit,
SystemExit_dealloc, 0, SystemExit_members, 0, 0, 0, SystemExit_members, 0, 0,
"Request to exit from the interpreter."); "Request to exit from the interpreter.");
/* /*
@ -552,124 +568,233 @@ SimpleExtendsException(PyExc_Exception, ImportError,
/* /*
* 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 /* Where a function has a single filename, such as open() or some
* of the os module functions, PyErr_SetFromErrnoWithFilename() is * of the os module functions, PyErr_SetFromErrnoWithFilename() is
* called, giving a third argument which is the filename. But, so * called, giving a third argument which is the filename. But, so
* that old code using in-place unpacking doesn't break, e.g.: * 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 * we hack args so that it only contains two items. This also
* means we need our own __str__() which prints out the filename * means we need our own __str__() which prints out the filename
* when it was supplied. * when it was supplied.
*/ */
static int
EnvironmentError_init(PyEnvironmentErrorObject *self, PyObject *args, static PyObject *
PyObject *kwds) OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
PyOSErrorObject *self = NULL;
Py_ssize_t nargs;
PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL; PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL;
PyObject *subslice = NULL; PyObject *subslice = NULL;
#ifdef MS_WINDOWS
PyObject *winerror = NULL;
long winerrcode = 0;
#endif
if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) if (!_PyArg_NoKeywords(type->tp_name, kwds))
return -1; return NULL;
Py_INCREF(args);
nargs = PyTuple_GET_SIZE(args);
if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3) { #ifdef MS_WINDOWS
return 0; if (nargs >= 2 && nargs <= 4) {
if (!PyArg_UnpackTuple(args, "OSError", 2, 4,
&myerrno, &strerror, &filename, &winerror))
goto error;
if (winerror && PyLong_Check(winerror)) {
long errcode;
PyObject *newargs;
Py_ssize_t i;
winerrcode = PyLong_AsLong(winerror);
if (winerrcode == -1 && PyErr_Occurred())
goto error;
/* 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)
goto error;
newargs = PyTuple_New(nargs);
if (!newargs)
goto error;
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 = newargs;
}
}
#else
if (nargs >= 2 && nargs <= 3) {
if (!PyArg_UnpackTuple(args, "OSError", 2, 3,
&myerrno, &strerror, &filename))
goto error;
}
#endif
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;
} }
if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, self = (PyOSErrorObject *) type->tp_alloc(type, 0);
&myerrno, &strerror, &filename)) { if (!self)
return -1; goto error;
}
Py_CLEAR(self->myerrno); /* replacing */
self->myerrno = myerrno;
Py_INCREF(self->myerrno);
Py_CLEAR(self->strerror); /* replacing */ self->dict = NULL;
self->strerror = strerror; self->traceback = self->cause = self->context = NULL;
Py_INCREF(self->strerror); self->written = -1;
/* self->filename will remain Py_None otherwise */ /* self->filename will remain Py_None otherwise */
if (filename != NULL) { if (filename && filename != Py_None) {
Py_CLEAR(self->filename); /* replacing */ if ((PyObject *) type == PyExc_BlockingIOError &&
self->filename = filename; PyNumber_Check(filename)) {
Py_INCREF(self->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())
goto error;
}
else {
Py_INCREF(filename);
self->filename = filename;
subslice = PyTuple_GetSlice(args, 0, 2); if (nargs >= 2 && nargs <= 3) {
if (!subslice) /* filename is removed from the args tuple (for compatibility
return -1; purposes, see test_exceptions.py) */
subslice = PyTuple_GetSlice(args, 0, 2);
if (!subslice)
goto error;
Py_DECREF(self->args); /* replacing args */ Py_DECREF(args); /* replacing args */
self->args = subslice; args = subslice;
}
}
} }
/* Steals the reference to args */
self->args = args;
args = NULL;
Py_XINCREF(myerrno);
self->myerrno = myerrno;
Py_XINCREF(strerror);
self->strerror = strerror;
#ifdef MS_WINDOWS
Py_XINCREF(winerror);
self->winerror = winerror;
#endif
return (PyObject *) self;
error:
Py_XDECREF(args);
Py_XDECREF(self);
return NULL;
}
static int
OSError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds)
{
/* Everything already done in OSError_new */
return 0; return 0;
} }
static int static int
EnvironmentError_clear(PyEnvironmentErrorObject *self) OSError_clear(PyOSErrorObject *self)
{ {
Py_CLEAR(self->myerrno); Py_CLEAR(self->myerrno);
Py_CLEAR(self->strerror); Py_CLEAR(self->strerror);
Py_CLEAR(self->filename); Py_CLEAR(self->filename);
#ifdef MS_WINDOWS
Py_CLEAR(self->winerror);
#endif
return BaseException_clear((PyBaseExceptionObject *)self); return BaseException_clear((PyBaseExceptionObject *)self);
} }
static void static void
EnvironmentError_dealloc(PyEnvironmentErrorObject *self) OSError_dealloc(PyOSErrorObject *self)
{ {
_PyObject_GC_UNTRACK(self); _PyObject_GC_UNTRACK(self);
EnvironmentError_clear(self); OSError_clear(self);
Py_TYPE(self)->tp_free((PyObject *)self); Py_TYPE(self)->tp_free((PyObject *)self);
} }
static int static int
EnvironmentError_traverse(PyEnvironmentErrorObject *self, visitproc visit, OSError_traverse(PyOSErrorObject *self, visitproc visit,
void *arg) void *arg)
{ {
Py_VISIT(self->myerrno); Py_VISIT(self->myerrno);
Py_VISIT(self->strerror); Py_VISIT(self->strerror);
Py_VISIT(self->filename); Py_VISIT(self->filename);
#ifdef MS_WINDOWS
Py_VISIT(self->winerror);
#endif
return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg);
} }
static PyObject * 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) if (self->filename)
return PyUnicode_FromFormat("[Errno %S] %S: %R", return PyUnicode_FromFormat("[Errno %S] %S: %R",
self->myerrno ? self->myerrno: Py_None, self->myerrno ? self->myerrno: Py_None,
self->strerror ? self->strerror: Py_None, self->strerror ? self->strerror: Py_None,
self->filename); self->filename);
else if (self->myerrno && self->strerror) if (self->myerrno && self->strerror)
return PyUnicode_FromFormat("[Errno %S] %S", return PyUnicode_FromFormat("[Errno %S] %S",
self->myerrno ? self->myerrno: Py_None, self->myerrno ? self->myerrno: Py_None,
self->strerror ? self->strerror: 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 * static PyObject *
EnvironmentError_reduce(PyEnvironmentErrorObject *self) OSError_reduce(PyOSErrorObject *self)
{ {
PyObject *args = self->args; PyObject *args = self->args;
PyObject *res = NULL, *tmp; PyObject *res = NULL, *tmp;
/* self->args is only the first two real arguments if there was a /* 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) { if (PyTuple_GET_SIZE(args) == 2 && self->filename) {
args = PyTuple_New(3); args = PyTuple_New(3);
if (!args) return NULL; if (!args) return NULL;
@ -695,144 +820,93 @@ EnvironmentError_reduce(PyEnvironmentErrorObject *self)
return res; return res;
} }
static PyObject *
OSError_written_get(PyOSErrorObject *self, void *context)
{
if (self->written == -1) {
PyErr_SetString(PyExc_AttributeError, "characters_written");
return NULL;
}
return PyLong_FromSsize_t(self->written);
}
static PyMethodDef EnvironmentError_methods[] = { static int
{"__reduce__", (PyCFunction)EnvironmentError_reduce, METH_NOARGS}, OSError_written_set(PyOSErrorObject *self, PyObject *arg, void *context)
{
Py_ssize_t n;
n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
if (n == -1 && PyErr_Occurred())
return -1;
self->written = n;
return 0;
}
static PyMemberDef OSError_members[] = {
{"errno", T_OBJECT, offsetof(PyOSErrorObject, myerrno), 0,
PyDoc_STR("POSIX exception code")},
{"strerror", T_OBJECT, offsetof(PyOSErrorObject, strerror), 0,
PyDoc_STR("exception strerror")},
{"filename", T_OBJECT, offsetof(PyOSErrorObject, filename), 0,
PyDoc_STR("exception filename")},
#ifdef MS_WINDOWS
{"winerror", T_OBJECT, offsetof(PyOSErrorObject, winerror), 0,
PyDoc_STR("Win32 exception code")},
#endif
{NULL} /* Sentinel */
};
static PyMethodDef OSError_methods[] = {
{"__reduce__", (PyCFunction)OSError_reduce, METH_NOARGS},
{NULL} {NULL}
}; };
ComplexExtendsException(PyExc_Exception, EnvironmentError, static PyGetSetDef OSError_getset[] = {
EnvironmentError, EnvironmentError_dealloc, {"characters_written", (getter) OSError_written_get,
EnvironmentError_methods, EnvironmentError_members, (setter) OSError_written_set, NULL},
EnvironmentError_str, {NULL}
};
ComplexExtendsException(PyExc_Exception, OSError,
OSError, OSError_new,
OSError_methods, OSError_members, OSError_getset,
OSError_str,
"Base class for I/O related errors."); "Base class for I/O related errors.");
/* /*
* IOError extends EnvironmentError * Various OSError subclasses
*/ */
MiddlingExtendsException(PyExc_EnvironmentError, IOError, MiddlingExtendsException(PyExc_OSError, BlockingIOError, OSError,
EnvironmentError, "I/O operation failed."); "I/O operation would block.");
MiddlingExtendsException(PyExc_OSError, ConnectionError, OSError,
"Connection error.");
/* MiddlingExtendsException(PyExc_OSError, ChildProcessError, OSError,
* OSError extends EnvironmentError "Child process error.");
*/ MiddlingExtendsException(PyExc_ConnectionError, BrokenPipeError, OSError,
MiddlingExtendsException(PyExc_EnvironmentError, OSError, "Broken pipe.");
EnvironmentError, "OS system call failed."); MiddlingExtendsException(PyExc_ConnectionError, ConnectionAbortedError, OSError,
"Connection aborted.");
MiddlingExtendsException(PyExc_ConnectionError, ConnectionRefusedError, OSError,
/* "Connection refused.");
* WindowsError extends OSError MiddlingExtendsException(PyExc_ConnectionError, ConnectionResetError, OSError,
*/ "Connection reset.");
#ifdef MS_WINDOWS MiddlingExtendsException(PyExc_OSError, FileExistsError, OSError,
#include "errmap.h" "File already exists.");
MiddlingExtendsException(PyExc_OSError, FileNotFoundError, OSError,
static int "File not found.");
WindowsError_clear(PyWindowsErrorObject *self) MiddlingExtendsException(PyExc_OSError, IsADirectoryError, OSError,
{ "Operation doesn't work on directories.");
Py_CLEAR(self->myerrno); MiddlingExtendsException(PyExc_OSError, NotADirectoryError, OSError,
Py_CLEAR(self->strerror); "Operation only works on directories.");
Py_CLEAR(self->filename); MiddlingExtendsException(PyExc_OSError, InterruptedError, OSError,
Py_CLEAR(self->winerror); "Interrupted by signal.");
return BaseException_clear((PyBaseExceptionObject *)self); MiddlingExtendsException(PyExc_OSError, PermissionError, OSError,
} "Not enough permissions.");
MiddlingExtendsException(PyExc_OSError, ProcessLookupError, OSError,
static void "Process not found.");
WindowsError_dealloc(PyWindowsErrorObject *self) MiddlingExtendsException(PyExc_OSError, TimeoutError, OSError,
{ "Timeout expired.");
_PyObject_GC_UNTRACK(self);
WindowsError_clear(self);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static int
WindowsError_traverse(PyWindowsErrorObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->myerrno);
Py_VISIT(self->strerror);
Py_VISIT(self->filename);
Py_VISIT(self->winerror);
return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg);
}
static int
WindowsError_init(PyWindowsErrorObject *self, PyObject *args, PyObject *kwds)
{
PyObject *o_errcode = NULL;
long errcode;
long posix_errno;
if (EnvironmentError_init((PyEnvironmentErrorObject *)self, args, kwds)
== -1)
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;
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,
PyDoc_STR("POSIX exception code")},
{"strerror", T_OBJECT, offsetof(PyWindowsErrorObject, strerror), 0,
PyDoc_STR("exception strerror")},
{"filename", T_OBJECT, offsetof(PyWindowsErrorObject, filename), 0,
PyDoc_STR("exception filename")},
{"winerror", T_OBJECT, offsetof(PyWindowsErrorObject, winerror), 0,
PyDoc_STR("Win32 exception code")},
{NULL} /* Sentinel */
};
ComplexExtendsException(PyExc_OSError, WindowsError, WindowsError,
WindowsError_dealloc, 0, WindowsError_members,
WindowsError_str, "MS-Windows OS system call failed.");
#endif /* MS_WINDOWS */
/*
* VMSError extends OSError (I think)
*/
#ifdef __VMS
MiddlingExtendsException(PyExc_OSError, VMSError, EnvironmentError,
"OpenVMS OS system call failed.");
#endif
/* /*
* EOFError extends Exception * EOFError extends Exception
@ -1046,7 +1120,7 @@ static PyMemberDef SyntaxError_members[] = {
}; };
ComplexExtendsException(PyExc_Exception, SyntaxError, SyntaxError, ComplexExtendsException(PyExc_Exception, SyntaxError, SyntaxError,
SyntaxError_dealloc, 0, SyntaxError_members, 0, 0, SyntaxError_members, 0,
SyntaxError_str, "Invalid syntax."); SyntaxError_str, "Invalid syntax.");
@ -1100,7 +1174,7 @@ KeyError_str(PyBaseExceptionObject *self)
} }
ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, ComplexExtendsException(PyExc_LookupError, KeyError, BaseException,
0, 0, 0, KeyError_str, "Mapping key not found."); 0, 0, 0, 0, KeyError_str, "Mapping key not found.");
/* /*
@ -1977,6 +2051,45 @@ PyObject *PyExc_RecursionErrorInst = NULL;
if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \ if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \
Py_FatalError("Module dictionary insertion problem."); Py_FatalError("Module dictionary insertion problem.");
#define INIT_ALIAS(NAME, TYPE) Py_INCREF(PyExc_ ## TYPE); \
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."); \
}
#ifdef MS_WINDOWS
#include <Winsock2.h>
#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 void
_PyExc_Init(void) _PyExc_Init(void)
@ -1991,15 +2104,7 @@ _PyExc_Init(void)
PRE_INIT(SystemExit) PRE_INIT(SystemExit)
PRE_INIT(KeyboardInterrupt) PRE_INIT(KeyboardInterrupt)
PRE_INIT(ImportError) PRE_INIT(ImportError)
PRE_INIT(EnvironmentError)
PRE_INIT(IOError)
PRE_INIT(OSError) PRE_INIT(OSError)
#ifdef MS_WINDOWS
PRE_INIT(WindowsError)
#endif
#ifdef __VMS
PRE_INIT(VMSError)
#endif
PRE_INIT(EOFError) PRE_INIT(EOFError)
PRE_INIT(RuntimeError) PRE_INIT(RuntimeError)
PRE_INIT(NotImplementedError) PRE_INIT(NotImplementedError)
@ -2039,6 +2144,24 @@ _PyExc_Init(void)
PRE_INIT(BytesWarning) PRE_INIT(BytesWarning)
PRE_INIT(ResourceWarning) PRE_INIT(ResourceWarning)
/* 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);
bltinmod = PyImport_ImportModule("builtins"); bltinmod = PyImport_ImportModule("builtins");
if (bltinmod == NULL) if (bltinmod == NULL)
Py_FatalError("exceptions bootstrapping error."); Py_FatalError("exceptions bootstrapping error.");
@ -2054,14 +2177,14 @@ _PyExc_Init(void)
POST_INIT(SystemExit) POST_INIT(SystemExit)
POST_INIT(KeyboardInterrupt) POST_INIT(KeyboardInterrupt)
POST_INIT(ImportError) POST_INIT(ImportError)
POST_INIT(EnvironmentError)
POST_INIT(IOError)
POST_INIT(OSError) POST_INIT(OSError)
INIT_ALIAS(EnvironmentError, OSError)
INIT_ALIAS(IOError, OSError)
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
POST_INIT(WindowsError) INIT_ALIAS(WindowsError, OSError)
#endif #endif
#ifdef __VMS #ifdef __VMS
POST_INIT(VMSError) INIT_ALIAS(VMSError, OSError)
#endif #endif
POST_INIT(EOFError) POST_INIT(EOFError)
POST_INIT(RuntimeError) POST_INIT(RuntimeError)
@ -2102,6 +2225,47 @@ _PyExc_Init(void)
POST_INIT(BytesWarning) POST_INIT(BytesWarning)
POST_INIT(ResourceWarning) POST_INIT(ResourceWarning)
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(); preallocate_memerrors();
PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL); PyExc_RecursionErrorInst = BaseException_new(&_PyExc_RuntimeError, NULL, NULL);
@ -2135,4 +2299,5 @@ _PyExc_Fini(void)
{ {
Py_CLEAR(PyExc_RecursionErrorInst); Py_CLEAR(PyExc_RecursionErrorInst);
free_preallocated_memerrors(); free_preallocated_memerrors();
Py_CLEAR(errnomap);
} }

View file

@ -496,10 +496,11 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
return NULL; return NULL;
} }
if (filenameObject != NULL) if (filenameObject == NULL)
v = Py_BuildValue("(iOO)", err, message, filenameObject); filenameObject = Py_None;
else /* This is the constructor signature for passing a Windows error code.
v = Py_BuildValue("(iO)", err, message); The POSIX translation will be figured out by the constructor. */
v = Py_BuildValue("(iOOi)", 0, message, filenameObject, err);
Py_DECREF(message); Py_DECREF(message);
if (v != NULL) { if (v != NULL) {