Change WindowsError to carry the Win32 error code in winerror,
and the DOS error code in errno. Revert changes where
WindowsError catch blocks unnecessarily special-case OSError.
diff --git a/Doc/lib/libexcs.tex b/Doc/lib/libexcs.tex
index f52ff0a..b51b7fc 100644
--- a/Doc/lib/libexcs.tex
+++ b/Doc/lib/libexcs.tex
@@ -399,11 +399,15 @@
\begin{excdesc}{WindowsError}
Raised when a Windows-specific error occurs or when the error number
does not correspond to an \cdata{errno} value. The
- \member{errno} and \member{strerror} values are created from the
+ \member{winerror} and \member{strerror} values are created from the
return values of the \cfunction{GetLastError()} and
\cfunction{FormatMessage()} functions from the Windows Platform API.
+ The \member{errno} value maps the \member{winerror} value to
+ corresponding \code{errno.h} values.
This is a subclass of \exception{OSError}.
\versionadded{2.0}
+\versionchanged[Previous versions put the \cfunction{GetLastError()}
+codes into \member{errno}]{2.5}
\end{excdesc}
\begin{excdesc}{ZeroDivisionError}
diff --git a/Lib/mailbox.py b/Lib/mailbox.py
index 2d3553a..bb115e1 100755
--- a/Lib/mailbox.py
+++ b/Lib/mailbox.py
@@ -24,12 +24,6 @@
'BabylMessage', 'MMDFMessage', 'UnixMailbox',
'PortableUnixMailbox', 'MmdfMailbox', 'MHMailbox', 'BabylMailbox' ]
-if sys.platform != 'win32':
- # Define WindowsError so that we can use it in an except statement
- # even on non-Windows systems
- class WindowsError:
- pass
-
class Mailbox:
"""A group of messages in a particular place."""
@@ -268,9 +262,6 @@
self.remove(key)
except KeyError:
pass
- except WindowsError, e:
- if e.errno != 2: # ERROR_FILE_NOT_FOUND
- raise
except OSError, e:
if e.errno != errno.ENOENT:
raise
@@ -426,12 +417,6 @@
path = os.path.join(self._path, 'tmp', uniq)
try:
os.stat(path)
- except WindowsError, e:
- if e.errno == 2: # ERROR_FILE_NOT_FOUND
- Maildir._count += 1
- return open(path, 'wb+')
- else:
- raise
except OSError, e:
if e.errno == errno.ENOENT:
Maildir._count += 1
@@ -579,12 +564,6 @@
self._file.close()
try:
os.rename(new_file.name, self._path)
- except WindowsError, e:
- if e.errno == 183: # ERROR_ALREADY_EXISTS
- os.remove(self._path)
- os.rename(new_file.name, self._path)
- else:
- raise
except OSError, e:
if e.errno == errno.EEXIST:
os.remove(self._path)
@@ -1856,13 +1835,6 @@
else:
os.rename(pre_lock.name, f.name + '.lock')
dotlock_done = True
- except WindowsError, e:
- if e.errno == 183: # ERROR_ALREADY_EXISTS
- os.remove(pre_lock.name)
- raise ExternalClashError('dot lock unavailable: %s' %
- f.name)
- else:
- raise
except OSError, e:
if e.errno == errno.EEXIST:
os.remove(pre_lock.name)
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 83dfa17..dd7e864 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -327,10 +327,6 @@
try:
_os.mkdir(file, 0700)
return file
- except WindowsError, e:
- if e.errno == 183: # ERROR_ALREADY_EXISTS
- continue # try again
- raise
except OSError, e:
if e.errno == _errno.EEXIST:
continue # try again
diff --git a/Misc/NEWS b/Misc/NEWS
index 4e1aa9e..0a769b7 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@
Core and builtins
-----------------
+- WindowsError now has two error code attributes: errno, which carries
+ the error values from errno.h, and winerror, which carries the error
+ values from winerror.h. Previous versions put the winerror.h values
+ (from GetLastError()) into the errno attribute.
+
- Patch #1475845: Raise IndentationError for unexpected indent.
- Patch #1479181: split open() and file() from being aliases for each other.
diff --git a/PC/errmap.h b/PC/errmap.h
new file mode 100644
index 0000000..59aeea1
--- /dev/null
+++ b/PC/errmap.h
@@ -0,0 +1,78 @@
+/* Generated file. Do not edit. */
+int winerror_to_errno(int winerror)
+{
+ switch(winerror) {
+ case 2: return 2;
+ case 3: return 2;
+ case 4: return 24;
+ case 5: return 13;
+ case 6: return 9;
+ case 7: return 12;
+ case 8: return 12;
+ case 9: return 12;
+ case 10: return 7;
+ case 11: return 8;
+ case 15: return 2;
+ case 16: return 13;
+ case 17: return 18;
+ case 18: return 2;
+ case 19: return 13;
+ case 20: return 13;
+ case 21: return 13;
+ case 22: return 13;
+ case 23: return 13;
+ case 24: return 13;
+ case 25: return 13;
+ case 26: return 13;
+ case 27: return 13;
+ case 28: return 13;
+ case 29: return 13;
+ case 30: return 13;
+ case 31: return 13;
+ case 32: return 13;
+ case 33: return 13;
+ case 34: return 13;
+ case 35: return 13;
+ case 36: return 13;
+ case 53: return 2;
+ case 65: return 13;
+ case 67: return 2;
+ case 80: return 17;
+ case 82: return 13;
+ case 83: return 13;
+ case 89: return 11;
+ case 108: return 13;
+ case 109: return 32;
+ case 112: return 28;
+ case 114: return 9;
+ case 128: return 10;
+ case 129: return 10;
+ case 130: return 9;
+ case 132: return 13;
+ case 145: return 41;
+ case 158: return 13;
+ case 161: return 2;
+ case 164: return 11;
+ case 167: return 13;
+ case 183: return 17;
+ case 188: return 8;
+ case 189: return 8;
+ case 190: return 8;
+ case 191: return 8;
+ case 192: return 8;
+ case 193: return 8;
+ case 194: return 8;
+ case 195: return 8;
+ case 196: return 8;
+ case 197: return 8;
+ case 198: return 8;
+ case 199: return 8;
+ case 200: return 8;
+ case 201: return 8;
+ case 202: return 8;
+ case 206: return 2;
+ case 215: return 11;
+ case 1816: return 12;
+ default: return EINVAL;
+ }
+}
diff --git a/PC/errmap.mak b/PC/errmap.mak
new file mode 100644
index 0000000..646bcd0
--- /dev/null
+++ b/PC/errmap.mak
@@ -0,0 +1,5 @@
+errmap.h: generrmap.exe
+ .\generrmap.exe > errmap.h
+
+genermap.exe: generrmap.c
+ cl generrmap.c
diff --git a/PC/generrmap.c b/PC/generrmap.c
new file mode 100644
index 0000000..2b25063
--- /dev/null
+++ b/PC/generrmap.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <errno.h>
+
+/* Extract the mapping of Win32 error codes to errno */
+
+int main()
+{
+ int i;
+ printf("/* Generated file. Do not edit. */\n");
+ printf("int winerror_to_errno(int winerror)\n");
+ printf("{\n\tswitch(winerror) {\n");
+ for(i=1; i < 65000; i++) {
+ _dosmaperr(i);
+ if (errno == EINVAL)
+ continue;
+ printf("\t\tcase %d: return %d;\n", i, errno);
+ }
+ printf("\t\tdefault: return EINVAL;\n");
+ printf("\t}\n}\n");
+}
diff --git a/Python/exceptions.c b/Python/exceptions.c
index 31fb53e..3f949ed 100644
--- a/Python/exceptions.c
+++ b/Python/exceptions.c
@@ -704,15 +704,132 @@
{NULL, NULL}
};
-
-
-
PyDoc_STRVAR(IOError__doc__, "I/O operation failed.");
PyDoc_STRVAR(OSError__doc__, "OS system call failed.");
#ifdef MS_WINDOWS
+#include "errmap.h"
+
PyDoc_STRVAR(WindowsError__doc__, "MS-Windows OS system call failed.");
+
+static PyObject *
+WindowsError__init__(PyObject *self, PyObject *args)
+{
+ PyObject *o_errcode, *result;
+ long errcode, posix_errno;
+ result = EnvironmentError__init__(self, args);
+ if (!result)
+ return NULL;
+ self = get_self(args);
+ if (!self)
+ goto failed;
+ /* Set errno to the POSIX errno, and winerror to the Win32
+ error code. */
+ o_errcode = PyObject_GetAttrString(self, "errno");
+ if (!o_errcode)
+ goto failed;
+ errcode = PyInt_AsLong(o_errcode);
+ if (!errcode == -1 && PyErr_Occurred())
+ goto failed;
+ posix_errno = winerror_to_errno(errcode);
+ if (PyObject_SetAttrString(self, "winerror", o_errcode) < 0)
+ goto failed;
+ Py_DECREF(o_errcode);
+ o_errcode = PyInt_FromLong(posix_errno);
+ if (!o_errcode)
+ goto failed;
+ if (PyObject_SetAttrString(self, "errno", o_errcode) < 0)
+ goto failed;
+ Py_DECREF(o_errcode);
+ return result;
+failed:
+ /* Could not set errno. */
+ Py_XDECREF(o_errcode);
+ Py_DECREF(self);
+ Py_DECREF(result);
+ return NULL;
+}
+
+static PyObject *
+WindowsError__str__(PyObject *self, PyObject *args)
+{
+ PyObject *originalself = self;
+ PyObject *filename;
+ PyObject *serrno;
+ PyObject *strerror;
+ PyObject *rtnval = NULL;
+
+ if (!PyArg_ParseTuple(args, "O:__str__", &self))
+ return NULL;
+
+ filename = PyObject_GetAttrString(self, "filename");
+ serrno = PyObject_GetAttrString(self, "winerror");
+ strerror = PyObject_GetAttrString(self, "strerror");
+ if (!filename || !serrno || !strerror)
+ goto finally;
+
+ if (filename != Py_None) {
+ PyObject *fmt = PyString_FromString("[Error %s] %s: %s");
+ PyObject *repr = PyObject_Repr(filename);
+ PyObject *tuple = PyTuple_New(3);
+
+ if (!fmt || !repr || !tuple) {
+ Py_XDECREF(fmt);
+ Py_XDECREF(repr);
+ Py_XDECREF(tuple);
+ goto finally;
+ }
+
+ PyTuple_SET_ITEM(tuple, 0, serrno);
+ PyTuple_SET_ITEM(tuple, 1, strerror);
+ PyTuple_SET_ITEM(tuple, 2, repr);
+
+ rtnval = PyString_Format(fmt, tuple);
+
+ Py_DECREF(fmt);
+ Py_DECREF(tuple);
+ /* already freed because tuple owned only reference */
+ serrno = NULL;
+ strerror = NULL;
+ }
+ else if (PyObject_IsTrue(serrno) && PyObject_IsTrue(strerror)) {
+ PyObject *fmt = PyString_FromString("[Error %s] %s");
+ PyObject *tuple = PyTuple_New(2);
+
+ if (!fmt || !tuple) {
+ Py_XDECREF(fmt);
+ Py_XDECREF(tuple);
+ goto finally;
+ }
+
+ PyTuple_SET_ITEM(tuple, 0, serrno);
+ PyTuple_SET_ITEM(tuple, 1, strerror);
+
+ rtnval = PyString_Format(fmt, tuple);
+
+ Py_DECREF(fmt);
+ Py_DECREF(tuple);
+ /* already freed because tuple owned only reference */
+ serrno = NULL;
+ strerror = NULL;
+ }
+ else
+ rtnval = EnvironmentError__str__(originalself, args);
+
+ finally:
+ Py_XDECREF(filename);
+ Py_XDECREF(serrno);
+ Py_XDECREF(strerror);
+ return rtnval;
+}
+
+static
+PyMethodDef WindowsError_methods[] = {
+ {"__init__", WindowsError__init__, METH_VARARGS},
+ {"__str__", WindowsError__str__, METH_VARARGS},
+ {NULL, NULL}
+};
#endif /* MS_WINDOWS */
#ifdef __VMS
@@ -1760,7 +1877,7 @@
{"OSError", &PyExc_OSError, &PyExc_EnvironmentError, OSError__doc__},
#ifdef MS_WINDOWS
{"WindowsError", &PyExc_WindowsError, &PyExc_OSError,
- WindowsError__doc__},
+WindowsError__doc__, WindowsError_methods},
#endif /* MS_WINDOWS */
#ifdef __VMS
{"VMSError", &PyExc_VMSError, &PyExc_OSError,