Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-fsspec for openSUSE:Factory checked in at 2022-02-24 18:20:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-fsspec (Old) and /work/SRC/openSUSE:Factory/.python-fsspec.new.1958 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-fsspec" Thu Feb 24 18:20:44 2022 rev:18 rq:957036 version:2022.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-fsspec/python-fsspec.changes 2022-02-01 14:03:13.183964691 +0100 +++ /work/SRC/openSUSE:Factory/.python-fsspec.new.1958/python-fsspec.changes 2022-02-24 18:24:04.398648791 +0100 @@ -1,0 +2,11 @@ +Tue Feb 22 23:01:18 UTC 2022 - Matej Cepl <mc...@suse.com> + +- Update to 2022.02.0: + - reference FS performance + - directory/prefix FS + - FUSE + - iteration in threads + - OpenFiles slicing + - drop py36 + +------------------------------------------------------------------- Old: ---- fsspec-2022.01.0.tar.gz New: ---- fsspec-2022.02.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-fsspec.spec ++++++ --- /var/tmp/diff_new_pack.axyqjF/_old 2022-02-24 18:24:04.886648664 +0100 +++ /var/tmp/diff_new_pack.axyqjF/_new 2022-02-24 18:24:04.890648662 +0100 @@ -26,9 +26,9 @@ %bcond_with test %endif %define skip_python2 1 -%define ghversion 2022.01.0 +%define ghversion 2022.02.0 Name: python-fsspec%{psuffix} -Version: 2022.1.0 +Version: 2022.2.0 Release: 0 Summary: Filesystem specification package License: BSD-3-Clause @@ -69,6 +69,7 @@ BuildRequires: %{python_module panel} BuildRequires: %{python_module paramiko} BuildRequires: %{python_module pyftpdlib} +BuildRequires: %{python_module pytest-mock} BuildRequires: %{python_module pytest} BuildRequires: %{python_module python-snappy} BuildRequires: %{python_module requests} ++++++ fsspec-2022.01.0.tar.gz -> fsspec-2022.02.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/.github/workflows/main.yaml new/filesystem_spec-2022.02.0/.github/workflows/main.yaml --- old/filesystem_spec-2022.01.0/.github/workflows/main.yaml 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/.github/workflows/main.yaml 2022-02-22 18:44:54.000000000 +0100 @@ -13,7 +13,7 @@ strategy: fail-fast: false matrix: - TOXENV: [py36, py37, py38, py39, s3fs, gcsfs] + TOXENV: [py37, py38, py39, s3fs, gcsfs] env: TOXENV: ${{ matrix.TOXENV }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/.gitignore new/filesystem_spec-2022.02.0/.gitignore --- old/filesystem_spec-2022.01.0/.gitignore 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/.gitignore 2022-02-22 18:44:54.000000000 +0100 @@ -117,4 +117,7 @@ # docker artifacts .docker +# vi* +*.swp + build/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/ci/environment-win.yml new/filesystem_spec-2022.02.0/ci/environment-win.yml --- old/filesystem_spec-2022.01.0/ci/environment-win.yml 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/ci/environment-win.yml 2022-02-22 18:44:54.000000000 +0100 @@ -12,8 +12,10 @@ - pyftpdlib - cloudpickle - pytest + - pytest-asyncio - pytest-benchmark - pytest-cov + - pytest-mock - pytest-vcr - python-libarchive-c - numpy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/docs/source/api.rst new/filesystem_spec-2022.02.0/docs/source/api.rst --- old/filesystem_spec-2022.01.0/docs/source/api.rst 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/docs/source/api.rst 2022-02-22 18:44:54.000000000 +0100 @@ -119,6 +119,7 @@ fsspec.implementations.libarchive.LibArchiveFileSystem fsspec.implementations.dbfs.DatabricksFileSystem fsspec.implementations.reference.ReferenceFileSystem + fsspec.implementations.dirfs.DirFileSystem .. autoclass:: fsspec.implementations.ftp.FTPFileSystem :members: __init__ @@ -183,6 +184,9 @@ .. autoclass:: fsspec.implementations.reference.ReferenceFileSystem :members: __init__ +.. autoclass:: fsspec.implementations.dirfs.DirFileSystem + :members: __init__ + Other Known Implementations --------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/docs/source/changelog.rst new/filesystem_spec-2022.02.0/docs/source/changelog.rst --- old/filesystem_spec-2022.01.0/docs/source/changelog.rst 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/docs/source/changelog.rst 2022-02-22 18:44:54.000000000 +0100 @@ -1,6 +1,24 @@ Changelog ========= +2022.02.0 +--------- + +Enhancements + +- reference FS performance (#892, 900) +- directory/prefix FS (#745) + +Fixes + +- FUSE (#905, 891) +- iteration in threads (#893) +- OpenFiles slicing (#887) + +Other + +- drop py36 (#889, 901) + 2022.01.0 --------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/docs/source/index.rst new/filesystem_spec-2022.02.0/docs/source/index.rst --- old/filesystem_spec-2022.01.0/docs/source/index.rst 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/docs/source/index.rst 2022-02-22 18:44:54.000000000 +0100 @@ -55,6 +55,7 @@ ``fsspec`` filesystems are also supported by: #. `pyarrow`_, the in-memory data layout engine +#. `petl`_, a general purpose package for extracting, transforming and loading tables of data. ... plus many more that we don't know about. @@ -66,7 +67,7 @@ .. _DVC: https://dvc.org/ .. _kedro: https://kedro.readthedocs.io/en/stable/01_introduction/01_introduction.html .. _pyarrow: https://arrow.apache.org/docs/python/ - +.. _petl: https://petl.readthedocs.io/en/stable/io.html#petl.io.remotes.RemoteSource Installation ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/_version.py new/filesystem_spec-2022.02.0/fsspec/_version.py --- old/filesystem_spec-2022.01.0/fsspec/_version.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/_version.py 2022-02-22 18:44:54.000000000 +0100 @@ -22,9 +22,9 @@ # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). - git_refnames = " (tag: 2022.01.0)" - git_full = "ece2fe15b1cac41167b31b8421ac9936aef29010" - git_date = "2022-01-11 10:29:11 -0500" + git_refnames = " (HEAD -> master, tag: 2022.02.0)" + git_full = "f9089f5ce97e1e52ab70ce1f372fc4c0feed5132" + git_date = "2022-02-22 12:44:54 -0500" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/asyn.py new/filesystem_spec-2022.02.0/fsspec/asyn.py --- old/filesystem_spec-2022.01.0/fsspec/asyn.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/asyn.py 2022-02-22 18:44:54.000000000 +0100 @@ -12,7 +12,7 @@ from .callbacks import _DEFAULT_CALLBACK from .exceptions import FSTimeoutError from .spec import AbstractFileSystem -from .utils import PY36, is_exception, other_paths +from .utils import is_exception, other_paths private = re.compile("_[^_]") @@ -29,12 +29,6 @@ event.set() -if PY36: - grl = asyncio.events._get_running_loop -else: - grl = asyncio.events.get_running_loop - - def sync(loop, func, *args, timeout=None, **kwargs): """ Make loop run coroutine until it returns. Runs in other thread @@ -45,7 +39,7 @@ if loop is None or loop.is_closed(): raise RuntimeError("Loop is not running") try: - loop0 = grl() + loop0 = asyncio.events.get_running_loop() if loop0 is loop: raise NotImplementedError("Calling sync() from within a running loop") except RuntimeError: @@ -240,9 +234,7 @@ ] if callback is not _DEFAULT_CALLBACK: [ - t.add_done_callback( - lambda *_, **__: callback.call("relative_update", 1) - ) + t.add_done_callback(lambda *_, **__: callback.relative_update(1)) for t in chunk ] results.extend( @@ -482,7 +474,7 @@ batch_size = batch_size or self.batch_size coros = [] - callback.call("set_size", len(file_pairs)) + callback.set_size(len(file_pairs)) for lfile, rfile in file_pairs: callback.branch(lfile, rfile, kwargs) coros.append(self._put_file(lfile, rfile, **kwargs)) @@ -521,7 +513,7 @@ batch_size = kwargs.pop("batch_size", self.batch_size) coros = [] - callback.lazy_call("set_size", len, lpaths) + callback.set_size(len(lpaths)) for lpath, rpath in zip(lpaths, rpaths): callback.branch(rpath, lpath, kwargs) coros.append(self._get_file(rpath, lpath, **kwargs)) @@ -790,9 +782,6 @@ ): import traceback - if PY36: - raise NotImplementedError("Do not call this on Py 3.6") - tasks = [t for t in asyncio.tasks.all_tasks(loop[0]) if not t.done()] if printout: [task.print_stack() for task in tasks] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/core.py new/filesystem_spec-2022.02.0/fsspec/core.py --- old/filesystem_spec-2022.01.0/fsspec/core.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/core.py 2022-02-22 18:44:54.000000000 +0100 @@ -204,6 +204,12 @@ break [s.__exit__(*args) for s in self] + def __getitem__(self, item): + out = super().__getitem__(item) + if isinstance(item, slice): + return OpenFiles(out, mode=self.mode, fs=self.fs) + return out + def __repr__(self): return "<List of %s OpenFile instances>" % len(self) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/fuse.py new/filesystem_spec-2022.02.0/fsspec/fuse.py --- old/filesystem_spec-2022.01.0/fsspec/fuse.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/fuse.py 2022-02-22 18:44:54.000000000 +0100 @@ -82,6 +82,7 @@ def write(self, path, data, offset, fh): logger.debug("write %s", (path, offset)) f = self.cache[fh] + f.seek(offset) f.write(data) return len(data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/dirfs.py new/filesystem_spec-2022.02.0/fsspec/implementations/dirfs.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/dirfs.py 1970-01-01 01:00:00.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/dirfs.py 2022-02-22 18:44:54.000000000 +0100 @@ -0,0 +1,325 @@ +from ..asyn import AsyncFileSystem + + +class DirFileSystem(AsyncFileSystem): + def __init__(self, path, fs, *args, **storage_options): + """ + Parameters + ---------- + path: str + Path to the directory. + fs: AbstractFileSystem + An instantiated filesystem to wrap. + """ + super().__init__(*args, **storage_options) + + if self.asynchronous and not fs.async_impl: + raise ValueError("can't use asynchronous with non-async fs") + + if fs.async_impl and self.asynchronous != fs.asynchronous: + raise ValueError("both dirfs and fs should be in the same sync/async mode") + + self.path = fs._strip_protocol(path) + self.fs = fs + + def _join(self, path): + if isinstance(path, str): + if not self.path: + return path + if not path: + return self.path + return self.fs.sep.join((self.path, path)) + return [self._join(_path) for _path in path] + + def _relpath(self, path): + if isinstance(path, str): + if not self.path: + return path + if path == self.path: + return "" + prefix = self.path + self.fs.sep + assert path.startswith(prefix) + return path[len(prefix) :] + return [self._relpath(_path) for _path in path] + + # Wrappers below + + @property + def sep(self): + return self.fs.sep + + async def set_session(self, *args, **kwargs): + return await self.fs.set_session(*args, **kwargs) + + async def _rm_file(self, path, **kwargs): + return await self.fs._rm_file(self._join(path), **kwargs) + + def rm_file(self, path, **kwargs): + return self.fs.rm_file(self._join(path), **kwargs) + + async def _rm(self, path, *args, **kwargs): + return await self.fs._rm(self._join(path), *args, **kwargs) + + def rm(self, path, *args, **kwargs): + return self.fs.rm(self._join(path), *args, **kwargs) + + async def _cp_file(self, path1, path2, **kwargs): + return await self.fs._cp_file(self._join(path1), self._join(path2), **kwargs) + + def cp_file(self, path1, path2, **kwargs): + return self.fs.cp_file(self._join(path1), self._join(path2), **kwargs) + + async def _copy( + self, + path1, + path2, + *args, + **kwargs, + ): + return await self.fs._copy( + self._join(path1), + self._join(path2), + *args, + **kwargs, + ) + + def copy(self, path1, path2, *args, **kwargs): + return self.fs.copy( + self._join(path1), + self._join(path2), + *args, + **kwargs, + ) + + async def _pipe(self, path, *args, **kwargs): + return await self.fs._pipe(self._join(path), *args, **kwargs) + + def pipe(self, path, *args, **kwargs): + return self.fs.pipe(self._join(path), *args, **kwargs) + + async def _cat_file(self, path, *args, **kwargs): + return await self.fs._cat_file(self._join(path), *args, **kwargs) + + def cat_file(self, path, *args, **kwargs): + return self.fs.cat_file(self._join(path), *args, **kwargs) + + async def _cat(self, path, *args, **kwargs): + ret = await self.fs._cat( + self._join(path), + *args, + **kwargs, + ) + + if isinstance(ret, dict): + return {self._relpath(key): value for key, value in ret.items()} + + return ret + + def cat(self, path, *args, **kwargs): + ret = self.fs.cat( + self._join(path), + *args, + **kwargs, + ) + + if isinstance(ret, dict): + return {self._relpath(key): value for key, value in ret.items()} + + return ret + + async def _put_file(self, lpath, rpath, **kwargs): + return await self.fs._put_file(lpath, self._join(rpath), **kwargs) + + def put_file(self, lpath, rpath, **kwargs): + return self.fs.put_file(lpath, self._join(rpath), **kwargs) + + async def _put( + self, + lpath, + rpath, + *args, + **kwargs, + ): + return await self.fs._put( + lpath, + self._join(rpath), + *args, + **kwargs, + ) + + def put(self, lpath, rpath, *args, **kwargs): + return self.fs.put( + lpath, + self._join(rpath), + *args, + **kwargs, + ) + + async def _get_file(self, rpath, lpath, **kwargs): + return await self.fs._get_file(self._join(rpath), lpath, **kwargs) + + def get_file(self, rpath, lpath, **kwargs): + return self.fs.get_file(self._join(rpath), lpath, **kwargs) + + async def _get(self, rpath, *args, **kwargs): + return await self.fs._get(self._join(rpath), *args, **kwargs) + + def get(self, rpath, *args, **kwargs): + return self.fs.get(self._join(rpath), *args, **kwargs) + + async def _isfile(self, path): + return await self.fs._isfile(self._join(path)) + + def isfile(self, path): + return self.fs.isfile(self._join(path)) + + async def _isdir(self, path): + return await self.fs._isdir(self._join(path)) + + def isdir(self, path): + return self.fs.isdir(self._join(path)) + + async def _size(self, path): + return await self.fs._size(self._join(path)) + + def size(self, path): + return self.fs.size(self._join(path)) + + async def _exists(self, path): + return await self.fs._exists(self._join(path)) + + def exists(self, path): + return self.fs.exists(self._join(path)) + + async def _info(self, path, **kwargs): + return await self.fs._info(self._join(path), **kwargs) + + def info(self, path, **kwargs): + return self.fs.info(self._join(path), **kwargs) + + async def _ls(self, path, detail=True, **kwargs): + ret = await self.fs._ls(self._join(path), detail=detail, **kwargs) + if detail: + for entry in ret: + entry["name"] = self._relpath(entry["name"]) + return ret + + return self._relpath(ret) + + def ls(self, path, detail=True, **kwargs): + ret = self.fs.ls(self._join(path), detail=detail, **kwargs) + if detail: + for entry in ret: + entry["name"] = self._relpath(entry["name"]) + return ret + + return self._relpath(ret) + + async def _walk(self, path, *args, **kwargs): + async for root, dirs, files in self.fs._walk(self._join(path), *args, **kwargs): + yield self._relpath(root), dirs, files + + def walk(self, path, *args, **kwargs): + for root, dirs, files in self.fs.walk(self._join(path), *args, **kwargs): + yield self._relpath(root), dirs, files + + async def _glob(self, path, **kwargs): + detail = kwargs.get("detail", False) + ret = await self.fs._glob(self._join(path), **kwargs) + if detail: + return {self._relpath(path): info for path, info in ret.items()} + return self._relpath(ret) + + def glob(self, path, **kwargs): + detail = kwargs.get("detail", False) + ret = self.fs.glob(self._join(path), **kwargs) + if detail: + return {self._relpath(path): info for path, info in ret.items()} + return self._relpath(ret) + + async def _du(self, path, *args, **kwargs): + total = kwargs.get("total", True) + ret = await self.fs._du(self._join(path), *args, **kwargs) + if total: + return ret + + return {self._relpath(path): size for path, size in ret.items()} + + def du(self, path, *args, **kwargs): + total = kwargs.get("total", True) + ret = self.fs.du(self._join(path), *args, **kwargs) + if total: + return ret + + return {self._relpath(path): size for path, size in ret.items()} + + async def _find(self, path, *args, **kwargs): + detail = kwargs.get("detail", False) + ret = await self.fs._find(self._join(path), *args, **kwargs) + if detail: + return {self._relpath(path): info for path, info in ret.items()} + return self._relpath(ret) + + def find(self, path, *args, **kwargs): + detail = kwargs.get("detail", False) + ret = self.fs.find(self._join(path), *args, **kwargs) + if detail: + return {self._relpath(path): info for path, info in ret.items()} + return self._relpath(ret) + + async def _expand_path(self, path, *args, **kwargs): + return self._relpath( + await self.fs._expand_path(self._join(path), *args, **kwargs) + ) + + def expand_path(self, path, *args, **kwargs): + return self._relpath(self.fs.expand_path(self._join(path), *args, **kwargs)) + + async def _mkdir(self, path, *args, **kwargs): + return await self.fs._mkdir(self._join(path), *args, **kwargs) + + def mkdir(self, path, *args, **kwargs): + return self.fs.mkdir(self._join(path), *args, **kwargs) + + async def _makedirs(self, path, *args, **kwargs): + return await self.fs._makedirs(self._join(path), *args, **kwargs) + + def makedirs(self, path, *args, **kwargs): + return self.fs.makedirs(self._join(path), *args, **kwargs) + + def rmdir(self, path): + return self.fs.rmdir(self._join(path)) + + def mv_file(self, path1, path2, **kwargs): + return self.fs.mv_file( + self._join(path1), + self._join(path2), + **kwargs, + ) + + def touch(self, path, **kwargs): + return self.fs.touch(self._join(path), **kwargs) + + def created(self, path): + return self.fs.created(self._join(path)) + + def modified(self, path): + return self.fs.modified(self._join(path)) + + def sign(self, path, *args, **kwargs): + return self.fs.sign(self._join(path), *args, **kwargs) + + def __repr__(self): + return f"{self.__class__.__qualname__}(path='{self.path}', fs={self.fs})" + + def open( + self, + path, + *args, + **kwargs, + ): + return self.fs.open( + self._join(path), + *args, + **kwargs, + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/github.py new/filesystem_spec-2022.02.0/fsspec/implementations/github.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/github.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/github.py 2022-02-22 18:44:54.000000000 +0100 @@ -156,15 +156,17 @@ if r.status_code == 404: raise FileNotFoundError(path) r.raise_for_status() + types = {"blob": "file", "tree": "directory"} out = [ { "name": path + "/" + f["path"] if path else f["path"], "mode": f["mode"], - "type": {"blob": "file", "tree": "directory"}[f["type"]], + "type": types[f["type"]], "size": f.get("size", 0), "sha": f["sha"], } for f in r.json()["tree"] + if f["type"] in types ] if sha in [self.root, None]: self.dircache[path] = out diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/memory.py new/filesystem_spec-2022.02.0/fsspec/implementations/memory.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/memory.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/memory.py 2022-02-22 18:44:54.000000000 +0100 @@ -46,7 +46,7 @@ paths = set() starter = path + "/" out = [] - for p2 in self.store: + for p2 in tuple(self.store): if p2.startswith(starter): if "/" not in p2[len(starter) :]: # exact child diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/reference.py new/filesystem_spec-2022.02.0/fsspec/implementations/reference.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/reference.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/reference.py 2022-02-22 18:44:54.000000000 +0100 @@ -221,6 +221,7 @@ part_or_url, start0, end0 = self._cat_common(path) if isinstance(part_or_url, bytes): return part_or_url[start:end] + # TODO: update start0, end0 if start/end given, instead of slicing return self.fs.cat_file(part_or_url, start=start0, end=end0)[start:end] def pipe_file(self, path, value, **_): @@ -238,10 +239,10 @@ if self.isdir(rpath): return os.makedirs(lpath, exist_ok=True) data = self.cat_file(rpath, **kwargs) - callback.lazy_call("set_size", len, data) + callback.set_size(len(data)) with open(lpath, "wb") as f: f.write(data) - callback.lazy_call("absolute_update", len, data) + callback.absolute_update(len(data)) def get(self, rpath, lpath, recursive=False, **kwargs): if self.fs.async_impl: @@ -279,7 +280,6 @@ if self.templates: self.df["url"] = self.df["url"].map(_render_jinja) - self._dircache_from_items() def _process_references(self, references, template_overrides=None): if isinstance(references, (str, bytes)): @@ -293,7 +293,6 @@ raise ValueError(f"Unknown reference spec version: {vers}") # TODO: we make dircache by iterating over all entries, but for Spec >= 1, # can replace with programmatic. Is it even needed for mapper interface? - self._dircache_from_items() def _process_references0(self, references): """Make reference dict for Spec Version 0""" @@ -320,7 +319,7 @@ if v.startswith("base64:"): self.references[k] = base64.b64decode(v[7:]) self.references[k] = v - else: + elif self.templates: u = v[0] if "{{" in u: if self.simple_templates: @@ -332,6 +331,8 @@ else: u = _render_jinja(u) self.references[k] = [u] if len(v) == 1 else [u, v[1], v[2]] + else: + self.references[k] = v self.references.update(self._process_gen(references.get("gen", []))) def _process_templates(self, tmp): @@ -422,6 +423,8 @@ def ls(self, path, detail=True, **kwargs): path = self._strip_protocol(path) + if not self.dircache: + self._dircache_from_items() out = self._ls_from_cache(path) if out is None: raise FileNotFoundError @@ -430,16 +433,18 @@ return [o["name"] for o in out] def exists(self, path, **kwargs): # overwrite auto-sync version - try: - return self._ls_from_cache(path) is not None - except FileNotFoundError: - return False + return self.isdir(path) or self.isfile(path) def isdir(self, path): # overwrite auto-sync version - return self.exists(path) and self.info(path)["type"] == "directory" + if self.dircache: + return path in self.dircache + else: + # this may be faster than building dircache for single calls, but + # by looping will be slow for many calls; could cache it? + return any(_.startswith(f"{path}/") for _ in self.references) def isfile(self, path): # overwrite auto-sync version - return self.exists(path) and self.info(path)["type"] == "file" + return path in self.references async def _ls(self, path, detail=True, **kwargs): # calls fast sync code return self.ls(path, detail, **kwargs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_dirfs.py new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_dirfs.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_dirfs.py 1970-01-01 01:00:00.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_dirfs.py 2022-02-22 18:44:54.000000000 +0100 @@ -0,0 +1,566 @@ +import sys + +import pytest + +from fsspec.asyn import AsyncFileSystem +from fsspec.implementations.dirfs import DirFileSystem +from fsspec.spec import AbstractFileSystem + +PATH = "path/to/dir" +ARGS = ["foo", "bar"] +KWARGS = {"baz": "baz", "qux": "qux"} + + +@pytest.fixture +def make_fs(mocker): + def _make_fs(async_impl=False, asynchronous=False): + attrs = { + "sep": "/", + "async_impl": async_impl, + "_strip_protocol": lambda path: path, + } + + if async_impl: + if asynchronous and sys.version_info < (3, 8): + pytest.skip("no AsyncMock before Python 3.8") + + attrs["asynchronous"] = asynchronous + cls = AsyncFileSystem + else: + cls = AbstractFileSystem + + fs = mocker.MagicMock(spec=cls, **attrs) + + return fs + + return _make_fs + + +@pytest.fixture( + params=[ + pytest.param(False, id="sync"), + pytest.param(True, id="async"), + ] +) +def fs(make_fs, request): + return make_fs(async_impl=request.param) + + +@pytest.fixture +def asyncfs(make_fs): + return make_fs(async_impl=True, asynchronous=True) + + +@pytest.fixture +def make_dirfs(): + def _make_dirfs(fs, asynchronous=False): + return DirFileSystem(PATH, fs, asynchronous=asynchronous) + + return _make_dirfs + + +@pytest.fixture +def dirfs(make_dirfs, fs): + return make_dirfs(fs) + + +@pytest.fixture +def adirfs(make_dirfs, asyncfs): + return make_dirfs(asyncfs, asynchronous=True) + + +def test_dirfs(fs, asyncfs): + DirFileSystem("path", fs) + DirFileSystem("path", asyncfs, asynchronous=True) + + with pytest.raises(ValueError): + DirFileSystem("path", asyncfs) + + with pytest.raises(ValueError): + DirFileSystem("path", fs, asynchronous=True) + + +@pytest.mark.parametrize( + "root, rel, full", + [ + ("", "", ""), + ("", "foo", "foo"), + ("root", "", "root"), + ("root", "foo", "root/foo"), + ], +) +def test_path(fs, root, rel, full): + dirfs = DirFileSystem(root, fs) + assert dirfs._join(rel) == full + assert dirfs._relpath(full) == rel + + +def test_sep(mocker, dirfs): + sep = mocker.Mock() + dirfs.fs.sep = sep + assert dirfs.sep == sep + + +@pytest.mark.asyncio +async def test_set_session(mocker, adirfs): + adirfs.fs.set_session = mocker.AsyncMock() + assert ( + await adirfs.set_session(*ARGS, **KWARGS) == adirfs.fs.set_session.return_value + ) + adirfs.fs.set_session.assert_called_once_with(*ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_rm_file(adirfs): + await adirfs._rm_file("file", **KWARGS) + adirfs.fs._rm_file.assert_called_once_with(f"{PATH}/file", **KWARGS) + + +def test_rm_file(dirfs): + dirfs.rm_file("file", **KWARGS) + dirfs.fs.rm_file.assert_called_once_with("path/to/dir/file", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_rm(adirfs): + await adirfs._rm("file", *ARGS, **KWARGS) + adirfs.fs._rm.assert_called_once_with("path/to/dir/file", *ARGS, **KWARGS) + + +def test_rm(dirfs): + dirfs.rm("file", *ARGS, **KWARGS) + dirfs.fs.rm.assert_called_once_with("path/to/dir/file", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_cp_file(adirfs): + await adirfs._cp_file("one", "two", **KWARGS) + adirfs.fs._cp_file.assert_called_once_with(f"{PATH}/one", f"{PATH}/two", **KWARGS) + + +def test_cp_file(dirfs): + dirfs.cp_file("one", "two", **KWARGS) + dirfs.fs.cp_file.assert_called_once_with(f"{PATH}/one", f"{PATH}/two", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_copy(adirfs): + await adirfs._copy("one", "two", *ARGS, **KWARGS) + adirfs.fs._copy.assert_called_once_with( + f"{PATH}/one", f"{PATH}/two", *ARGS, **KWARGS + ) + + +def test_copy(dirfs): + dirfs.copy("one", "two", *ARGS, **KWARGS) + dirfs.fs.copy.assert_called_once_with(f"{PATH}/one", f"{PATH}/two", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_pipe(adirfs): + await adirfs._pipe("file", *ARGS, **KWARGS) + adirfs.fs._pipe.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +def test_pipe(dirfs): + dirfs.pipe("file", *ARGS, **KWARGS) + dirfs.fs.pipe.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_cat_file(adirfs): + assert ( + await adirfs._cat_file("file", *ARGS, **KWARGS) + == adirfs.fs._cat_file.return_value + ) + adirfs.fs._cat_file.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +def test_cat_file(dirfs): + assert dirfs.cat_file("file", *ARGS, **KWARGS) == dirfs.fs.cat_file.return_value + dirfs.fs.cat_file.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_cat(adirfs): + assert await adirfs._cat("file", *ARGS, **KWARGS) == adirfs.fs._cat.return_value + adirfs.fs._cat.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +def test_cat(dirfs): + assert dirfs.cat("file", *ARGS, **KWARGS) == dirfs.fs.cat.return_value + dirfs.fs.cat.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_cat_list(adirfs): + adirfs.fs._cat.return_value = {f"{PATH}/one": "foo", f"{PATH}/two": "bar"} + assert await adirfs._cat(["one", "two"], *ARGS, **KWARGS) == { + "one": "foo", + "two": "bar", + } + adirfs.fs._cat.assert_called_once_with( + [f"{PATH}/one", f"{PATH}/two"], *ARGS, **KWARGS + ) + + +def test_cat_list(dirfs): + dirfs.fs.cat.return_value = {f"{PATH}/one": "foo", f"{PATH}/two": "bar"} + assert dirfs.cat(["one", "two"], *ARGS, **KWARGS) == {"one": "foo", "two": "bar"} + dirfs.fs.cat.assert_called_once_with( + [f"{PATH}/one", f"{PATH}/two"], *ARGS, **KWARGS + ) + + +@pytest.mark.asyncio +async def test_async_put_file(adirfs): + await adirfs._put_file("local", "file", **KWARGS) + adirfs.fs._put_file.assert_called_once_with("local", f"{PATH}/file", **KWARGS) + + +def test_put_file(dirfs): + dirfs.put_file("local", "file", **KWARGS) + dirfs.fs.put_file.assert_called_once_with("local", f"{PATH}/file", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_put(adirfs): + await adirfs._put("local", "file", **KWARGS) + adirfs.fs._put.assert_called_once_with("local", f"{PATH}/file", **KWARGS) + + +def test_put(dirfs): + dirfs.put("local", "file", **KWARGS) + dirfs.fs.put.assert_called_once_with("local", f"{PATH}/file", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_get_file(adirfs): + await adirfs._get_file("file", "local", **KWARGS) + adirfs.fs._get_file.assert_called_once_with(f"{PATH}/file", "local", **KWARGS) + + +def test_get_file(dirfs): + dirfs.get_file("file", "local", **KWARGS) + dirfs.fs.get_file.assert_called_once_with(f"{PATH}/file", "local", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_get(adirfs): + await adirfs._get("file", "local", **KWARGS) + adirfs.fs._get.assert_called_once_with(f"{PATH}/file", "local", **KWARGS) + + +def test_get(dirfs): + dirfs.get("file", "local", **KWARGS) + dirfs.fs.get.assert_called_once_with(f"{PATH}/file", "local", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_isfile(adirfs): + assert await adirfs._isfile("file") == adirfs.fs._isfile.return_value + adirfs.fs._isfile.assert_called_once_with(f"{PATH}/file") + + +def test_isfile(dirfs): + assert dirfs.isfile("file") == dirfs.fs.isfile.return_value + dirfs.fs.isfile.assert_called_once_with(f"{PATH}/file") + + +@pytest.mark.asyncio +async def test_async_isdir(adirfs): + assert await adirfs._isdir("file") == adirfs.fs._isdir.return_value + adirfs.fs._isdir.assert_called_once_with(f"{PATH}/file") + + +def test_isdir(dirfs): + assert dirfs.isdir("file") == dirfs.fs.isdir.return_value + dirfs.fs.isdir.assert_called_once_with(f"{PATH}/file") + + +@pytest.mark.asyncio +async def test_async_size(adirfs): + assert await adirfs._size("file") == adirfs.fs._size.return_value + adirfs.fs._size.assert_called_once_with(f"{PATH}/file") + + +def test_size(dirfs): + assert dirfs.size("file") == dirfs.fs.size.return_value + dirfs.fs.size.assert_called_once_with(f"{PATH}/file") + + +@pytest.mark.asyncio +async def test_async_exists(adirfs): + assert await adirfs._exists("file") == adirfs.fs._exists.return_value + adirfs.fs._exists.assert_called_once_with(f"{PATH}/file") + + +def test_exists(dirfs): + assert dirfs.exists("file") == dirfs.fs.exists.return_value + dirfs.fs.exists.assert_called_once_with(f"{PATH}/file") + + +@pytest.mark.asyncio +async def test_async_info(adirfs): + assert await adirfs._info("file", **KWARGS) == adirfs.fs._info.return_value + adirfs.fs._info.assert_called_once_with(f"{PATH}/file", **KWARGS) + + +def test_info(dirfs): + assert dirfs.info("file", **KWARGS) == dirfs.fs.info.return_value + dirfs.fs.info.assert_called_once_with(f"{PATH}/file", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_ls(adirfs): + adirfs.fs._ls.return_value = [f"{PATH}/file"] + assert await adirfs._ls("file", detail=False, **KWARGS) == ["file"] + adirfs.fs._ls.assert_called_once_with(f"{PATH}/file", detail=False, **KWARGS) + + +def test_ls(dirfs): + dirfs.fs.ls.return_value = [f"{PATH}/file"] + assert dirfs.ls("file", detail=False, **KWARGS) == ["file"] + dirfs.fs.ls.assert_called_once_with(f"{PATH}/file", detail=False, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_ls_detail(adirfs): + adirfs.fs._ls.return_value = [{"name": f"{PATH}/file", "foo": "bar"}] + assert await adirfs._ls("file", detail=True, **KWARGS) == [ + {"name": "file", "foo": "bar"} + ] + adirfs.fs._ls.assert_called_once_with(f"{PATH}/file", detail=True, **KWARGS) + + +def test_ls_detail(dirfs): + dirfs.fs.ls.return_value = [{"name": f"{PATH}/file", "foo": "bar"}] + assert dirfs.ls("file", detail=True, **KWARGS) == [{"name": "file", "foo": "bar"}] + dirfs.fs.ls.assert_called_once_with(f"{PATH}/file", detail=True, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_walk(adirfs, mocker): + async def _walk(path, *args, **kwargs): + yield (f"{PATH}/root", ["foo", "bar"], ["baz", "qux"]) + + adirfs.fs._walk = mocker.MagicMock() + adirfs.fs._walk.side_effect = _walk + + actual = [] + async for entry in adirfs._walk("root", *ARGS, **KWARGS): + actual.append(entry) + assert actual == [("root", ["foo", "bar"], ["baz", "qux"])] + adirfs.fs._walk.assert_called_once_with(f"{PATH}/root", *ARGS, **KWARGS) + + +def test_walk(dirfs): + dirfs.fs.walk.return_value = iter( + [(f"{PATH}/root", ["foo", "bar"], ["baz", "qux"])] + ) + assert list(dirfs.walk("root", *ARGS, **KWARGS)) == [ + ("root", ["foo", "bar"], ["baz", "qux"]) + ] + dirfs.fs.walk.assert_called_once_with(f"{PATH}/root", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_glob(adirfs): + adirfs.fs._glob.return_value = [f"{PATH}/one", f"{PATH}/two"] + assert await adirfs._glob("*", **KWARGS) == ["one", "two"] + adirfs.fs._glob.assert_called_once_with(f"{PATH}/*", **KWARGS) + + +def test_glob(dirfs): + dirfs.fs.glob.return_value = [f"{PATH}/one", f"{PATH}/two"] + assert dirfs.glob("*", **KWARGS) == ["one", "two"] + dirfs.fs.glob.assert_called_once_with(f"{PATH}/*", **KWARGS) + + +@pytest.mark.asyncio +async def test_async_glob_detail(adirfs): + adirfs.fs._glob.return_value = { + f"{PATH}/one": {"foo": "bar"}, + f"{PATH}/two": {"baz": "qux"}, + } + assert await adirfs._glob("*", detail=True, **KWARGS) == { + "one": {"foo": "bar"}, + "two": {"baz": "qux"}, + } + adirfs.fs._glob.assert_called_once_with(f"{PATH}/*", detail=True, **KWARGS) + + +def test_glob_detail(dirfs): + dirfs.fs.glob.return_value = { + f"{PATH}/one": {"foo": "bar"}, + f"{PATH}/two": {"baz": "qux"}, + } + assert dirfs.glob("*", detail=True, **KWARGS) == { + "one": {"foo": "bar"}, + "two": {"baz": "qux"}, + } + dirfs.fs.glob.assert_called_once_with(f"{PATH}/*", detail=True, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_du(adirfs): + adirfs.fs._du.return_value = 1234 + assert await adirfs._du("file", *ARGS, **KWARGS) == 1234 + adirfs.fs._du.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +def test_du(dirfs): + dirfs.fs.du.return_value = 1234 + assert dirfs.du("file", *ARGS, **KWARGS) == 1234 + dirfs.fs.du.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_du_granular(adirfs): + adirfs.fs._du.return_value = {f"{PATH}/dir/one": 1, f"{PATH}/dir/two": 2} + assert await adirfs._du("dir", *ARGS, total=False, **KWARGS) == { + "dir/one": 1, + "dir/two": 2, + } + adirfs.fs._du.assert_called_once_with(f"{PATH}/dir", *ARGS, total=False, **KWARGS) + + +def test_du_granular(dirfs): + dirfs.fs.du.return_value = {f"{PATH}/dir/one": 1, f"{PATH}/dir/two": 2} + assert dirfs.du("dir", *ARGS, total=False, **KWARGS) == {"dir/one": 1, "dir/two": 2} + dirfs.fs.du.assert_called_once_with(f"{PATH}/dir", *ARGS, total=False, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_find(adirfs): + adirfs.fs._find.return_value = [f"{PATH}/dir/one", f"{PATH}/dir/two"] + assert await adirfs._find("dir", *ARGS, **KWARGS) == ["dir/one", "dir/two"] + adirfs.fs._find.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +def test_find(dirfs): + dirfs.fs.find.return_value = [f"{PATH}/dir/one", f"{PATH}/dir/two"] + assert dirfs.find("dir", *ARGS, **KWARGS) == ["dir/one", "dir/two"] + dirfs.fs.find.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_find_detail(adirfs): + adirfs.fs._find.return_value = { + f"{PATH}/dir/one": {"foo": "bar"}, + f"{PATH}/dir/two": {"baz": "qux"}, + } + assert await adirfs._find("dir", *ARGS, detail=True, **KWARGS) == { + "dir/one": {"foo": "bar"}, + "dir/two": {"baz": "qux"}, + } + adirfs.fs._find.assert_called_once_with(f"{PATH}/dir", *ARGS, detail=True, **KWARGS) + + +def test_find_detail(dirfs): + dirfs.fs.find.return_value = { + f"{PATH}/dir/one": {"foo": "bar"}, + f"{PATH}/dir/two": {"baz": "qux"}, + } + assert dirfs.find("dir", *ARGS, detail=True, **KWARGS) == { + "dir/one": {"foo": "bar"}, + "dir/two": {"baz": "qux"}, + } + dirfs.fs.find.assert_called_once_with(f"{PATH}/dir", *ARGS, detail=True, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_expand_path(adirfs): + adirfs.fs._expand_path.return_value = [f"{PATH}/file"] + assert await adirfs._expand_path("*", *ARGS, **KWARGS) == ["file"] + adirfs.fs._expand_path.assert_called_once_with(f"{PATH}/*", *ARGS, **KWARGS) + + +def test_expand_path(dirfs): + dirfs.fs.expand_path.return_value = [f"{PATH}/file"] + assert dirfs.expand_path("*", *ARGS, **KWARGS) == ["file"] + dirfs.fs.expand_path.assert_called_once_with(f"{PATH}/*", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_expand_path_list(adirfs): + adirfs.fs._expand_path.return_value = [f"{PATH}/1file", f"{PATH}/2file"] + assert await adirfs._expand_path(["1*", "2*"], *ARGS, **KWARGS) == [ + "1file", + "2file", + ] + adirfs.fs._expand_path.assert_called_once_with( + [f"{PATH}/1*", f"{PATH}/2*"], *ARGS, **KWARGS + ) + + +def test_expand_path_list(dirfs): + dirfs.fs.expand_path.return_value = [f"{PATH}/1file", f"{PATH}/2file"] + assert dirfs.expand_path(["1*", "2*"], *ARGS, **KWARGS) == ["1file", "2file"] + dirfs.fs.expand_path.assert_called_once_with( + [f"{PATH}/1*", f"{PATH}/2*"], *ARGS, **KWARGS + ) + + +@pytest.mark.asyncio +async def test_async_mkdir(adirfs): + await adirfs._mkdir("dir", *ARGS, **KWARGS) + adirfs.fs._mkdir.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +def test_mkdir(dirfs): + dirfs.mkdir("dir", *ARGS, **KWARGS) + dirfs.fs.mkdir.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +@pytest.mark.asyncio +async def test_async_makedirs(adirfs): + await adirfs._makedirs("dir", *ARGS, **KWARGS) + adirfs.fs._makedirs.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +def test_makedirs(dirfs): + dirfs.makedirs("dir", *ARGS, **KWARGS) + dirfs.fs.makedirs.assert_called_once_with(f"{PATH}/dir", *ARGS, **KWARGS) + + +def test_rmdir(mocker, dirfs): + dirfs.fs.rmdir = mocker.Mock() + dirfs.rmdir("dir") + dirfs.fs.rmdir.assert_called_once_with(f"{PATH}/dir") + + +def test_mv_file(mocker, dirfs): + dirfs.fs.mv_file = mocker.Mock() + dirfs.mv_file("one", "two", **KWARGS) + dirfs.fs.mv_file.assert_called_once_with(f"{PATH}/one", f"{PATH}/two", **KWARGS) + + +def test_touch(mocker, dirfs): + dirfs.fs.touch = mocker.Mock() + dirfs.touch("file", **KWARGS) + dirfs.fs.touch.assert_called_once_with(f"{PATH}/file", **KWARGS) + + +def test_created(mocker, dirfs): + dirfs.fs.created = mocker.Mock(return_value="date") + assert dirfs.created("file") == "date" + dirfs.fs.created.assert_called_once_with(f"{PATH}/file") + + +def test_modified(mocker, dirfs): + dirfs.fs.modified = mocker.Mock(return_value="date") + assert dirfs.modified("file") == "date" + dirfs.fs.modified.assert_called_once_with(f"{PATH}/file") + + +def test_sign(mocker, dirfs): + dirfs.fs.sign = mocker.Mock(return_value="url") + assert dirfs.sign("file", *ARGS, **KWARGS) == "url" + dirfs.fs.sign.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) + + +def test_open(mocker, dirfs): + dirfs.fs.open = mocker.Mock() + assert dirfs.open("file", *ARGS, **KWARGS) == dirfs.fs.open.return_value + dirfs.fs.open.assert_called_once_with(f"{PATH}/file", *ARGS, **KWARGS) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_http.py new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_http.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_http.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_http.py 2022-02-22 18:44:54.000000000 +0100 @@ -516,7 +516,6 @@ loop.call_soon_threadsafe(loop.stop) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in py36") def test_async_this_thread(server): async def _(): fs = fsspec.filesystem("http", asynchronous=True) @@ -565,7 +564,6 @@ @pytest.mark.parametrize("get_client", [get_aiohttp, get_proxy]) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_close(get_client): fs = fsspec.filesystem("http", skip_instance_cache=True) fs.close_session(None, asyncio.run(get_client())) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_local.py new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_local.py --- old/filesystem_spec-2022.01.0/fsspec/implementations/tests/test_local.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/implementations/tests/test_local.py 2022-02-22 18:44:54.000000000 +0100 @@ -182,9 +182,6 @@ @pytest.mark.parametrize("mode", ["rt", "rb"]) @pytest.mark.parametrize("fmt", list(compression.compr)) def test_compressions(fmt, mode, tmpdir): - if fmt == "zip" and sys.version_info < (3, 6): - pytest.xfail("zip compression requires python3.6 or higher") - tmpdir = str(tmpdir) fn = os.path.join(tmpdir, ".tmp.getsize") fs = LocalFileSystem() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/tests/test_api.py new/filesystem_spec-2022.02.0/fsspec/tests/test_api.py --- old/filesystem_spec-2022.01.0/fsspec/tests/test_api.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/tests/test_api.py 2022-02-22 18:44:54.000000000 +0100 @@ -3,7 +3,6 @@ import contextlib import os import pickle -import sys import tempfile import pytest @@ -213,7 +212,6 @@ assert f.read().decode("utf-8") == f.name -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no seek in old zipfile") def test_multilevel_chained_fs_zip_zip_file(): """This test reproduces fsspec/filesystem_spec#334""" import zipfile diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/tests/test_async.py new/filesystem_spec-2022.02.0/fsspec/tests/test_async.py --- old/filesystem_spec-2022.01.0/fsspec/tests/test_async.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/tests/test_async.py 2022-02-22 18:44:54.000000000 +0100 @@ -1,7 +1,6 @@ import asyncio import inspect import os -import sys import time import pytest @@ -18,7 +17,6 @@ assert not inspect.iscoroutinefunction(inst.info) -@pytest.mark.skipif(fsspec.asyn.PY36, reason="missing asyncio features o py36") def test_interrupt(): loop = fsspec.asyn.get_loop() @@ -46,32 +44,27 @@ dummy_func = fsspec.asyn.sync_wrapper(_dummy_async_func) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_sync_wrapper_timeout_on_less_than_expected_wait_time_not_finish_function(): test_obj = _DummyAsyncKlass() with pytest.raises(fsspec.FSTimeoutError): test_obj.dummy_func(timeout=0.1) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_sync_wrapper_timeout_on_more_than_expected_wait_time_will_finish_function(): test_obj = _DummyAsyncKlass() assert test_obj.dummy_func(timeout=5) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_sync_wrapper_timeout_none_will_wait_func_finished(): test_obj = _DummyAsyncKlass() assert test_obj.dummy_func(timeout=None) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_sync_wrapper_treat_timeout_0_as_none(): test_obj = _DummyAsyncKlass() assert test_obj.dummy_func(timeout=0) -@pytest.mark.skipif(sys.version_info < (3, 7), reason="no asyncio.run in <3.7") def test_run_coros_in_chunks(monkeypatch): total_running = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/tests/test_core.py new/filesystem_spec-2022.02.0/fsspec/tests/test_core.py --- old/filesystem_spec-2022.01.0/fsspec/tests/test_core.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/tests/test_core.py 2022-02-22 18:44:54.000000000 +0100 @@ -184,6 +184,8 @@ assert isinstance(files, OpenFiles) assert isinstance(files[0], OpenFile) assert len(files) == 2 + assert isinstance(files[:1], OpenFiles) + assert len(files[:1]) == 1 with files as of: assert len(of) == 2 assert not of[0].closed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/tests/test_file.py new/filesystem_spec-2022.02.0/fsspec/tests/test_file.py --- old/filesystem_spec-2022.01.0/fsspec/tests/test_file.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/tests/test_file.py 2022-02-22 18:44:54.000000000 +0100 @@ -1,6 +1,5 @@ """Tests abstract buffered file API, using FTP implementation""" import pickle -import sys import pytest @@ -9,10 +8,6 @@ data = b"hello" * 10000 -@pytest.mark.xfail( - sys.version_info < (3, 6), - reason="py35 error, see https://github.com/fsspec/filesystem_spec/issues/147", -) def test_pickle(ftp_writable): host, port, user, pw = ftp_writable ftp = FTPFileSystem(host=host, port=port, username=user, password=pw) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/tests/test_fuse.py new/filesystem_spec-2022.02.0/fsspec/tests/test_fuse.py --- old/filesystem_spec-2022.01.0/fsspec/tests/test_fuse.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/tests/test_fuse.py 2022-02-22 18:44:54.000000000 +0100 @@ -1,5 +1,4 @@ import os -import signal import subprocess import time from multiprocessing import Process @@ -69,8 +68,11 @@ os.rmdir(fn + "/inner") os.rmdir(fn) finally: - os.kill(fuse_process.pid, signal.SIGTERM) - fuse_process.join() + fuse_process.terminate() + fuse_process.join(timeout=10) + if fuse_process.is_alive(): + fuse_process.kill() + fuse_process.join() def host_mount_local(source_dir, mount_dir, debug_log): @@ -94,8 +96,11 @@ try: yield (source_dir, mount_dir) finally: - os.kill(fuse_process.pid, signal.SIGTERM) - fuse_process.join() + fuse_process.terminate() + fuse_process.join(timeout=10) + if fuse_process.is_alive(): + fuse_process.kill() + fuse_process.join() def test_mount(mount_local): @@ -124,3 +129,18 @@ assert cp.stdout == b"" assert set(os.listdir(source_dir)) == set(["text", "new"]) assert open(mount_dir / "new").read() == "test" + + +def test_seek_rw(mount_local): + source_dir, mount_dir = mount_local + fh = open(mount_dir / "text", "w") + fh.write("teST") + fh.seek(2) + fh.write("st") + fh.close() + + fh = open(mount_dir / "text", "r") + assert fh.read() == "test" + fh.seek(2) + assert fh.read() == "st" + fh.close() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/fsspec/utils.py new/filesystem_spec-2022.02.0/fsspec/utils.py --- old/filesystem_spec-2022.01.0/fsspec/utils.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/fsspec/utils.py 2022-02-22 18:44:54.000000000 +0100 @@ -10,7 +10,6 @@ from urllib.parse import urlsplit DEFAULT_BLOCK_SIZE = 5 * 2 ** 20 -PY36 = sys.version_info < (3, 7) def infer_storage_options(urlpath, inherit_storage_options=None): @@ -301,8 +300,8 @@ Notes ----- - Objects supporting the fspath protocol (Python 3.6+) are coerced - according to its __fspath__ method. + Objects supporting the fspath protocol are coerced according to its + __fspath__ method. For backwards compatibility with older Python version, pathlib.Path objects are specially coerced. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/setup.py new/filesystem_spec-2022.02.0/setup.py --- old/filesystem_spec-2022.01.0/setup.py 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/setup.py 2022-02-22 18:44:54.000000000 +0100 @@ -18,7 +18,6 @@ "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", @@ -32,7 +31,7 @@ license="BSD", keywords="file", packages=["fsspec", "fsspec.implementations"], - python_requires=">=3.6", + python_requires=">=3.7", install_requires=open("requirements.txt").read().strip().split("\n"), extras_require={ "entrypoints": ["importlib_metadata ; python_version < '3.8' "], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/filesystem_spec-2022.01.0/tox.ini new/filesystem_spec-2022.02.0/tox.ini --- old/filesystem_spec-2022.01.0/tox.ini 2022-01-11 16:29:11.000000000 +0100 +++ new/filesystem_spec-2022.02.0/tox.ini 2022-02-22 18:44:54.000000000 +0100 @@ -1,6 +1,6 @@ # content of: tox.ini , put in same dir as setup.py [tox] -envlist = {py36,py37,py38,py39} +envlist = {py37,py38,py39} [core] conda_channels= @@ -25,8 +25,10 @@ pyftpdlib cloudpickle pytest + pytest-asyncio pytest-benchmark pytest-cov + pytest-mock pytest-vcr fusepy tomli < 2 @@ -38,7 +40,7 @@ deps= hadoop-test-cluster==0.1.0 smbprotocol - py36,py37: importlib_metadata + py37: importlib_metadata [testenv] description=Run test suite against target versions. @@ -62,7 +64,7 @@ {[core]conda_deps} httpretty aiobotocore - "moto<2.0" + "moto<3.0" flask changedir=.tox/s3fs/tmp whitelist_externals=