Issue #23391: Restore OSError constructor argument documentation

This restores details lost in revision 097f4fda61a4 (since Python 3.3,
related to the new OSError subclasses). Further additions:

* Markup for attributes and constructor signature
* Explain "winerror" and "filename2"
* Extend test to check for filename2 defaulting to None
* Clarify that the constructor can return a subclass

I have intentionally left out any details of allowing more than five
arguments, or how the "args" attribute is set for four or more arguments.
These details seem to be dependent on the Python version and platform.
This commit is contained in:
Martin Panter 2015-10-26 11:05:42 +00:00
parent f085a16f55
commit 5487c13e44
2 changed files with 60 additions and 26 deletions

View File

@ -231,44 +231,71 @@ The following exceptions are the exceptions that are usually raised.
classes to override the method. classes to override the method.
.. exception:: OSError .. exception:: OSError([arg])
OSError(errno, strerror[, filename[, winerror[, filename2]]])
.. index:: module: errno .. index:: module: errno
This exception is raised when a system function returns a system-related This exception is raised when a system function returns a system-related
error, including I/O failures such as "file not found" or "disk full" error, including I/O failures such as "file not found" or "disk full"
(not for illegal argument types or other incidental errors). Often a (not for illegal argument types or other incidental errors).
subclass of :exc:`OSError` will actually be raised as described in
`OS exceptions`_ below. The :attr:`errno` attribute is a numeric error
code from the C variable :c:data:`errno`.
Under Windows, the :attr:`winerror` attribute gives you the native The second form of the constructor sets the corresponding attributes,
Windows error code. The :attr:`errno` attribute is then an approximate described below. The attributes default to :const:`None` if not
translation, in POSIX terms, of that native error code. specified. For backwards compatibility, if three arguments are passed,
the :attr:`~BaseException.args` attribute contains only a 2-tuple
of the first two constructor arguments.
Under all platforms, the :attr:`strerror` attribute is the corresponding The constructor often actually returns a subclass of :exc:`OSError`, as
error message as provided by the operating system (as formatted by the C described in `OS exceptions`_ below. The particular subclass depends on
functions :c:func:`perror` under POSIX, and :c:func:`FormatMessage` the final :attr:`.errno` value. This behaviour only occurs when
Windows). constructing :exc:`OSError` directly or via an alias, and is not
inherited when subclassing.
For exceptions that involve a file system path (such as :func:`open` or .. attribute:: errno
:func:`os.unlink`), the exception instance will contain an additional
attribute, :attr:`filename`, which is the file name passed to the function. A numeric error code from the C variable :c:data:`errno`.
For functions that involve two file system paths (such as
:func:`os.rename`), the exception instance will contain a second .. attribute:: winerror
:attr:`filename2` attribute corresponding to the second file name passed
to the function. Under Windows, this gives you the native
Windows error code. The :attr:`.errno` attribute is then an approximate
translation, in POSIX terms, of that native error code.
Under Windows, if the *winerror* constructor argument is an integer,
the :attr:`.errno` attribute is determined from the Windows error code,
and the *errno* argument is ignored. On other platforms, the
*winerror* argument is ignored, and the :attr:`winerror` attribute
does not exist.
.. attribute:: strerror
The corresponding error message, as provided by
the operating system. It is formatted by the C
functions :c:func:`perror` under POSIX, and :c:func:`FormatMessage`
under Windows.
.. attribute:: filename
filename2
For exceptions that involve a file system path (such as :func:`open` or
:func:`os.unlink`), :attr:`filename` is the file name passed to the function.
For functions that involve two file system paths (such as
:func:`os.rename`), :attr:`filename2` corresponds to the second
file name passed to the function.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
:exc:`EnvironmentError`, :exc:`IOError`, :exc:`WindowsError`, :exc:`EnvironmentError`, :exc:`IOError`, :exc:`WindowsError`,
:exc:`VMSError`, :exc:`socket.error`, :exc:`select.error` and :exc:`VMSError`, :exc:`socket.error`, :exc:`select.error` and
:exc:`mmap.error` have been merged into :exc:`OSError`. :exc:`mmap.error` have been merged into :exc:`OSError`, and the
constructor may return a subclass.
.. versionchanged:: 3.4 .. versionchanged:: 3.4
The :attr:`filename` attribute is now the original file name passed to The :attr:`filename` attribute is now the original file name passed to
the function, instead of the name encoded to or decoded from the the function, instead of the name encoded to or decoded from the
filesystem encoding. Also, the :attr:`filename2` attribute was added. filesystem encoding. Also, the *filename2* constructor argument and
attribute was added.
.. exception:: OverflowError .. exception:: OverflowError

View File

