Issue #20517: Functions in the os module that accept two filenames
now register both filenames in the exception on failure. This required adding new C API functions allowing OSError exceptions to reference two filenames instead of one.
This commit is contained in:
parent
dc62b7e261
commit
b082731fbb
|
@ -241,6 +241,15 @@ in various ways. There is a separate error indicator for each thread.
|
|||
exception instance.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromErrnoWithFilenameObjects(PyObject *type, PyObject *filenameObject, PyObject *filenameObject2)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromErrnoWithFilenameObject`, but takes a second
|
||||
filename object, for raising errors when a function that takes two filenames
|
||||
fails.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromErrnoWithFilename(PyObject *type, const char *filename)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromErrnoWithFilenameObject`, but the filename
|
||||
|
@ -248,6 +257,14 @@ in various ways. There is a separate error indicator for each thread.
|
|||
(:func:`os.fsdecode`).
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromErrnoWithFilenames(PyObject *type, const char *filename, const char *filename2)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromErrnoWithFilename`, but accepts a
|
||||
second filename.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromWindowsErr(int ierr)
|
||||
|
||||
This is a convenience function to raise :exc:`WindowsError`. If called with
|
||||
|
@ -266,13 +283,6 @@ in various ways. There is a separate error indicator for each thread.
|
|||
specifying the exception type to be raised. Availability: Windows.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilenameObject(int ierr, PyObject *filenameObject)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromWindowsErr`, with the additional behavior
|
||||
that if *filenameObject* is not *NULL*, it is passed to the constructor of
|
||||
:exc:`WindowsError` as a third parameter. Availability: Windows.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilename(int ierr, const char *filename)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, but the
|
||||
|
@ -280,6 +290,14 @@ in various ways. There is a separate error indicator for each thread.
|
|||
encoding (:func:`os.fsdecode`). Availability: Windows.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetFromWindowsErrWithFilenames(int ierr, const char *filename, const char *filename2)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilename`, but accepts
|
||||
a second filename. Availability: Windows.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObject(PyObject *type, int ierr, PyObject *filename)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilenameObject`, with an
|
||||
|
@ -287,12 +305,30 @@ in various ways. There is a separate error indicator for each thread.
|
|||
Availability: Windows.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenameObjects(PyObject *type, int ierr, PyObject *filename, PyObject *filename2)
|
||||
|
||||
Similar to :c:func:`PyErr_SetExcFromWindowsErrWithFilenameObject`,
|
||||
but accepts a second filename object.
|
||||
Availability: Windows.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, const char *filename)
|
||||
|
||||
Similar to :c:func:`PyErr_SetFromWindowsErrWithFilename`, with an additional
|
||||
parameter specifying the exception type to be raised. Availability: Windows.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilenames(PyObject *type, int ierr, const char *filename, const char *filename2)
|
||||
|
||||
Similar to :c:func:`PyErr_SetExcFromWindowsErrWithFilename`,
|
||||
but accepts a second filename object.
|
||||
Availability: Windows.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
|
||||
|
||||
This is a convenience function to raise :exc:`ImportError`. *msg* will be
|
||||
|
|
|
@ -317,6 +317,12 @@ PyErr_SetExcFromWindowsErrWithFilename:PyObject*:type:0:
|
|||
PyErr_SetExcFromWindowsErrWithFilename:int:ierr::
|
||||
PyErr_SetExcFromWindowsErrWithFilename:const char*:filename::
|
||||
|
||||
PyErr_SetExcFromWindowsErrWithFilenames:PyObject*::null:
|
||||
PyErr_SetExcFromWindowsErrWithFilenames:PyObject*:type:0:
|
||||
PyErr_SetExcFromWindowsErrWithFilenames:int:ierr::
|
||||
PyErr_SetExcFromWindowsErrWithFilenames:const char*:filename::
|
||||
PyErr_SetExcFromWindowsErrWithFilenames:const char*:filename2::
|
||||
|
||||
PyErr_SetFromErrno:PyObject*::null:
|
||||
PyErr_SetFromErrno:PyObject*:type:0:
|
||||
|
||||
|
@ -324,6 +330,11 @@ PyErr_SetFromErrnoWithFilename:PyObject*::null:
|
|||
PyErr_SetFromErrnoWithFilename:PyObject*:type:0:
|
||||
PyErr_SetFromErrnoWithFilename:const char*:filename::
|
||||
|
||||
PyErr_SetFromErrnoWithFilenames:PyObject*::null:
|
||||
PyErr_SetFromErrnoWithFilenames:PyObject*:type:0:
|
||||
PyErr_SetFromErrnoWithFilenames:const char*:filename::
|
||||
PyErr_SetFromErrnoWithFilenames:const char*:filename2::
|
||||
|
||||
PyErr_SetFromWindowsErr:PyObject*::null:
|
||||
PyErr_SetFromWindowsErr:int:ierr::
|
||||
|
||||
|
@ -331,6 +342,11 @@ PyErr_SetFromWindowsErrWithFilename:PyObject*::null:
|
|||
PyErr_SetFromWindowsErrWithFilename:int:ierr::
|
||||
PyErr_SetFromWindowsErrWithFilename:const char*:filename::
|
||||
|
||||
PyErr_SetFromWindowsErrWithFilenames:PyObject*::null:
|
||||
PyErr_SetFromWindowsErrWithFilenames:int:ierr::
|
||||
PyErr_SetFromWindowsErrWithFilenames:const char*:filename::
|
||||
PyErr_SetFromWindowsErrWithFilenames:const char*:filename2::
|
||||
|
||||
PyErr_SetInterrupt:void:::
|
||||
|
||||
PyErr_SetNone:void:::
|
||||
|
|
|
@ -253,6 +253,11 @@ The following exceptions are the exceptions that are usually raised.
|
|||
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.
|
||||
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
:exc:`EnvironmentError`, :exc:`IOError`, :exc:`WindowsError`,
|
||||
|
@ -263,7 +268,7 @@ The following exceptions are the exceptions that are usually raised.
|
|||
|
||||
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.
|
||||
filesystem encoding. Also, the :attr:`filename2` attribute was added.
|
||||
|
||||
|
||||
.. exception:: OverflowError
|
||||
|
|
|
@ -53,6 +53,7 @@ typedef struct {
|
|||
PyObject *myerrno;
|
||||
PyObject *strerror;
|
||||
PyObject *filename;
|
||||
PyObject *filename2;
|
||||
#ifdef MS_WINDOWS
|
||||
PyObject *winerror;
|
||||
#endif
|
||||
|
@ -225,13 +226,23 @@ PyAPI_FUNC(PyObject *) PyErr_NoMemory(void);
|
|||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrno(PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObject(
|
||||
PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObjects(
|
||||
PyObject *, PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilename(
|
||||
PyObject *exc,
|
||||
const char *filename /* decoded from the filesystem encoding */
|
||||
);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenames(
|
||||
PyObject *exc,
|
||||
/* decoded from the filesystem encoding */
|
||||
const char *filename,
|
||||
const char *filename2
|
||||
);
|
||||
#if defined(MS_WINDOWS) && !defined(Py_LIMITED_API)
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename(
|
||||
PyObject *, const Py_UNICODE *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilenames(
|
||||
PyObject *, const Py_UNICODE *, const Py_UNICODE *);
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
PyAPI_FUNC(PyObject *) PyErr_Format(
|
||||
|
@ -245,22 +256,41 @@ PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename(
|
|||
int ierr,
|
||||
const char *filename /* decoded from the filesystem encoding */
|
||||
);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilenames(
|
||||
int ierr,
|
||||
/* decoded from the filesystem encoding */
|
||||
const char *filename,
|
||||
const char *filename2
|
||||
);
|
||||
#ifndef Py_LIMITED_API
|
||||
/* XXX redeclare to use WSTRING */
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename(
|
||||
int, const Py_UNICODE *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilenames(
|
||||
int, const Py_UNICODE *, const Py_UNICODE *);
|
||||
#endif
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject(
|
||||
PyObject *,int, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyObject *,int, PyObject *, PyObject *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
const char *filename /* decoded from the filesystem encoding */
|
||||
);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenames(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
/* decoded from the filesystem encoding */
|
||||
const char *filename,
|
||||
const char *filename2
|
||||
);
|
||||
#ifndef Py_LIMITED_API
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename(
|
||||
PyObject *,int, const Py_UNICODE *);
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilenames(
|
||||
PyObject *,int, const Py_UNICODE *, const Py_UNICODE *);
|
||||
#endif
|
||||
PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int);
|
||||
#endif /* MS_WINDOWS */
|
||||
|
|
|
@ -266,8 +266,8 @@ class ExceptionTests(unittest.TestCase):
|
|||
(OSError, ('foo', 'bar', 'baz'),
|
||||
{'args' : ('foo', 'bar'), 'filename' : 'baz',
|
||||
'errno' : 'foo', 'strerror' : 'bar'}),
|
||||
(OSError, ('foo', 'bar', 'baz', 'quux'),
|
||||
{'args' : ('foo', 'bar', 'baz', 'quux')}),
|
||||
(OSError, ('foo', 'bar', 'baz', None, 'quux'),
|
||||
{'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
|
||||
(OSError, ('errnoStr', 'strErrorStr', 'filenameStr'),
|
||||
{'args' : ('errnoStr', 'strErrorStr'),
|
||||
'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
|
||||
|
|
|
@ -1121,6 +1121,23 @@ class PosixTester(unittest.TestCase):
|
|||
# http://lists.freebsd.org/pipermail/freebsd-amd64/2012-January/014332.html
|
||||
raise unittest.SkipTest("OSError raised!")
|
||||
|
||||
def test_path_error2(self):
|
||||
"""
|
||||
Test functions that call path_error2(), providing two filenames in their exceptions.
|
||||
"""
|
||||
for name in ("rename", "replace", "link", "symlink"):
|
||||
function = getattr(os, name, None)
|
||||
|
||||
if function:
|
||||
for dst in ("noodly2", support.TESTFN):
|
||||
try:
|
||||
function('doesnotexistfilename', dst)
|
||||
except OSError as e:
|
||||
self.assertIn("'doesnotexistfilename' -> '{}'".format(dst), str(e))
|
||||
break
|
||||
else:
|
||||
self.fail("No valid path_error2() test for os." + name)
|
||||
|
||||
class PosixGroupsTester(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
12
Misc/NEWS
12
Misc/NEWS
|
@ -32,6 +32,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #20517: Functions in the os module that accept two filenames
|
||||
now register both filenames in the exception on failure.
|
||||
|
||||
- Issue #20563: The ipaddress module API is now considered stable.
|
||||
|
||||
- Issue #14983: email.generator now always adds a line end after each MIME
|
||||
|
@ -236,6 +239,15 @@ Build
|
|||
|
||||
- Issue #20465: Update SQLite shipped with OS X installer to 3.8.3.
|
||||
|
||||
C-API
|
||||
-----
|
||||
|
||||
- Issue #20517: Added new functions allowing OSError exceptions to reference
|
||||
two filenames instead of one: PyErr_SetFromErrnoWithFilenameObjects(),
|
||||
PyErr_SetFromErrnoWithFilenames(), PyErr_SetFromWindowsErrWithFilenames(),
|
||||
PyErr_SetExcFromWindowsErrWithFilenameObjects(), and
|
||||
PyErr_SetExcFromWindowsErrWithFilenames().
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
|
|
|
@ -1313,6 +1313,19 @@ path_error(path_t *path)
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
path_error2(path_t *path, path_t *path2)
|
||||
{
|
||||
#ifdef MS_WINDOWS
|
||||
return PyErr_SetExcFromWindowsErrWithFilenameObjects(PyExc_OSError,
|
||||
0, path->object, path2->object);
|
||||
#else
|
||||
return PyErr_SetFromErrnoWithFilenameObjects(PyExc_OSError,
|
||||
path->object, path2->object);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* POSIX generic methods */
|
||||
|
||||
static PyObject *
|
||||
|
@ -3518,7 +3531,7 @@ posix_link(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
#else
|
||||
|
@ -3536,7 +3549,7 @@ posix_link(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
@ -4284,7 +4297,7 @@ internal_rename(PyObject *args, PyObject *kwargs, int is_replace)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -4299,7 +4312,7 @@ internal_rename(PyObject *args, PyObject *kwargs, int is_replace)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
@ -7345,7 +7358,7 @@ posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (!result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -7361,7 +7374,7 @@ posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
|
|||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (result) {
|
||||
return_value = path_error(&src);
|
||||
return_value = path_error2(&src, &dst);
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -724,13 +724,17 @@ ComplexExtendsException(PyExc_Exception, ImportError,
|
|||
* we hack args so that it only contains two items. This also
|
||||
* means we need our own __str__() which prints out the filename
|
||||
* when it was supplied.
|
||||
*
|
||||
* (If a function has two filenames, such as rename(), symlink(),
|
||||
* or copy(), PyErr_SetFromErrnoWithFilenames() is called, which
|
||||
* allows passing in a second filename.)
|
||||
*/
|
||||
|
||||
/* This function doesn't cleanup on error, the caller should */
|
||||
static int
|
||||
oserror_parse_args(PyObject **p_args,
|
||||
PyObject **myerrno, PyObject **strerror,
|
||||
PyObject **filename
|
||||
PyObject **filename, PyObject **filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, PyObject **winerror
|
||||
#endif
|
||||
|
@ -738,14 +742,23 @@ oserror_parse_args(PyObject **p_args,
|
|||
{
|
||||
Py_ssize_t nargs;
|
||||
PyObject *args = *p_args;
|
||||
#ifndef MS_WINDOWS
|
||||
/*
|
||||
* ignored on non-Windows platforms,
|
||||
* but parsed so OSError has a consistent signature
|
||||
*/
|
||||
PyObject *_winerror = NULL;
|
||||
PyObject **winerror = &_winerror;
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
nargs = PyTuple_GET_SIZE(args);
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
if (nargs >= 2 && nargs <= 4) {
|
||||
if (!PyArg_UnpackTuple(args, "OSError", 2, 4,
|
||||
myerrno, strerror, filename, winerror))
|
||||
if (nargs >= 2 && nargs <= 5) {
|
||||
if (!PyArg_UnpackTuple(args, "OSError", 2, 5,
|
||||
myerrno, strerror,
|
||||
filename, winerror, filename2))
|
||||
return -1;
|
||||
#ifdef MS_WINDOWS
|
||||
if (*winerror && PyLong_Check(*winerror)) {
|
||||
long errcode, winerrcode;
|
||||
PyObject *newargs;
|
||||
|
@ -777,14 +790,8 @@ oserror_parse_args(PyObject **p_args,
|
|||
Py_DECREF(args);
|
||||
args = *p_args = newargs;
|
||||
}
|
||||
#endif /* MS_WINDOWS */
|
||||
}
|
||||
#else
|
||||
if (nargs >= 2 && nargs <= 3) {
|
||||
if (!PyArg_UnpackTuple(args, "OSError", 2, 3,
|
||||
myerrno, strerror, filename))
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -792,7 +799,7 @@ oserror_parse_args(PyObject **p_args,
|
|||
static int
|
||||
oserror_init(PyOSErrorObject *self, PyObject **p_args,
|
||||
PyObject *myerrno, PyObject *strerror,
|
||||
PyObject *filename
|
||||
PyObject *filename, PyObject *filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, PyObject *winerror
|
||||
#endif
|
||||
|
@ -816,9 +823,14 @@ oserror_init(PyOSErrorObject *self, PyObject **p_args,
|
|||
Py_INCREF(filename);
|
||||
self->filename = filename;
|
||||
|
||||
if (nargs >= 2 && nargs <= 3) {
|
||||
/* filename is removed from the args tuple (for compatibility
|
||||
purposes, see test_exceptions.py) */
|
||||
if (filename2 && filename2 != Py_None) {
|
||||
Py_INCREF(filename2);
|
||||
self->filename2 = filename2;
|
||||
}
|
||||
|
||||
if (nargs >= 2 && nargs <= 5) {
|
||||
/* filename, filename2, and winerror are removed from the args tuple
|
||||
(for compatibility purposes, see test_exceptions.py) */
|
||||
PyObject *subslice = PyTuple_GetSlice(args, 0, 2);
|
||||
if (!subslice)
|
||||
return -1;
|
||||
|
@ -877,7 +889,8 @@ static PyObject *
|
|||
OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyOSErrorObject *self = NULL;
|
||||
PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL;
|
||||
PyObject *myerrno = NULL, *strerror = NULL;
|
||||
PyObject *filename = NULL, *filename2 = NULL;
|
||||
#ifdef MS_WINDOWS
|
||||
PyObject *winerror = NULL;
|
||||
#endif
|
||||
|
@ -888,7 +901,8 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
if (!_PyArg_NoKeywords(type->tp_name, kwds))
|
||||
goto error;
|
||||
|
||||
if (oserror_parse_args(&args, &myerrno, &strerror, &filename
|
||||
if (oserror_parse_args(&args, &myerrno, &strerror,
|
||||
&filename, &filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, &winerror
|
||||
#endif
|
||||
|
@ -917,7 +931,7 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
self->written = -1;
|
||||
|
||||
if (!oserror_use_init(type)) {
|
||||
if (oserror_init(self, &args, myerrno, strerror, filename
|
||||
if (oserror_init(self, &args, myerrno, strerror, filename, filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, winerror
|
||||
#endif
|
||||
|
@ -942,7 +956,8 @@ error:
|
|||
static int
|
||||
OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL;
|
||||
PyObject *myerrno = NULL, *strerror = NULL;
|
||||
PyObject *filename = NULL, *filename2 = NULL;
|
||||
#ifdef MS_WINDOWS
|
||||
PyObject *winerror = NULL;
|
||||
#endif
|
||||
|
@ -955,14 +970,14 @@ OSError_init(PyOSErrorObject *self, PyObject *args, PyObject *kwds)
|
|||
return -1;
|
||||
|
||||
Py_INCREF(args);
|
||||
if (oserror_parse_args(&args, &myerrno, &strerror, &filename
|
||||
if (oserror_parse_args(&args, &myerrno, &strerror, &filename, &filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, &winerror
|
||||
#endif
|
||||
))
|
||||
goto error;
|
||||
|
||||
if (oserror_init(self, &args, myerrno, strerror, filename
|
||||
if (oserror_init(self, &args, myerrno, strerror, filename, filename2
|
||||
#ifdef MS_WINDOWS
|
||||
, winerror
|
||||
#endif
|
||||
|
@ -982,6 +997,7 @@ OSError_clear(PyOSErrorObject *self)
|
|||
Py_CLEAR(self->myerrno);
|
||||
Py_CLEAR(self->strerror);
|
||||
Py_CLEAR(self->filename);
|
||||
Py_CLEAR(self->filename2);
|
||||
#ifdef MS_WINDOWS
|
||||
Py_CLEAR(self->winerror);
|
||||
#endif
|
||||
|
@ -1003,6 +1019,7 @@ OSError_traverse(PyOSErrorObject *self, visitproc visit,
|
|||
Py_VISIT(self->myerrno);
|
||||
Py_VISIT(self->strerror);
|
||||
Py_VISIT(self->filename);
|
||||
Py_VISIT(self->filename2);
|
||||
#ifdef MS_WINDOWS
|
||||
Py_VISIT(self->winerror);
|
||||
#endif
|
||||
|
@ -1012,23 +1029,42 @@ OSError_traverse(PyOSErrorObject *self, visitproc visit,
|
|||
static PyObject *
|
||||
OSError_str(PyOSErrorObject *self)
|
||||
{
|
||||
#define OR_NONE(x) ((x)?(x):Py_None)
|
||||
#ifdef MS_WINDOWS
|
||||
/* If available, winerror has the priority over myerrno */
|
||||
if (self->winerror && self->filename)
|
||||
if (self->winerror && self->filename) {
|
||||
if (self->filename2) {
|
||||
return PyUnicode_FromFormat("[WinError %S] %S: %R -> %R",
|
||||
OR_NONE(self->winerror),
|
||||
OR_NONE(self->strerror),
|
||||
self->filename,
|
||||
self->filename2);
|
||||
} else {
|
||||
return PyUnicode_FromFormat("[WinError %S] %S: %R",
|
||||
self->winerror ? self->winerror: Py_None,
|
||||
self->strerror ? self->strerror: Py_None,
|
||||
OR_NONE(self->winerror),
|
||||
OR_NONE(self->strerror),
|
||||
self->filename);
|
||||
}
|
||||
}
|
||||
if (self->winerror && self->strerror)
|
||||
return PyUnicode_FromFormat("[WinError %S] %S",
|
||||
self->winerror ? self->winerror: Py_None,
|
||||
self->strerror ? self->strerror: Py_None);
|
||||
#endif
|
||||
if (self->filename)
|
||||
if (self->filename) {
|
||||
if (self->filename2) {
|
||||
return PyUnicode_FromFormat("[Errno %S] %S: %R -> %R",
|
||||
OR_NONE(self->myerrno),
|
||||
OR_NONE(self->strerror),
|
||||
self->filename,
|
||||
self->filename2);
|
||||
} else {
|
||||
return PyUnicode_FromFormat("[Errno %S] %S: %R",
|
||||
self->myerrno ? self->myerrno: Py_None,
|
||||
self->strerror ? self->strerror: Py_None,
|
||||
OR_NONE(self->myerrno),
|
||||
OR_NONE(self->strerror),
|
||||
self->filename);
|
||||
}
|
||||
}
|
||||
if (self->myerrno && self->strerror)
|
||||
return PyUnicode_FromFormat("[Errno %S] %S",
|
||||
self->myerrno ? self->myerrno: Py_None,
|
||||
|
@ -1045,7 +1081,8 @@ OSError_reduce(PyOSErrorObject *self)
|
|||
/* self->args is only the first two real arguments if there was a
|
||||
* file name given to OSError. */
|
||||
if (PyTuple_GET_SIZE(args) == 2 && self->filename) {
|
||||
args = PyTuple_New(3);
|
||||
Py_ssize_t size = self->filename2 ? 5 : 3;
|
||||
args = PyTuple_New(size);
|
||||
if (!args)
|
||||
return NULL;
|
||||
|
||||
|
@ -1059,6 +1096,20 @@ OSError_reduce(PyOSErrorObject *self)
|
|||
|
||||
Py_INCREF(self->filename);
|
||||
PyTuple_SET_ITEM(args, 2, self->filename);
|
||||
|
||||
if (self->filename2) {
|
||||
/*
|
||||
* This tuple is essentially used as OSError(*args).
|
||||
* So, to recreate filename2, we need to pass in
|
||||
* winerror as well.
|
||||
*/
|
||||
Py_INCREF(Py_None);
|
||||
PyTuple_SET_ITEM(args, 3, Py_None);
|
||||
|
||||
/* filename2 */
|
||||
Py_INCREF(self->filename2);
|
||||
PyTuple_SET_ITEM(args, 4, self->filename2);
|
||||
}
|
||||
} else
|
||||
Py_INCREF(args);
|
||||
|
||||
|
@ -1098,6 +1149,8 @@ static PyMemberDef OSError_members[] = {
|
|||
PyDoc_STR("exception strerror")},
|
||||
{"filename", T_OBJECT, offsetof(PyOSErrorObject, filename), 0,
|
||||
PyDoc_STR("exception filename")},
|
||||
{"filename2", T_OBJECT, offsetof(PyOSErrorObject, filename2), 0,
|
||||
PyDoc_STR("second exception filename")},
|
||||
#ifdef MS_WINDOWS
|
||||
{"winerror", T_OBJECT, offsetof(PyOSErrorObject, winerror), 0,
|
||||
PyDoc_STR("Win32 exception code")},
|
||||
|
|
167
Python/errors.c
167
Python/errors.c
|
@ -409,6 +409,12 @@ PyErr_NoMemory(void)
|
|||
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
|
||||
{
|
||||
return PyErr_SetFromErrnoWithFilenameObjects(exc, filenameObject, NULL);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithFilenameObjects(PyObject *exc, PyObject *filenameObject, PyObject *filenameObject2)
|
||||
{
|
||||
PyObject *message;
|
||||
PyObject *v, *args;
|
||||
|
@ -480,10 +486,15 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (filenameObject != NULL)
|
||||
args = Py_BuildValue("(iOO)", i, message, filenameObject);
|
||||
if (filenameObject != NULL) {
|
||||
if (filenameObject2 != NULL)
|
||||
args = Py_BuildValue("(iOOiO)", i, message, filenameObject, 0, filenameObject2);
|
||||
else
|
||||
args = Py_BuildValue("(iOO)", i, message, filenameObject);
|
||||
} else {
|
||||
assert(filenameObject2 == NULL);
|
||||
args = Py_BuildValue("(iO)", i, message);
|
||||
}
|
||||
Py_DECREF(message);
|
||||
|
||||
if (args != NULL) {
|
||||
|
@ -500,16 +511,26 @@ PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithFilename(PyObject *exc, const char *filename)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL);
|
||||
Py_XDECREF(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithFilenames(PyObject *exc, const char *filename, const char *filename2)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *name2 = filename2 ? PyUnicode_DecodeFSDefault(filename2) : NULL;
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, const Py_UNICODE *filename)
|
||||
|
@ -517,16 +538,31 @@ PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, const Py_UNICODE *filename)
|
|||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name);
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, NULL);
|
||||
Py_XDECREF(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyErr_SetFromErrnoWithUnicodeFilenames(PyObject *exc, const Py_UNICODE *filename, const Py_UNICODE *filename2)
|
||||
{
|
||||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *name2 = filename2 ?
|
||||
PyUnicode_FromUnicode(filename2, wcslen(filename2)) :
|
||||
NULL;
|
||||
PyObject *result = PyErr_SetFromErrnoWithFilenameObjects(exc, name, name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return result;
|
||||
}
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
PyObject *
|
||||
PyErr_SetFromErrno(PyObject *exc)
|
||||
{
|
||||
return PyErr_SetFromErrnoWithFilenameObject(exc, NULL);
|
||||
return PyErr_SetFromErrnoWithFilenameObjects(exc, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
|
@ -535,6 +571,16 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
|
|||
PyObject *exc,
|
||||
int ierr,
|
||||
PyObject *filenameObject)
|
||||
{
|
||||
return PyErr_SetExcFromWindowsErrWithFilenameObjects(exc, ierr,
|
||||
filenameObject, NULL);
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
PyObject *filenameObject,
|
||||
PyObject *filenameObject2)
|
||||
{
|
||||
int len;
|
||||
WCHAR *s_buf = NULL; /* Free via LocalFree */
|
||||
|
@ -571,11 +617,15 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (filenameObject == NULL)
|
||||
filenameObject = Py_None;
|
||||
/* This is the constructor signature for passing a Windows error code.
|
||||
if (filenameObject == NULL) {
|
||||
assert(filenameObject2 == NULL);
|
||||
filenameObject = filenameObject2 = Py_None;
|
||||
}
|
||||
else if (filenameObject2 == NULL)
|
||||
filenameObject2 = Py_None;
|
||||
/* This is the constructor signature for OSError.
|
||||
The POSIX translation will be figured out by the constructor. */
|
||||
args = Py_BuildValue("(iOOi)", 0, message, filenameObject, err);
|
||||
args = Py_BuildValue("(iOOiO)", 0, message, filenameObject, err, filenameObject2);
|
||||
Py_DECREF(message);
|
||||
|
||||
if (args != NULL) {
|
||||
|
@ -596,13 +646,31 @@ PyObject *PyErr_SetExcFromWindowsErrWithFilename(
|
|||
const char *filename)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc,
|
||||
ierr,
|
||||
name);
|
||||
name,
|
||||
NULL);
|
||||
Py_XDECREF(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetExcFromWindowsErrWithFilenames(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
const char *filename,
|
||||
const char *filename2)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *name2 = filename2 ? PyUnicode_DecodeFSDefault(filename2) : NULL;
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc,
|
||||
ierr,
|
||||
name,
|
||||
name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilename(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
|
@ -611,31 +679,69 @@ PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilename(
|
|||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc,
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc,
|
||||
ierr,
|
||||
name);
|
||||
name,
|
||||
NULL);
|
||||
Py_XDECREF(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilenames(
|
||||
PyObject *exc,
|
||||
int ierr,
|
||||
const Py_UNICODE *filename,
|
||||
const Py_UNICODE *filename2)
|
||||
{
|
||||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *name2 = filename2 ?
|
||||
PyUnicode_FromUnicode(filename2, wcslen(filename2)) :
|
||||
NULL;
|
||||
PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObjects(exc,
|
||||
ierr,
|
||||
name,
|
||||
name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetExcFromWindowsErr(PyObject *exc, int ierr)
|
||||
{
|
||||
return PyErr_SetExcFromWindowsErrWithFilename(exc, ierr, NULL);
|
||||
return PyErr_SetExcFromWindowsErrWithFilenames(exc, ierr, NULL, NULL);
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetFromWindowsErr(int ierr)
|
||||
{
|
||||
return PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,
|
||||
ierr, NULL);
|
||||
return PyErr_SetExcFromWindowsErrWithFilenames(PyExc_OSError,
|
||||
ierr, NULL, NULL);
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetFromWindowsErrWithFilenames(
|
||||
int ierr,
|
||||
const char *filename,
|
||||
const char *filename2)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *name2 = filename2 ? PyUnicode_DecodeFSDefault(filename2) : NULL;
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyExc_OSError,
|
||||
ierr, name, name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetFromWindowsErrWithFilename(
|
||||
int ierr,
|
||||
const char *filename)
|
||||
{
|
||||
PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL;
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyExc_OSError,
|
||||
ierr, name);
|
||||
ierr, name, NULL);
|
||||
Py_XDECREF(name);
|
||||
return result;
|
||||
}
|
||||
|
@ -647,12 +753,31 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
|
|||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject(
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyExc_OSError,
|
||||
ierr, name);
|
||||
ierr, name, NULL);
|
||||
Py_XDECREF(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *PyErr_SetFromWindowsErrWithUnicodeFilenames(
|
||||
int ierr,
|
||||
const Py_UNICODE *filename,
|
||||
const Py_UNICODE *filename2)
|
||||
{
|
||||
PyObject *name = filename ?
|
||||
PyUnicode_FromUnicode(filename, wcslen(filename)) :
|
||||
NULL;
|
||||
PyObject *name2 = filename2 ?
|
||||
PyUnicode_FromUnicode(filename2, wcslen(filename2)) :
|
||||
NULL;
|
||||
PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObjects(
|
||||
PyExc_OSError,
|
||||
ierr, name, name2);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(name2);
|
||||
return result;
|
||||
}
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
PyObject *
|
||||
|
|
Loading…
Reference in New Issue