[pypy-commit] pypy py3.5: Remove WindowsError, and add support for the "winerror" parameter in OSError.

amauryfa pypy.commits at gmail.com
Sat Apr 1 12:12:31 EDT 2017


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.5
Changeset: r90896:1b8d1cb66a57
Date: 2017-04-01 18:11 +0200
http://bitbucket.org/pypy/pypy/changeset/1b8d1cb66a57/

Log:	Remove WindowsError, and add support for the "winerror" parameter in
	OSError. Also maybe fix wrap_oserror on Windows.

	This is a shoot in the dark: I don't have Windows. But most of
	interp_exceptions can be tested on Linux.

diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -9,6 +9,7 @@
 from rpython.rlib.objectmodel import we_are_translated, specialize
 from rpython.rlib.objectmodel import dont_inline
 from rpython.rlib import rstack, rstackovf
+from rpython.rlib import rwin32
 
 from pypy.interpreter import debug
 
@@ -568,33 +569,6 @@
     # 31: ANSI color code "red"
     ansi_print(text, esc="31", file=file, newline=newline)
 
-try:
-    WindowsError
-except NameError:
-    _WINDOWS = False
-else:
-    _WINDOWS = True
-
-    def wrap_windowserror(space, e, w_filename=None):
-        XXX    # WindowsError no longer exists in Py3.5
-               # instead, OSError has a kwarg winerror that overrides
-               # any errno supplied
-        from rpython.rlib import rwin32
-
-        winerror = e.winerror
-        try:
-            msg = rwin32.FormatError(winerror)
-        except ValueError:
-            msg = 'Windows Error %d' % winerror
-        exc = space.w_WindowsError
-        if w_filename is not None:
-            w_error = space.call_function(exc, space.newint(winerror),
-                                          space.newtext(msg), w_filename)
-        else:
-            w_error = space.call_function(exc, space.newint(winerror),
-                                          space.newtext(msg))
-        return OperationError(exc, w_error)
-
 @specialize.arg(3, 6)
 def wrap_oserror2(space, e, w_filename=None, exception_name='w_OSError',
                   w_exception_class=None, w_filename2=None, eintr_retry=False):
