From 5487c13e44ec851023383edda6e33458aaa1310f Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Mon, 26 Oct 2015 11:05:42 +0000 Subject: [PATCH] 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. --- Doc/library/exceptions.rst | 69 ++++++++++++++++++++++++++----------- Lib/test/test_exceptions.py | 17 ++++++--- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst index e9cab386bb7..ef39e6c6f0a 100644 --- a/Doc/library/exceptions.rst +++ b/Doc/library/exceptions.rst @@ -231,44 +231,71 @@ The following exceptions are the exceptions that are usually raised. classes to override the method. -.. exception:: OSError +.. exception:: OSError([arg]) + OSError(errno, strerror[, filename[, winerror[, filename2]]]) .. index:: module: errno 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" - (not for illegal argument types or other incidental errors). Often a - 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`. + (not for illegal argument types or other incidental errors). - Under Windows, the :attr:`winerror` attribute gives you the native - Windows error code. The :attr:`errno` attribute is then an approximate - translation, in POSIX terms, of that native error code. + The second form of the constructor sets the corresponding attributes, + described below. The attributes default to :const:`None` if not + 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 - error message as provided by the operating system (as formatted by the C - functions :c:func:`perror` under POSIX, and :c:func:`FormatMessage` - Windows). + The constructor often actually returns a subclass of :exc:`OSError`, as + described in `OS exceptions`_ below. The particular subclass depends on + the final :attr:`.errno` value. This behaviour only occurs when + 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 - :func:`os.unlink`), the exception instance will contain an additional - attribute, :attr:`filename`, which is the file name passed to the function. - For functions that involve two file system paths (such as - :func:`os.rename`), the exception instance will contain a second - :attr:`filename2` attribute corresponding to the second file name passed - to the function. + .. attribute:: errno + + A numeric error code from the C variable :c:data:`errno`. + + .. attribute:: winerror + + 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 :exc:`EnvironmentError`, :exc:`IOError`, :exc:`WindowsError`, :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 The :attr:`filename` attribute is now the original file name passed to 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 diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 80d4f1aeb5a..d9543028bb9 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -230,6 +230,7 @@ class ExceptionTests(unittest.TestCase): self.assertEqual(w.winerror, 3) self.assertEqual(w.strerror, 'foo') self.assertEqual(w.filename, 'bar') + self.assertEqual(w.filename2, None) self.assertEqual(str(w), "[WinError 3] foo: 'bar'") # Unknown win error becomes EINVAL (22) w = OSError(0, 'foo', None, 1001) @@ -237,6 +238,7 @@ class ExceptionTests(unittest.TestCase): self.assertEqual(w.winerror, 1001) self.assertEqual(w.strerror, 'foo') self.assertEqual(w.filename, None) + self.assertEqual(w.filename2, None) self.assertEqual(str(w), "[WinError 1001] foo") # Non-numeric "errno" w = OSError('bar', 'foo') @@ -244,6 +246,7 @@ class ExceptionTests(unittest.TestCase): self.assertEqual(w.winerror, None) self.assertEqual(w.strerror, 'foo') self.assertEqual(w.filename, None) + self.assertEqual(w.filename2, None) @unittest.skipUnless(sys.platform == 'win32', 'test specific to Windows') @@ -268,13 +271,15 @@ class ExceptionTests(unittest.TestCase): (SystemExit, ('foo',), {'args' : ('foo',), 'code' : 'foo'}), (OSError, ('foo',), - {'args' : ('foo',), 'filename' : None, + {'args' : ('foo',), 'filename' : None, 'filename2' : None, 'errno' : None, 'strerror' : None}), (OSError, ('foo', 'bar'), - {'args' : ('foo', 'bar'), 'filename' : None, + {'args' : ('foo', 'bar'), + 'filename' : None, 'filename2' : None, 'errno' : 'foo', 'strerror' : 'bar'}), (OSError, ('foo', 'bar', 'baz'), - {'args' : ('foo', 'bar'), 'filename' : 'baz', + {'args' : ('foo', 'bar'), + 'filename' : 'baz', 'filename2' : None, 'errno' : 'foo', 'strerror' : 'bar'}), (OSError, ('foo', 'bar', 'baz', None, 'quux'), {'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}), @@ -284,7 +289,8 @@ class ExceptionTests(unittest.TestCase): 'filename' : 'filenameStr'}), (OSError, (1, 'strErrorStr', 'filenameStr'), {'args' : (1, 'strErrorStr'), 'errno' : 1, - 'strerror' : 'strErrorStr', 'filename' : 'filenameStr'}), + 'strerror' : 'strErrorStr', + 'filename' : 'filenameStr', 'filename2' : None}), (SyntaxError, (), {'msg' : None, 'text' : None, 'filename' : None, 'lineno' : None, 'offset' : None, 'print_file_and_line' : None}), @@ -340,7 +346,8 @@ class ExceptionTests(unittest.TestCase): (WindowsError, (1, 'strErrorStr', 'filenameStr'), {'args' : (1, 'strErrorStr'), 'strerror' : 'strErrorStr', 'winerror' : None, - 'errno' : 1, 'filename' : 'filenameStr'}) + 'errno' : 1, + 'filename' : 'filenameStr', 'filename2' : None}) ) except NameError: pass