diff --git a/ipfshttpclient/multipart.py b/ipfshttpclient/multipart.py index 09ff5985..3aa78721 100644 --- a/ipfshttpclient/multipart.py +++ b/ipfshttpclient/multipart.py @@ -621,9 +621,10 @@ def auto_close_iter_fd(fd, iter): finally: os.close(fd) - dirname = os.path.basename(os.path.normpath(directory)) + directory_str = utils.convert_path(directory) + dirname = os.path.basename(os.path.normpath(directory_str)) - fd = os.open(directory, os.O_CLOEXEC | os.O_DIRECTORY) + fd = os.open(directory_str, os.O_CLOEXEC | os.O_DIRECTORY) body, headers = stream_directory_impl(fd, dirname) return auto_close_iter_fd(fd, body), headers else: @@ -654,7 +655,7 @@ def stream_filesystem_node(filepaths, """ is_dir = False if isinstance(filepaths, utils.path_types): - is_dir = os.path.isdir(filepaths) + is_dir = os.path.isdir(utils.convert_path(filepaths)) elif isinstance(filepaths, int): import stat is_dir = stat.S_ISDIR(os.fstat(filepaths).st_mode) diff --git a/ipfshttpclient/utils.py b/ipfshttpclient/utils.py index b3a14313..a901d1e5 100644 --- a/ipfshttpclient/utils.py +++ b/ipfshttpclient/utils.py @@ -18,7 +18,31 @@ class collections: path_types = (six.text_type, six.binary_type) if hasattr(os, "PathLike"): #PY36+ - path_types += (os.PathLike,) + path_types += (os.PathLike,) + + def convert_path(path): + # Not needed since all system APIs also accept an `os.PathLike` + return path +else: + _pathlib_types = () + try: #PY2: doesn't have `pathlib` + import pathlib + _pathlib_types += (pathlib.PurePath,) + except ImportError: + pass + # Independently maintained forward-port of `pathlib` for Py27 and others + try: + import pathlib2 + _pathlib_types += (pathlib2.PurePath,) + except ImportError: + pass + path_types += _pathlib_types + + def convert_path(path): + # `pathlib`'s PathLike objects need to be treated specially and + # converted to strings when interacting with system APIs + return str(path) if isinstance(path, _pathlib_types) else path + def guess_mimetype(filename): @@ -59,7 +83,7 @@ def clean_file(file): if isinstance(file, int): return os.fdopen(file, 'rb', closefd=False), True elif not hasattr(file, 'read'): - return open(file, 'rb'), True + return open(convert_path(file), 'rb'), True else: return file, False diff --git a/test/functional/test_files.py b/test/functional/test_files.py index 1dfaf530..5c64faba 100644 --- a/test/functional/test_files.py +++ b/test/functional/test_files.py @@ -240,7 +240,7 @@ def test_mfs_file_write_stat_read_delete(client): assert sorted(desc["Stat"].items()) == sorted(stat.items()) # Read back (and compare file contents) - with open(desc["Name"], "rb") as file: + with open(str(desc["Name"]), "rb") as file: content = client.files.read(filepath) assert content == file.read() diff --git a/test/run-tests.py b/test/run-tests.py index 117d262e..6e3c7d58 100755 --- a/test/run-tests.py +++ b/test/run-tests.py @@ -77,8 +77,10 @@ def _contextlib_suppress(*exceptions): #PY2: Only add `encoding` parameter on Python 3 as it's not available on Unicode-hostile versions extra_args = {} -if not six.PY2: +if sys.version_info >= (3, 6, 0): extra_args["encoding"] = locale.getpreferredencoding() +elif not six.PY2: + extra_args["universal_newlines"] = True # Spawn IPFS daemon in data directory DAEMON = subprocess.Popen(["ipfs", "daemon", "--enable-pubsub-experiment"],