@ -230,6 +230,7 @@ class ExceptionTests(unittest.TestCase):
self.assertEqual(w.winerror, 3) self.assertEqual(w.winerror, 3)
self.assertEqual(w.strerror, 'foo') self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, 'bar') self.assertEqual(w.filename, 'bar')
self.assertEqual(w.filename2, None)
self.assertEqual(str(w), "[WinError 3] foo: 'bar'") self.assertEqual(str(w), "[WinError 3] foo: 'bar'")
# Unknown win error becomes EINVAL (22) # Unknown win error becomes EINVAL (22)
w = OSError(0, 'foo', None, 1001) w = OSError(0, 'foo', None, 1001)
@ -237,6 +238,7 @@ class ExceptionTests(unittest.TestCase):
self.assertEqual(w.winerror, 1001) self.assertEqual(w.winerror, 1001)
self.assertEqual(w.strerror, 'foo') self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, None) self.assertEqual(w.filename, None)
self.assertEqual(w.filename2, None)
self.assertEqual(str(w), "[WinError 1001] foo") self.assertEqual(str(w), "[WinError 1001] foo")
# Non-numeric "errno" # Non-numeric "errno"
w = OSError('bar', 'foo') w = OSError('bar', 'foo')
@ -244,6 +246,7 @@ class ExceptionTests(unittest.TestCase):
self.assertEqual(w.winerror, None) self.assertEqual(w.winerror, None)
self.assertEqual(w.strerror, 'foo') self.assertEqual(w.strerror, 'foo')
self.assertEqual(w.filename, None) self.assertEqual(w.filename, None)
self.assertEqual(w.filename2, None)
@unittest.skipUnless(sys.platform == 'win32', @unittest.skipUnless(sys.platform == 'win32',
'test specific to Windows') 'test specific to Windows')
@ -268,13 +271,15 @@ class ExceptionTests(unittest.TestCase):
(SystemExit, ('foo',), (SystemExit, ('foo',),
{'args' : ('foo',), 'code' : 'foo'}), {'args' : ('foo',), 'code' : 'foo'}),
(OSError, ('foo',), (OSError, ('foo',),
{'args' : ('foo',), 'filename' : None, {'args' : ('foo',), 'filename' : None, 'filename2' : None,
'errno' : None, 'strerror' : None}), 'errno' : None, 'strerror' : None}),
(OSError, ('foo', 'bar'), (OSError, ('foo', 'bar'),
{'args' : ('foo', 'bar'), 'filename' : None, {'args' : ('foo', 'bar'),
'filename' : None, 'filename2' : None,
'errno' : 'foo', 'strerror' : 'bar'}), 'errno' : 'foo', 'strerror' : 'bar'}),
(OSError, ('foo', 'bar', 'baz'), (OSError, ('foo', 'bar', 'baz'),
{'args' : ('foo', 'bar'), 'filename' : 'baz', {'args' : ('foo', 'bar'),
'filename' : 'baz', 'filename2' : None,
'errno' : 'foo', 'strerror' : 'bar'}), 'errno' : 'foo', 'strerror' : 'bar'}),
(OSError, ('foo', 'bar', 'baz', None, 'quux'), (OSError, ('foo', 'bar', 'baz', None, 'quux'),
{'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}), {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
@ -284,7 +289,8 @@ class ExceptionTests(unittest.TestCase):
'filename' : 'filenameStr'}), 'filename' : 'filenameStr'}),
(OSError, (1, 'strErrorStr', 'filenameStr'), (OSError, (1, 'strErrorStr', 'filenameStr'),
{'args' : (1, 'strErrorStr'), 'errno' : 1, {'args' : (1, 'strErrorStr'), 'errno' : 1,
'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}), 'strerror' : 'strErrorStr',
'filename' : 'filenameStr', 'filename2' : None}),
(SyntaxError, (), {'msg' : None, 'text' : None, (SyntaxError, (), {'msg' : None, 'text' : None,
'filename' : None, 'lineno' : None, 'offset' : None, 'filename' : None, 'lineno' : None, 'offset' : None,
'print_file_and_line' : None}), 'print_file_and_line' : None}),
@ -340,7 +346,8 @@ class ExceptionTests(unittest.TestCase):
(WindowsError, (1, 'strErrorStr', 'filenameStr'), (WindowsError, (1, 'strErrorStr', 'filenameStr'),
{'args' : (1, 'strErrorStr'), {'args' : (1, 'strErrorStr'),
'strerror' : 'strErrorStr', 'winerror' : None, 'strerror' : 'strErrorStr', 'winerror' : None,
'errno' : 1, 'filename' : 'filenameStr'}) 'errno' : 1,
'filename' : 'filenameStr', 'filename2' : None})
) )
except NameError: except NameError:
pass pass