Author: &#321;ukasz Langa <luk...@langa.pl>
Branch: py3.6
Changeset: r95906:075d529ca03f
Date: 2019-02-08 17:39 +0100
http://bitbucket.org/pypy/pypy/changeset/075d529ca03f/

Log:    Support for os.PathLike in the posix module

diff --git a/lib-python/3/test/test_os.py b/lib-python/3/test/test_os.py
--- a/lib-python/3/test/test_os.py
+++ b/lib-python/3/test/test_os.py
@@ -3041,8 +3041,11 @@
                         if cleanup_fn is not None:
                             cleanup_fn(result)
 
+                # custom PyPy error message: see BPO-35942
                 with self.assertRaisesRegex(
-                        TypeError, 'should be string, bytes'):
+                        TypeError,
+                        r'(should be string, bytes|'
+                        r'__fspath__\(\) to return str or bytes)'):
                     fn(int_fspath, *extra_args)
 
                 if allow_fd:
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1740,9 +1740,19 @@
         from pypy.interpreter.unicodehelper import fsdecode
         return fsdecode(space, w_obj)
 
-    def fsencode_w(self, w_obj):
-        if self.isinstance_w(w_obj, self.w_unicode):
-            w_obj = self.fsencode(w_obj)
+    def fsencode_w(self, w_obj, allowed_types="string, bytes, or os.PathLike"):
+        try:
+            self._try_buffer_w(w_obj, self.BUF_FULL_RO)
+            if not self.isinstance_w(w_obj, self.w_bytes):
+                tp = self.type(w_obj).name
+                self.warn(self.newtext(
+                    "path should be %s, not %s" % (allowed_types, tp,)),
+                    self.w_DeprecationWarning)
+        except BufferInterfaceNotFound:
+            from pypy.module.posix.interp_posix import fspath
+            w_obj = fspath(self, w_obj)
+            if self.isinstance_w(w_obj, self.w_unicode):
+                w_obj = self.fsencode(w_obj)
         return self.bytesbuf0_w(w_obj)
 
     def bytesbuf0_w(self, w_obj):
@@ -1760,7 +1770,12 @@
         return rstring.assert_str0(result)
 
     def fsdecode_w(self, w_obj):
-        if self.isinstance_w(w_obj, self.w_bytes):
+        try:
+            self._try_buffer_w(w_obj, self.BUF_FULL_RO)
+        except BufferInterfaceNotFound:
+            from pypy.module.posix.interp_posix import fspath
+            w_obj = fspath(self, w_obj)
+        else:
             w_obj = self.fsdecode(w_obj)
         return self.unicode0_w(w_obj)
 
diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -56,7 +56,7 @@
         return self.space.fsencode_w(self.w_obj)
 
     def as_unicode(self):
-        return self.space.unicode0_w(self.w_obj)
+        return self.space.fsdecode_w(self.w_obj)
 
 class FileDecoder(object):
     is_unicode = False
@@ -66,7 +66,7 @@
         self.w_obj = w_obj
 
     def as_bytes(self):
-        return self.space.bytesbuf0_w(self.w_obj)
+        return self.space.fsencode_w(self.w_obj)
 
     def as_unicode(self):
         return self.space.fsdecode_w(self.w_obj)
@@ -85,7 +85,7 @@
             fname = FileEncoder(space, w_fname)
             return func(fname, *args)
         else:
-            fname = space.bytesbuf0_w(w_fname)
+            fname = FileDecoder(space, w_fname)
             return func(fname, *args)
     return dispatch
 
@@ -136,9 +136,11 @@
 
 @specialize.arg(2)
 def _unwrap_path(space, w_value, allow_fd=True):
-    if space.is_none(w_value):
-        raise oefmt(space.w_TypeError,
-            "can't specify None for path argument")
+    # equivalent of posixmodule.c:path_converter() in CPython
+    if allow_fd:
+        allowed_types = "string, bytes, os.PathLike or integer"
+    else:
+        allowed_types = "string, bytes or os.PathLike"
     if _WIN32:
         try:
             path_u = space.unicode0_w(w_value)
@@ -146,36 +148,20 @@
         except OperationError:
             pass
     try:
