Author: Łukasz Langa <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit