Author: Ł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