-        path_b = space.fsencode_w(w_value)
+        path_b = space.fsencode_w(w_value, allowed_types=allowed_types)
         return Path(-1, path_b, None, w_value)
     except OperationError as e:
-        if not e.match(space, space.w_TypeError):
+        if not allow_fd or not e.match(space, space.w_TypeError):
             raise
-    if allow_fd:
+        # File descriptor case
         try:
             space.index(w_value)
         except OperationError:
-            pass
-        else:
-            fd = unwrap_fd(space, w_value, "string, bytes or integer")
-            return Path(fd, None, None, w_value)
-
-    # Inline fspath() for better error messages.
-    w_fspath_method = space.lookup(w_value, '__fspath__')
-    if w_fspath_method:
-        w_result = space.get_and_call_function(w_fspath_method, w_value)
-        if (space.isinstance_w(w_result, space.w_text) or
-            space.isinstance_w(w_result, space.w_bytes)):
-            return _unwrap_path(space, w_result, allow_fd=False)
-
-    if allow_fd:
-        raise oefmt(space.w_TypeError,
-                    "illegal type for path parameter (should be "
-                    "string, bytes, os.PathLike or integer, not %T)", w_value)
-    else:
-        raise oefmt(space.w_TypeError,
-                    "illegal type for path parameter (should be "
-                    "string, bytes or os.PathLike, not %T)", w_value)
+            raise oefmt(space.w_TypeError,
+                        "illegal type for path parameter (should be "
+                        "%s, not %T)", allowed_types, w_value)
+        fd = unwrap_fd(space, w_value, allowed_types)
+        return Path(fd, None, None, w_value)
 
 class _PathOrFd(Unwrapper):
     def unwrap(self, space, w_value):
@@ -211,7 +197,7 @@
     if space.is_none(w_value):
         return DEFAULT_DIR_FD
     else:
-        return unwrap_fd(space, w_value)
+        return unwrap_fd(space, w_value, allowed_types="integer or None")
 
 class _DirFD(Unwrapper):
     def unwrap(self, space, w_value):
diff --git a/pypy/module/posix/test/test_posix2.py 
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -212,7 +212,7 @@
             assert exc.value.filename == "nonexistentdir/nonexistentfile"
 
         excinfo = raises(TypeError, self.posix.stat, None)
-        assert "can't specify None" in str(excinfo.value)
+        assert "should be string, bytes, os.PathLike or integer, not None" in 
str(excinfo.value)
         excinfo = raises(TypeError, self.posix.stat, 2.)
         assert "should be string, bytes, os.PathLike or integer, not float" in 
str(excinfo.value)
         raises(ValueError, self.posix.stat, -1)
@@ -1189,15 +1189,19 @@
                 skip("encoding not good enough")
             dest = bytes_dir + b"/file.txt"
             posix.symlink(bytes_dir + b"/somefile", dest)
-            with open(dest) as f:
-                data = f.read()
-                assert data == "who cares?"
-            #
-            posix.unlink(dest)
+            try:
+                with open(dest) as f:
+                    data = f.read()
+                    assert data == "who cares?"
+            finally:
+                posix.unlink(dest)
             posix.symlink(memoryview(bytes_dir + b"/somefile"), dest)
-            with open(dest) as f:
-                data = f.read()
-                assert data == "who cares?"
+            try:
+                with open(dest) as f:
+                    data = f.read()
+                    assert data == "who cares?"
+            finally:
+                posix.unlink(dest)
 
         # XXX skip test if dir_fd is unsupported
         def test_symlink_fd(self):
@@ -1211,6 +1215,25 @@
             finally:
                 posix.close(f)
                 posix.unlink(bytes_dir + '/somelink'.encode())
+
+        def test_symlink_fspath(self):
+            class Path:
+                def __init__(self, b):
+                    self.path = b
+                def __fspath__(self):
+                    return self.path
+            posix = self.posix
+            bytes_dir = self.bytes_dir
+            if bytes_dir is None:
+                skip("encoding not good enough")
+            dest = Path(bytes_dir + b"/file.txt")
+            posix.symlink(Path(bytes_dir + b"/somefile"), dest)
+            try:
+                with open(dest) as f:
+                    data = f.read()
+                    assert data == "who cares?"
+            finally:
+                posix.unlink(dest)
     else:
         def test_symlink(self):
             posix = self.posix
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to