@@ -612,9 +586,6 @@
     """
     assert isinstance(e, OSError)
 
-    if _WINDOWS and isinstance(e, WindowsError):
-        return wrap_windowserror(space, e, w_filename)
-
     if w_exception_class is None:
         w_exc = getattr(space, exception_name)
     else:
@@ -631,28 +602,37 @@
 def _wrap_oserror2_impl(space, e, w_filename, w_filename2, w_exc, eintr_retry):
     # move the common logic in its own function, instead of having it
     # duplicated 4 times in all 4 specialized versions of wrap_oserror2()
-    errno = e.errno
 
-    if errno == EINTR:
-        space.getexecutioncontext().checksignals()
-        if eintr_retry:
-            return None
+    if rwin32.WIN32 and isinstance(e, WindowsError):
+        winerror = e.winerror
+        try:
+            msg = rwin32.FormatError(winerror)
+        except ValueError:
+            msg = 'Windows Error %d' % winerror
+        w_errno = space.w_None
+        w_winerror = space.newint(winerror)
+        w_msg = space.newtext(msg)
+    else:
+        errno = e.errno
+        if errno == EINTR:
+            space.getexecutioncontext().checksignals()
+            if eintr_retry:
+                return None
 
-    try:
-        msg = strerror(errno)
-    except ValueError:
-        msg = u'error %d' % errno
-    if w_filename is not None:
-        if w_filename2 is not None:
-            w_error = space.call_function(w_exc, space.newint(errno),
-                                          space.newunicode(msg), w_filename,
-                                          space.w_None, w_filename2)
-        else:
-            w_error = space.call_function(w_exc, space.newint(errno),
-                                          space.newunicode(msg), w_filename)
-    else:
-        w_error = space.call_function(w_exc, space.newint(errno),
-                                      space.newunicode(msg))
+        try:
+            msg = strerror(errno)
+        except ValueError:
+            msg = u'error %d' % errno
+        w_errno = space.newint(errno)
+        w_winerror = space.w_None
+        w_msg = space.newunicode(msg)
+
+    if w_filename is None:
+        w_filename = space.w_None
+    if w_filename2 is None:
+        w_filename2 = space.w_None
+    w_error = space.call_function(w_exc, w_errno, w_msg, w_filename,
+                                  w_winerror, w_filename2)
     operror = OperationError(w_exc, w_error)
     if eintr_retry:
         raise operror
diff --git a/pypy/module/exceptions/__init__.py b/pypy/module/exceptions/__init__.py
--- a/pypy/module/exceptions/__init__.py
+++ b/pypy/module/exceptions/__init__.py
@@ -1,4 +1,4 @@
-import sys
+from rpython.rlib import rwin32
 from pypy.interpreter.mixedmodule import MixedModule
 
 class Module(MixedModule):
@@ -73,8 +73,8 @@
         'ZeroDivisionError' : 'interp_exceptions.W_ZeroDivisionError',
         }
 
-    if sys.platform.startswith("win"):
-        interpleveldefs['WindowsError'] = 'interp_exceptions.W_WindowsError'
+    if rwin32.WIN32:
+        interpleveldefs['WindowsError'] = 'interp_exceptions.W_OSError'
 
     def setup_after_space_initialization(self):
         from pypy.objspace.std.transparent import register_proxyable
diff --git a/pypy/module/exceptions/interp_exceptions.py b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -444,6 +444,7 @@
 
     def __init__(self, space):
         self.w_errno = None
+        self.w_winerror = None
         self.w_strerror = None
         self.w_filename = None
         self.w_filename2 = None
@@ -476,18 +477,36 @@
             w_errno = args_w[0]
             w_strerror = args_w[1]
             w_filename = None
+            w_winerror = None
             w_filename2 = None
             if len(args_w) > 2:
                 w_filename = args_w[2]
-                if len(args_w) > 4:
-                    w_filename2 = args_w[4]
-            return w_errno, w_strerror, w_filename, w_filename2
-        return None, None, None, None
+                if len(args_w) > 3:
+                    w_winerror = args_w[3]
+                    if len(args_w) > 4:
+                        w_filename2 = args_w[4]
+            if rwin32.WIN32 and w_winerror:
+                # Under Windows, if the winerror constructor argument is
+                # an integer, the 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 winerror attribute does not exist.
+                try:
+                    winerror = space.int_w(w_winerror)
+                except OperationError:
+                    w_winerror = None
+                else:
+                    w_errno = space.newint(
+                        WINERROR_TO_ERRNO.get(winerror, DEFAULT_WIN32_ERRNO))
+            return w_errno, w_winerror, w_strerror, w_filename, w_filename2
+        return None, None, None, None, None
 
     @staticmethod
     def descr_new(space, w_subtype, __args__):
         args_w, kwds_w = __args__.unpack()
         w_errno = None
+        w_winerror = None
         w_strerror = None
         w_filename = None
         w_filename2 = None
@@ -495,7 +514,7 @@
             if kwds_w:
                 raise oefmt(space.w_TypeError,
                             "OSError does not take keyword arguments")
-            (w_errno, w_strerror, w_filename, w_filename2
+            (w_errno, w_winerror, w_strerror, w_filename, w_filename2
              ) = W_OSError._parse_init_args(space, args_w)
         if (not space.is_none(w_errno) and
             space.is_w(w_subtype, space.gettypeobject(W_OSError.typedef))):
@@ -513,8 +532,8 @@
         exc = space.allocate_instance(W_OSError, w_subtype)
         W_OSError.__init__(exc, space)
         if not W_OSError._use_init(space, w_subtype):
-            exc._init_error(space, args_w, w_errno, w_strerror, w_filename,
-                            w_filename2)
+            exc._init_error(space, args_w, w_errno, w_winerror, w_strerror,
+                            w_filename, w_filename2)
         return exc
 
     def descr_init(self, space, __args__):
@@ -525,18 +544,17 @@
         if kwds_w:
             raise oefmt(space.w_TypeError,
                         "OSError does not take keyword arguments")
-        (w_errno, w_strerror, w_filename, w_filename2
+        (w_errno, w_winerror, w_strerror, w_filename, w_filename2
          ) = W_OSError._parse_init_args(space, args_w)
-        self._init_error(space, args_w, w_errno, w_strerror, w_filename,
-                         w_filename2)
+        self._init_error(space, args_w, w_errno, w_winerror, w_strerror,
+                         w_filename, w_filename2)
 
-    def _init_error(self, space, args_w, w_errno, w_strerror, w_filename,
-                    w_filename2):
+    def _init_error(self, space, args_w, w_errno, w_winerror, w_strerror,
+                    w_filename, w_filename2):
         W_BaseException.descr_init(self, space, args_w)
-        if w_errno:
-            self.w_errno = w_errno
-        if w_strerror:
-            self.w_strerror = w_strerror
+        self.w_errno = w_errno
+        self.w_winerror = w_winerror
+        self.w_strerror = w_strerror
 
         if not space.is_none(w_filename):
             if space.isinstance_w(
@@ -546,7 +564,8 @@
                 except OperationError:
                     self.w_filename = w_filename
             else:
-                self.w_filename = w_filename
+                if not space.is_none(w_filename):
+                    self.w_filename = w_filename
                 if not space.is_none(w_filename2):
                     self.w_filename2 = w_filename2
                 # filename is removed from the args tuple (for compatibility
@@ -575,6 +594,20 @@
             strerror = space.unicode_w(space.str(self.w_strerror))
         else:
             strerror = u""
+        if rwin32.WIN32 and self.w_winerror:
+            winerror = space.unicode_w(space.str(self.w_winerror))
+            # If available, winerror has the priority over errno
+            if self.w_filename:
+                if self.w_filename2:
+                    return space.newunicode(u"[WinError %s] %s: %s -> %s" % (
+                        winerror, strerror,
+                        space.unicode_w(space.repr(self.w_filename)),
+                        space.unicode_w(space.repr(self.w_filename2))))
+                return space.newunicode(u"[WinError %s] %s: %s" % (
+                    winerror, strerror,
+                    space.unicode_w(space.repr(self.w_filename))))
+            return space.newunicode(u"[WinError %s] %s" % (
+                winerror, strerror))
         if self.w_filename:
             if self.w_filename2:
                 return space.newunicode(u"[Errno %s] %s: %s -> %s" % (
@@ -597,6 +630,12 @@
     def descr_set_written(self, space, w_written):
         self.written = space.int_w(w_written)
 
+
+if hasattr(rwin32, 'build_winerror_to_errno'):
+    WINERROR_TO_ERRNO, DEFAULT_WIN32_ERRNO = rwin32.build_winerror_to_errno()
+else:
+    WINERROR_TO_ERRNO, DEFAULT_WIN32_ERRNO = {}, 22 # EINVAL
+
 W_OSError.typedef = TypeDef(
     'OSError',
     W_Exception.typedef,
@@ -609,62 +648,11 @@
     strerror = readwrite_attrproperty_w('w_strerror', W_OSError),
     filename = readwrite_attrproperty_w('w_filename', W_OSError),
     filename2= readwrite_attrproperty_w('w_filename2',W_OSError),
+    winerror = readwrite_attrproperty_w('w_winerror', W_OSError),
     characters_written = GetSetProperty(W_OSError.descr_get_written,
                                         W_OSError.descr_set_written),
     )
 
-class W_WindowsError(W_OSError):
-    """MS-Windows OS system call failed."""
-
-    def __init__(self, space):
-        self.w_winerror = space.w_None
-        W_OSError.__init__(self, space)
-
-    def descr_init(self, space, __args__):
-        # Set errno to the POSIX errno, and winerror to the Win32
-        # error code.
-        W_OSError.descr_init(self, space, __args__)
-        try:
-            errno = space.int_w(self.w_errno)
-        except OperationError:
-            errno = self._default_errno
-        else:
-            errno = self._winerror_to_errno.get(errno, self._default_errno)
-        self.w_winerror = self.w_errno
-        self.w_errno = space.newint(errno)
-
-    def descr_str(self, space):
-        if (not space.is_w(self.w_winerror, space.w_None) and
-            not space.is_w(self.w_strerror, space.w_None)):
-            winerror = space.int_w(self.w_winerror)
-            strerror = space.unicode_w(self.w_strerror)
-            if self.w_filename:
-                return space.newunicode(u"[Error %d] %s: %s" % (
-                    winerror,
-                    strerror,
-                    space.unicode_w(self.w_filename)))
-            return space.newunicode(u"[Error %d] %s" % (winerror,
-                                                  strerror))
-        return W_BaseException.descr_str(self, space)
-
-    if hasattr(rwin32, 'build_winerror_to_errno'):
-        _winerror_to_errno, _default_errno = rwin32.build_winerror_to_errno()
-        # Python 2 doesn't map ERROR_DIRECTORY (267) to ENOTDIR but
-        # Python 3 (CPython issue #12802) and build_winerror_to_errno do
-        del _winerror_to_errno[267]
-    else:
-        _winerror_to_errno, _default_errno = {}, 22 # EINVAL
-
-W_WindowsError.typedef = TypeDef(
-    "WindowsError",
-    W_OSError.typedef,
-    __doc__  = W_WindowsError.__doc__,
-    __new__  = _new(W_WindowsError),
-    __init__ = interp2app(W_WindowsError.descr_init),
-    __str__  = interp2app(W_WindowsError.descr_str),
-    winerror = readwrite_attrproperty_w('w_winerror', W_WindowsError),
-    )
-
 W_BlockingIOError = _new_exception(
     "BlockingIOError", W_OSError, "I/O operation would block")
 W_ConnectionError = _new_exception(
diff --git a/pypy/module/exceptions/test/test_exc.py b/pypy/module/exceptions/test/test_exc.py
--- a/pypy/module/exceptions/test/test_exc.py
+++ b/pypy/module/exceptions/test/test_exc.py
@@ -101,12 +101,13 @@
             WindowsError
         except NameError:
             skip('WindowsError not present')
-        ee = WindowsError(3, "x", "y")
-        assert str(ee) == "[Error 3] x: y"
+        ee = WindowsError(None, "x", "y", 3)
+        assert type(ee) is FileNotFoundError
+        assert str(ee) == "[WinError 3] x: 'y'"
         # winerror=3 (ERROR_PATH_NOT_FOUND) maps to errno=2 (ENOENT)
         assert ee.winerror == 3
         assert ee.errno == 2
-        assert str(WindowsError(3, "x")) == "[Error 3] x"
+        assert str(WindowsError(3, "x")) == "[Errno 3] x"
 
     def test_syntax_error(self):
         s = SyntaxError()


More information about the pypy-commit mailing list