Hello community, here is the log from the commit of package python-fs for openSUSE:Factory checked in at 2019-03-05 12:26:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-fs (Old) and /work/SRC/openSUSE:Factory/.python-fs.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-fs" Tue Mar 5 12:26:51 2019 rev:6 rq:681664 version:2.4.4 Changes: -------- --- /work/SRC/openSUSE:Factory/python-fs/python-fs.changes 2019-02-15 09:55:49.655751866 +0100 +++ /work/SRC/openSUSE:Factory/.python-fs.new.28833/python-fs.changes 2019-03-05 12:26:53.448835931 +0100 @@ -1,0 +2,25 @@ +Fri Mar 1 09:24:19 UTC 2019 - John Vandenberg <[email protected]> + +- Remove unnecessary bcond_without test +- Simplifed build dependencies on scandir and typing +- Fix compatibility Requires for older Python which were using incorrect + comparisons with python_version_nodots, and incorrectly used Recommends +- Update to v2.4.4 + * OSFS fail in nfs mounts +- from 2.4.3 + * Fixed broken "case_insensitive" check + * Fixed Windows test fails +- from 2.4.2 + * Fixed exception when Python runs with -OO +- from 2.4.1 + * Fixed hash method missing from WrapFS +- from 2.4.0 + * Added exclude and filter_dirs arguments to walk + * Micro-optimizations to walk +- from 2.3.1 + * Add encoding check in OSFS.validatepath +- from 2.3.0 + * IllegalBackReference had mangled error message + * Added FS.hash method + +------------------------------------------------------------------- Old: ---- fs-2.2.1.tar.gz New: ---- fs-2.4.4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-fs.spec ++++++ --- /var/tmp/diff_new_pack.gES6hN/_old 2019-03-05 12:26:54.112836050 +0100 +++ /var/tmp/diff_new_pack.gES6hN/_new 2019-03-05 12:26:54.116836051 +0100 @@ -16,10 +16,10 @@ # Please submit bugfixes or comments via https://bugs.opensuse.org/ # + %{?!python_module:%define python_module() python-%{**} python3-%{**}} -%bcond_without test Name: python-fs -Version: 2.2.1 +Version: 2.4.4 Release: 0 Summary: Python's filesystem abstraction layer License: MIT @@ -28,32 +28,35 @@ Source: https://files.pythonhosted.org/packages/source/f/fs/fs-%{version}.tar.gz # PATCH-FIX-UPSTREAM more-relaxed-requirements.patch [email protected] -- Weaken the version dependencies Patch0: more-relaxed-requirements.patch -BuildRequires: %{python_module setuptools} -BuildRequires: fdupes -BuildRequires: python-rpm-macros -%if %{with test} -BuildRequires: %{python_module appdirs >= 1.4} +BuildRequires: %{python_module appdirs >= 1.4.3} BuildRequires: %{python_module mock} BuildRequires: %{python_module nose} -BuildRequires: %{python_module pyftpdlib} BuildRequires: %{python_module psutil} +BuildRequires: %{python_module pyftpdlib} BuildRequires: %{python_module pysendfile} BuildRequires: %{python_module pytz} +BuildRequires: %{python_module scandir >= 1.5} +BuildRequires: %{python_module setuptools} BuildRequires: %{python_module six >= 1.10.0} +BuildRequires: %{python_module typing} +BuildRequires: fdupes BuildRequires: python-backports.os -BuildRequires: python-typing -%endif -Requires: python-appdirs +BuildRequires: python-rpm-macros +Requires: python-appdirs >= 1.4.3 Requires: python-psutil Requires: python-pytz Requires: python-setuptools -Requires: python-six +Requires: python-six >= 1.10.0 +Requires: python-typing >= 3.6 +Recommends: python-pyftpdlib %ifpython2 Requires: python-backports.os %endif -%if %{python_version_nodots} < 35 -Requires: python-typing -Recommends: python-enum34 +%if %{python_version_nodots} < 34 +Requires: python-enum34 >= 1.1.6 +Recommends: python-pysendfile +%endif +%if %{python3_version_nodots} < 35 Recommends: python-scandir >= 1.5 %endif BuildArch: noarch @@ -78,11 +81,9 @@ %python_install %python_expand %fdupes %{buildroot}%{$python_sitelib} -%if %{with test} %check export LANG=en_US.UTF-8 %python_exec setup.py test -%endif %files %{python_files} %doc README.md ++++++ fs-2.2.1.tar.gz -> fs-2.4.4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/PKG-INFO new/fs-2.4.4/PKG-INFO --- old/fs-2.2.1/PKG-INFO 2019-01-06 14:28:10.000000000 +0100 +++ new/fs-2.4.4/PKG-INFO 2019-02-23 11:15:03.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fs -Version: 2.2.1 +Version: 2.4.4 Summary: Python's filesystem abstraction layer Home-page: https://github.com/PyFilesystem/pyfilesystem2 Author: Will McGugan diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/_version.py new/fs-2.4.4/fs/_version.py --- old/fs-2.2.1/fs/_version.py 2019-01-06 14:28:03.000000000 +0100 +++ new/fs-2.4.4/fs/_version.py 2019-02-23 11:14:55.000000000 +0100 @@ -1,3 +1,3 @@ """Version, used in module and setup.py. """ -__version__ = "2.2.1" +__version__ = "2.4.4" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/base.py new/fs-2.4.4/fs/base.py --- old/fs-2.2.1/fs/base.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/fs/base.py 2019-02-23 11:14:55.000000000 +0100 @@ -9,6 +9,7 @@ from __future__ import absolute_import, print_function, unicode_literals import abc +import hashlib import itertools import os import threading @@ -65,6 +66,7 @@ def _new_name(method, old_name): """Return a method with a deprecation warning.""" # Looks suspiciously like a decorator, but isn't! + @wraps(method) def _method(*args, **kwargs): warnings.warn( @@ -75,6 +77,16 @@ ) return method(*args, **kwargs) + deprecated_msg = """ + Note: + .. deprecated:: 2.2.0 + Please use `~{}` +""".format( + method.__name__ + ) + if getattr(_method, "__doc__"): + _method.__doc__ += deprecated_msg + return _method @@ -1472,7 +1484,7 @@ pass else: if len(sys_path) > max_sys_path_length: - _msg = "path too long " "(max {max_chars} characters in sys path)" + _msg = "path too long (max {max_chars} characters in sys path)" msg = _msg.format(max_chars=max_sys_path_length) raise errors.InvalidPath(path, msg=msg) path = abspath(normpath(path)) @@ -1593,3 +1605,31 @@ from .tree import render render(self, **kwargs) + + def hash(self, path, name): + # type: (Text, Text) -> Text + """Get the hash of a file's contents. + + Arguments: + path(str): A path on the filesystem. + name(str): One of the algorithms supported by the hashlib module, e.g. `"md5"` + + Returns: + str: The hex digest of the hash. + + Raises: + fs.errors.UnsupportedHash: If the requested hash is not supported. + + """ + _path = self.validatepath(path) + try: + hash_object = hashlib.new(name) + except ValueError: + raise errors.UnsupportedHash("hash '{}' is not supported".format(name)) + with self.openbin(path) as binary_file: + while True: + chunk = binary_file.read(1024 * 1024) + if not chunk: + break + hash_object.update(chunk) + return hash_object.hexdigest() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/copy.py new/fs-2.4.4/fs/copy.py --- old/fs-2.2.1/fs/copy.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/fs/copy.py 2019-02-15 16:03:01.000000000 +0100 @@ -35,7 +35,7 @@ walker (~fs.walk.Walker, optional): A walker object that will be used to scan for files in ``src_fs``. Set this if you only want to consider a sub-set of the resources in ``src_fs``. - on_copy (callable):A function callback called after a single file copy + on_copy (callable): A function callback called after a single file copy is executed. Expected signature is ``(src_fs, src_path, dst_fs, dst_path)``. workers (int): Use `worker` threads to copy data, or ``0`` (default) for diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/errors.py new/fs-2.4.4/fs/errors.py --- old/fs-2.2.1/fs/errors.py 2018-08-19 16:37:51.000000000 +0200 +++ new/fs-2.4.4/fs/errors.py 2019-02-10 14:13:50.000000000 +0100 @@ -364,3 +364,12 @@ def __reduce__(self): return type(self), (self.path,) + + +class UnsupportedHash(ValueError): + """The requested hash algorithm is not supported. + + This exception will be thrown if a hash algorithm is requested that is + not supported by hashlib. + + """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/info.py new/fs-2.4.4/fs/info.py --- old/fs-2.2.1/fs/info.py 2019-01-06 14:28:03.000000000 +0100 +++ new/fs-2.4.4/fs/info.py 2019-01-30 17:51:00.000000000 +0100 @@ -45,6 +45,8 @@ """ + __slots__ = ["raw", "_to_datetime", "namespaces"] + def __init__(self, raw_info, to_datetime=epoch_to_datetime): # type: (RawInfo, ToDatetime) -> None """Create a resource info object from a raw info dict. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/osfs.py new/fs-2.4.4/fs/osfs.py --- old/fs-2.2.1/fs/osfs.py 2018-12-28 15:25:39.000000000 +0100 +++ new/fs-2.4.4/fs/osfs.py 2019-02-23 11:14:55.000000000 +0100 @@ -47,7 +47,7 @@ from .permissions import Permissions from .error_tools import convert_os_errors from .mode import Mode, validate_open_mode -from .errors import NoURL +from .errors import FileExpected, NoURL if False: # typing.TYPE_CHECKING from typing import ( @@ -134,7 +134,7 @@ raise errors.CreateFailed("root path does not exist") _meta = self._meta = { - "case_insensitive": os.path.normcase("Aa") != "aa", + "case_insensitive": os.path.normcase("Aa") == "aa", "network": False, "read_only": False, "supports_rename": True, @@ -151,9 +151,13 @@ _meta["invalid_path_chars"] = "\0" if "PC_PATH_MAX" in os.pathconf_names: - _meta["max_sys_path_length"] = os.pathconf( - fsencode(_root_path), os.pathconf_names["PC_PATH_MAX"] - ) + try: + _meta["max_sys_path_length"] = os.pathconf( + fsencode(_root_path), os.pathconf_names["PC_PATH_MAX"] + ) + except OSError: # pragma: no cover + # The above fails with nfs mounts on OSX. Go figure. + pass def __repr__(self): # type: () -> str @@ -245,12 +249,17 @@ def _gettarget(self, sys_path): # type: (Text) -> Optional[Text] - try: - target = os.readlink(fsencode(sys_path)) - except OSError: - return None - else: - return target + if hasattr(os, "readlink"): + try: + if _WINDOWS_PLATFORM: # pragma: no cover + target = os.readlink(sys_path) + else: + target = os.readlink(fsencode(sys_path)) + except OSError: + pass + else: + return target + return None def _make_link_info(self, sys_path): # type: (Text) -> Dict[Text, object] @@ -328,6 +337,8 @@ _mode.validate_bin() self.check() _path = self.validatepath(path) + if _path == "/": + raise errors.FileExpected(path) sys_path = self._to_sys_path(_path) with convert_os_errors("openbin", path): if six.PY2 and _mode.exclusive: @@ -454,7 +465,12 @@ self.check() namespaces = namespaces or () _path = self.validatepath(path) - sys_path = self._to_sys_path(_path) + if _WINDOWS_PLATFORM: + sys_path = os.path.join( + self._root_path, path.lstrip("/").replace("/", os.sep) + ) + else: + sys_path = self._to_sys_path(_path) with convert_os_errors("scandir", path, directory=True): for dir_entry in scandir(sys_path): info = { @@ -595,6 +611,8 @@ validate_open_mode(mode) self.check() _path = self.validatepath(path) + if _path == "/": + raise FileExpected(path) sys_path = self._to_sys_path(_path) with convert_os_errors("open", path): if six.PY2 and _mode.exclusive: @@ -627,3 +645,17 @@ if accessed is not None or modified is not None: with convert_os_errors("setinfo", path): os.utime(sys_path, (accessed, modified)) + + def validatepath(self, path): + # type: (Text) -> Text + """Check path may be encoded, in addition to usual checks.""" + try: + fsencode(path) + except UnicodeEncodeError as error: + raise errors.InvalidCharsInPath( + path, + msg="path '{path}' could not be encoded for the filesystem (check LANG env var); {error}".format( + path=path, error=error + ), + ) + return super(OSFS, self).validatepath(path) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/path.py new/fs-2.4.4/fs/path.py --- old/fs-2.2.1/fs/path.py 2018-08-19 16:37:51.000000000 +0200 +++ new/fs-2.4.4/fs/path.py 2019-01-26 13:32:28.000000000 +0100 @@ -66,7 +66,7 @@ >>> normpath("foo/../../bar") Traceback (most recent call last) ... - IllegalBackReference: Too many backrefs in 'foo/../../bar' + IllegalBackReference: path 'foo/../../bar' contains back-references outside of filesystem" """ if path in "/": @@ -86,7 +86,7 @@ else: components.append(component) except IndexError: - raise IllegalBackReference("Too many backrefs in '{}'".format(path)) + raise IllegalBackReference(path) return prefix + "/".join(components) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/test.py new/fs-2.4.4/fs/test.py --- old/fs-2.2.1/fs/test.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/fs/test.py 2019-02-20 15:13:10.000000000 +0100 @@ -1834,3 +1834,16 @@ def test_glob(self): self.assertIsInstance(self.fs.glob, glob.BoundGlobber) + def test_hash(self): + self.fs.makedir("foo").writebytes("hashme.txt", b"foobar" * 1024) + self.assertEqual( + self.fs.hash("foo/hashme.txt", "md5"), "9fff4bb103ab8ce4619064109c54cb9c" + ) + with self.assertRaises(errors.UnsupportedHash): + self.fs.hash("foo/hashme.txt", "nohash") + + with self.fs.opendir("foo") as foo_fs: + self.assertEqual( + foo_fs.hash("hashme.txt", "md5"), "9fff4bb103ab8ce4619064109c54cb9c" + ) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/walk.py new/fs-2.4.4/fs/walk.py --- old/fs-2.2.1/fs/walk.py 2018-08-19 16:37:51.000000000 +0200 +++ new/fs-2.4.4/fs/walk.py 2019-02-15 16:03:01.000000000 +0100 @@ -17,7 +17,7 @@ from ._repr import make_repr from .errors import FSError from .path import abspath -from .path import join +from .path import combine from .path import normpath if False: # typing.TYPE_CHECKING @@ -68,6 +68,12 @@ a list of filename patterns, e.g. ``['*.py']``. Files will only be returned if the final component matches one of the patterns. + exclude (list, optional): If supplied, this parameter should be + a list of filename patterns, e.g. ``['~*']``. Files matching + any of these patterns will be removed from the walk. + filter_dirs (list, optional): A list of patterns that will be used + to match directories paths. The walk will only open directories + that match at least one of these patterns. exclude_dirs (list, optional): A list of patterns that will be used to filter out directories from the walk. e.g. ``['*.svn', '*.git']``. @@ -81,6 +87,8 @@ on_error=None, # type: Optional[OnError] search="breadth", # type: Text filter=None, # type: Optional[List[Text]] + exclude=None, # type: Optional[List[Text]] + filter_dirs=None, # type: Optional[List[Text]] exclude_dirs=None, # type: Optional[List[Text]] max_depth=None, # type: Optional[int] ): @@ -99,6 +107,8 @@ self.on_error = on_error self.search = search self.filter = filter + self.exclude = exclude + self.filter_dirs = filter_dirs self.exclude_dirs = exclude_dirs self.max_depth = max_depth super(Walker, self).__init__() @@ -169,6 +179,8 @@ on_error=(self.on_error, None), search=(self.search, "breadth"), filter=(self.filter, None), + exclude=(self.exclude, None), + filter_dirs=(self.filter_dirs, None), exclude_dirs=(self.exclude_dirs, None), max_depth=(self.max_depth, None), ) @@ -192,6 +204,8 @@ """ if self.exclude_dirs is not None and fs.match(self.exclude_dirs, info.name): return False + if self.filter_dirs is not None and not fs.match(self.filter_dirs, info.name): + return False return self.check_open_dir(fs, path, info) def check_open_dir(self, fs, path, info): @@ -251,6 +265,9 @@ bool: `True` if the file should be included. """ + + if self.exclude is not None and fs.match(self.exclude, info.name): + return False return fs.match(self.filter, info.name) def _scan( @@ -341,9 +358,10 @@ recursively within the given directory. """ + _combine = combine for _path, info in self._iter_walk(fs, path=path): if info is not None and not info.is_dir: - yield join(_path, info.name) + yield _combine(_path, info.name) def dirs(self, fs, path="/"): # type: (FS, Text) -> Iterator[Text] @@ -358,9 +376,10 @@ recursively within the given directory. """ + _combine = combine for _path, info in self._iter_walk(fs, path=path): if info is not None and info.is_dir: - yield join(_path, info.name) + yield _combine(_path, info.name) def info( self, @@ -381,10 +400,11 @@ (str, Info): a tuple of ``(<absolute path>, <resource info>)``. """ + _combine = combine _walk = self._iter_walk(fs, path=path, namespaces=namespaces) for _path, info in _walk: if info is not None: - yield join(_path, info.name), info + yield _combine(_path, info.name), info def _walk_breadth( self, @@ -398,19 +418,27 @@ queue = deque([path]) push = queue.appendleft pop = queue.pop - depth = self._calculate_depth(path) + + _combine = combine + _scan = self._scan + _calculate_depth = self._calculate_depth + _check_open_dir = self._check_open_dir + _check_scan_dir = self._check_scan_dir + _check_file = self.check_file + + depth = _calculate_depth(path) while queue: dir_path = pop() - for info in self._scan(fs, dir_path, namespaces=namespaces): + for info in _scan(fs, dir_path, namespaces=namespaces): if info.is_dir: - _depth = self._calculate_depth(dir_path) - depth + 1 - if self._check_open_dir(fs, dir_path, info): + _depth = _calculate_depth(dir_path) - depth + 1 + if _check_open_dir(fs, dir_path, info): yield dir_path, info # Opened a directory - if self._check_scan_dir(fs, dir_path, info, _depth): - push(join(dir_path, info.name)) + if _check_scan_dir(fs, dir_path, info, _depth): + push(_combine(dir_path, info.name)) else: - if self.check_file(fs, info): + if _check_file(fs, info): yield dir_path, info # Found a file yield dir_path, None # End of directory @@ -425,15 +453,18 @@ """ # No recursion! - def scan(path): - # type: (Text) -> Iterator[Info] - """Perform scan.""" - return self._scan(fs, path, namespaces=namespaces) + _combine = combine + _scan = self._scan + _calculate_depth = self._calculate_depth + _check_open_dir = self._check_open_dir + _check_scan_dir = self._check_scan_dir + _check_file = self.check_file + depth = _calculate_depth(path) stack = [ - (path, scan(path), None) + (path, _scan(fs, path, namespaces=namespaces), None) ] # type: List[Tuple[Text, Iterator[Info], Optional[Tuple[Text, Info]]]] - depth = self._calculate_depth(path) + push = stack.append while stack: @@ -445,15 +476,21 @@ yield dir_path, None del stack[-1] elif info.is_dir: - _depth = self._calculate_depth(dir_path) - depth + 1 - if self._check_open_dir(fs, dir_path, info): - if self._check_scan_dir(fs, dir_path, info, _depth): - _path = join(dir_path, info.name) - push((_path, scan(_path), (dir_path, info))) + _depth = _calculate_depth(dir_path) - depth + 1 + if _check_open_dir(fs, dir_path, info): + if _check_scan_dir(fs, dir_path, info, _depth): + _path = _combine(dir_path, info.name) + push( + ( + _path, + _scan(fs, _path, namespaces=namespaces), + (dir_path, info), + ) + ) else: yield dir_path, info else: - if self.check_file(fs, info): + if _check_file(fs, info): yield dir_path, info @@ -525,6 +562,12 @@ of file name patterns, e.g. ``['*.py']``. Files will only be returned if the final component matches one of the patterns. + exclude (list, optional): If supplied, this parameter should be + a list of filename patterns, e.g. ``['~*', '.*']``. Files matching + any of these patterns will be removed from the walk. + filter_dirs (list, optional): A list of patterns that will be used + to match directories paths. The walk will only open directories + that match at least one of these patterns. exclude_dirs (list): A list of patterns that will be used to filter out directories from the walk, e.g. ``['*.svn', '*.git']``. @@ -574,6 +617,12 @@ of file name patterns, e.g. ``['*.py']``. Files will only be returned if the final component matches one of the patterns. + exclude (list, optional): If supplied, this parameter should be + a list of filename patterns, e.g. ``['~*', '.*']``. Files matching + any of these patterns will be removed from the walk. + filter_dirs (list, optional): A list of patterns that will be used + to match directories paths. The walk will only open directories + that match at least one of these patterns. exclude_dirs (list): A list of patterns that will be used to filter out directories from the walk, e.g. ``['*.svn', '*.git']``. @@ -606,6 +655,9 @@ `False` to re-raise it. search (str): If ``'breadth'`` then the directory will be walked *top down*. Set to ``'depth'`` to walk *bottom up*. + filter_dirs (list, optional): A list of patterns that will be used + to match directories paths. The walk will only open directories + that match at least one of these patterns. exclude_dirs (list): A list of patterns that will be used to filter out directories from the walk, e.g. ``['*.svn', '*.git']``. @@ -650,6 +702,12 @@ of file name patterns, e.g. ``['*.py']``. Files will only be returned if the final component matches one of the patterns. + exclude (list, optional): If supplied, this parameter should be + a list of filename patterns, e.g. ``['~*', '.*']``. Files matching + any of these patterns will be removed from the walk. + filter_dirs (list, optional): A list of patterns that will be used + to match directories paths. The walk will only open directories + that match at least one of these patterns. exclude_dirs (list): A list of patterns that will be used to filter out directories from the walk, e.g. ``['*.svn', '*.git']``. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs/wrapfs.py new/fs-2.4.4/fs/wrapfs.py --- old/fs-2.2.1/fs/wrapfs.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/fs/wrapfs.py 2019-02-20 15:13:10.000000000 +0100 @@ -491,6 +491,13 @@ path = abspath(normpath(path)) return path + def hash(self, path, name): + # type: (Text, Text) -> Text + self.check() + _fs, _path = self.delegate_path(path) + with unwrap_errors(path): + return _fs.hash(_path, name) + @property def walk(self): # type: () -> BoundWalker diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/fs.egg-info/PKG-INFO new/fs-2.4.4/fs.egg-info/PKG-INFO --- old/fs-2.2.1/fs.egg-info/PKG-INFO 2019-01-06 14:28:10.000000000 +0100 +++ new/fs-2.4.4/fs.egg-info/PKG-INFO 2019-02-23 11:15:03.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: fs -Version: 2.2.1 +Version: 2.4.4 Summary: Python's filesystem abstraction layer Home-page: https://github.com/PyFilesystem/pyfilesystem2 Author: Will McGugan diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_archives.py new/fs-2.4.4/tests/test_archives.py --- old/fs-2.2.1/tests/test_archives.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/tests/test_archives.py 2019-02-23 10:58:23.000000000 +0100 @@ -86,9 +86,10 @@ except errors.NoSysPath: pass else: - self.assertEqual( - top.permissions.mode, stat.S_IMODE(os.stat(source_syspath).st_mode) - ) + if top.has_namespace("access"): + self.assertEqual( + top.permissions.mode, stat.S_IMODE(os.stat(source_syspath).st_mode) + ) self.assertEqual(top.get("details", "type"), ResourceType.file) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_ftpfs.py new/fs-2.4.4/tests/test_ftpfs.py --- old/fs-2.2.1/tests/test_ftpfs.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/tests/test_ftpfs.py 2019-02-23 10:58:23.000000000 +0100 @@ -25,6 +25,7 @@ from fs import errors from fs.opener import open_fs from fs.ftpfs import FTPFS, ftp_errors +from fs.path import join from fs.subfs import SubFS from fs.test import FSTestCases @@ -200,7 +201,7 @@ def test_create(self): - directory = os.path.join("home", self.user, "test", "directory") + directory = join("home", self.user, "test", "directory") base = "ftp://user:1234@{}:{}/foo".format(self.server.host, self.server.port) url = "{}/{}".format(base, directory) @@ -215,7 +216,7 @@ # Open the base filesystem and check the subdirectory exists with open_fs(base) as ftp_fs: self.assertTrue(ftp_fs.isdir(directory)) - self.assertTrue(ftp_fs.isfile(os.path.join(directory, "foo"))) + self.assertTrue(ftp_fs.isfile(join(directory, "foo"))) # Open without `create` and check the file exists with open_fs(url) as ftp_fs: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_osfs.py new/fs-2.4.4/tests/test_osfs.py --- old/fs-2.2.1/tests/test_osfs.py 2018-10-03 11:58:58.000000000 +0200 +++ new/fs-2.4.4/tests/test_osfs.py 2019-02-23 10:58:23.000000000 +0100 @@ -1,3 +1,4 @@ +# coding: utf-8 from __future__ import unicode_literals import errno @@ -68,23 +69,23 @@ with self.assertRaises(errors.CreateFailed): fs = osfs.OSFS("/does/not/exists/") - @unittest.skipIf(osfs.sendfile is None, 'sendfile not supported') + @unittest.skipIf(osfs.sendfile is None, "sendfile not supported") def test_copy_sendfile(self): # try copying using sendfile - with mock.patch.object(osfs, 'sendfile') as sendfile: - sendfile.side_effect = OSError(errno.ENOTSUP, 'sendfile not supported') + with mock.patch.object(osfs, "sendfile") as sendfile: + sendfile.side_effect = OSError(errno.ENOTSUP, "sendfile not supported") self.test_copy() # check other errors are transmitted - self.fs.touch('foo') - with mock.patch.object(osfs, 'sendfile') as sendfile: + self.fs.touch("foo") + with mock.patch.object(osfs, "sendfile") as sendfile: sendfile.side_effect = OSError(errno.EWOULDBLOCK) with self.assertRaises(OSError): - self.fs.copy('foo', 'foo_copy') + self.fs.copy("foo", "foo_copy") # check parent exist and is dir with self.assertRaises(errors.ResourceNotFound): - self.fs.copy('foo', 'spam/eggs') + self.fs.copy("foo", "spam/eggs") with self.assertRaises(errors.DirectoryExpected): - self.fs.copy('foo', 'foo_copy/foo') + self.fs.copy("foo", "foo_copy/foo") def test_create(self): """Test create=True""" @@ -114,6 +115,7 @@ finally: shutil.rmtree(dir_path) + @unittest.skipIf(not hasattr(os, "symlink"), "No symlink support") def test_symlinks(self): with open(self._get_real_path("foo"), "wb") as f: f.write(b"foobar") @@ -131,3 +133,12 @@ bar_info = self.fs.getinfo("bar", namespaces=["link", "lstat"]) self.assertIn("link", bar_info.raw) self.assertIn("lstat", bar_info.raw) + + def test_validatepath(self): + """Check validatepath detects bad encodings.""" + + with mock.patch("fs.osfs.fsencode") as fsencode: + fsencode.side_effect = lambda error: "–".encode("ascii") + with self.assertRaises(errors.InvalidCharsInPath): + with self.fs.open("13 – Marked Register.pdf", "wb") as fh: + fh.write(b"foo") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_tarfs.py new/fs-2.4.4/tests/test_tarfs.py --- old/fs-2.2.1/tests/test_tarfs.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/tests/test_tarfs.py 2019-02-23 10:58:23.000000000 +0100 @@ -26,6 +26,7 @@ class TestWriteReadTarFS(unittest.TestCase): def setUp(self): fh, self._temp_path = tempfile.mkstemp() + os.close(fh) def tearDown(self): os.remove(self._temp_path) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_walk.py new/fs-2.4.4/tests/test_walk.py --- old/fs-2.2.1/tests/test_walk.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/tests/test_walk.py 2019-02-15 16:03:01.000000000 +0100 @@ -63,6 +63,22 @@ ] self.assertEqual(_walk, expected) + def test_walk_filter_dirs(self): + _walk = [] + for step in self.fs.walk(filter_dirs=["foo*"]): + self.assertIsInstance(step, walk.Step) + path, dirs, files = step + _walk.append( + (path, [info.name for info in dirs], [info.name for info in files]) + ) + expected = [ + ("/", ["foo1", "foo2", "foo3"], []), + ("/foo1", [], ["top1.txt", "top2.txt"]), + ("/foo2", [], ["top3.bin"]), + ("/foo3", [], []), + ] + self.assertEqual(_walk, expected) + def test_walk_depth(self): _walk = [] for step in self.fs.walk(search="depth"): @@ -193,6 +209,19 @@ self.assertEqual(files, []) + def test_walk_files_exclude(self): + # Test exclude argument works + files = list(self.fs.walk.files(exclude=["*.txt"])) + self.assertEqual(files, ["/foo2/top3.bin"]) + + # Test exclude doesn't break filter + files = list(self.fs.walk.files(filter=["*.bin"], exclude=["*.txt"])) + self.assertEqual(files, ["/foo2/top3.bin"]) + + # Test excluding everything + files = list(self.fs.walk.files(exclude=["*"])) + self.assertEqual(files, []) + def test_walk_info(self): walk = [] for path, info in self.fs.walk.info(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fs-2.2.1/tests/test_zipfs.py new/fs-2.4.4/tests/test_zipfs.py --- old/fs-2.2.1/tests/test_zipfs.py 2019-01-06 13:13:51.000000000 +0100 +++ new/fs-2.4.4/tests/test_zipfs.py 2019-02-23 10:58:23.000000000 +0100 @@ -22,6 +22,7 @@ class TestWriteReadZipFS(unittest.TestCase): def setUp(self): fh, self._temp_path = tempfile.mkstemp() + os.close(fh) def tearDown(self): os.remove(self._temp_path)
