From 29a9e64e0ea7b3b0246c930a58da232fd8ead4a1 Mon Sep 17 00:00:00 2001 From: Diego Argueta Date: Sat, 7 Sep 2019 07:53:57 -0700 Subject: [PATCH] Add flake8 linting (#351) * Remove unused imports, fix line lengths * Fix JSON exception catching * Add linting tools * More linting * Fix broken/extra imports, long lines, unused variables * Fix hasattr/getattr confusion * Remove unused loop variables, fix comprehensions * Update CHANGELOG * Move tool configs to setup.cfg with the rest --- .travis.yml | 3 +++ CHANGELOG.md | 7 +++++- fs/_bulk.py | 7 +++--- fs/_fscompat.py | 2 -- fs/_repr.py | 2 +- fs/_typing.py | 2 +- fs/_url_tools.py | 5 +++-- fs/appfs.py | 2 +- fs/base.py | 7 +++--- fs/compress.py | 4 ++-- fs/copy.py | 3 +-- fs/error_tools.py | 14 ++++++------ fs/errors.py | 2 +- fs/filesize.py | 5 +++-- fs/ftpfs.py | 19 ++++++++++------ fs/glob.py | 7 +++--- fs/info.py | 18 +++++++-------- fs/iotools.py | 5 ++--- fs/memoryfs.py | 18 +++++++-------- fs/mirror.py | 3 +-- fs/mode.py | 4 ++-- fs/mountfs.py | 2 +- fs/move.py | 2 +- fs/multifs.py | 2 +- fs/opener/appfs.py | 2 +- fs/opener/base.py | 4 ++-- fs/opener/ftpfs.py | 10 ++++----- fs/opener/memoryfs.py | 4 ++-- fs/opener/osfs.py | 4 ++-- fs/opener/parse.py | 2 +- fs/opener/registry.py | 6 +---- fs/opener/tarfs.py | 4 ++-- fs/opener/tempfs.py | 4 ++-- fs/opener/zipfs.py | 4 ++-- fs/osfs.py | 13 +++++------ fs/path.py | 4 ++-- fs/permissions.py | 4 ++-- fs/subfs.py | 4 ++-- fs/tarfs.py | 12 +++++----- fs/tempfs.py | 2 +- fs/test.py | 10 ++++----- fs/tools.py | 3 +-- fs/tree.py | 2 +- fs/walk.py | 2 +- fs/wildcard.py | 5 ++--- fs/wrap.py | 6 ++--- fs/wrapfs.py | 5 +---- fs/zipfs.py | 4 ++-- setup.cfg | 17 ++++++++++++++ tests/test_archives.py | 1 - tests/test_copy.py | 4 +--- tests/test_errors.py | 2 +- tests/test_ftpfs.py | 51 ++++++++++++++++++++++++++++++------------ tests/test_opener.py | 2 +- tests/test_path.py | 26 +++++++++++++++++++-- tests/test_tarfs.py | 4 ++-- tests/test_tree.py | 1 + tox.ini | 13 ++++++++++- 58 files changed, 227 insertions(+), 159 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1e19a196..8d584b1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,9 @@ matrix: - name: "Type checking" python: "3.7" env: TOXENV=typecheck + - name: 'Lint' + python: '3.7' + env: TOXENV=lint before_install: - pip install -U tox tox-travis diff --git a/CHANGELOG.md b/CHANGELOG.md index 6967df4f..f423301e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,12 +23,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fixed abstract class import from `collections` which would break on Python 3.8 - Fixed incorrect imports of `mock` on Python 3 - Removed some unused imports and unused `requirements.txt` file -- Added mypy checks to Travis +- Added mypy checks to Travis. Closes [#332](https://github.com/PyFilesystem/pyfilesystem2/issues/332). - Fixed missing `errno.ENOTSUP` on PyPy. Closes [#338](https://github.com/PyFilesystem/pyfilesystem2/issues/338). +- Fixed bug in a decorator that would trigger an `AttributeError` when a class + was created that implemented a deprecated method and had no docstring of its + own. ### Changed - Entire test suite has been migrated to [pytest](https://docs.pytest.org/en/latest/). Closes [#327](https://github.com/PyFilesystem/pyfilesystem2/issues/327). +- Style checking is now enforced using `flake8`; this involved some code cleanup + such as removing unused imports. ## [2.4.10] - 2019-07-29 diff --git a/fs/_bulk.py b/fs/_bulk.py index a11069e8..9b0b8b79 100644 --- a/fs/_bulk.py +++ b/fs/_bulk.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals import threading +import typing from six.moves.queue import Queue @@ -14,10 +15,10 @@ from .errors import BulkCopyFailed from .tools import copy_file_data -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from .base import FS from types import TracebackType - from typing import IO, Iterator, List, Optional, Mapping, Text, Type, Union + from typing import IO, List, Optional, Text, Type class _Worker(threading.Thread): @@ -96,7 +97,7 @@ def start(self): def stop(self): """Stop the workers (will block until they are finished).""" if self.running and self.num_workers: - for worker in self.workers: + for _worker in self.workers: self.queue.put(None) for worker in self.workers: worker.join() diff --git a/fs/_fscompat.py b/fs/_fscompat.py index ca7f5431..de59fa29 100644 --- a/fs/_fscompat.py +++ b/fs/_fscompat.py @@ -1,5 +1,3 @@ -import sys - import six try: diff --git a/fs/_repr.py b/fs/_repr.py index af51c28a..0a207207 100644 --- a/fs/_repr.py +++ b/fs/_repr.py @@ -5,7 +5,7 @@ import typing -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text, Tuple diff --git a/fs/_typing.py b/fs/_typing.py index 47d6c9b1..7c1f2275 100644 --- a/fs/_typing.py +++ b/fs/_typing.py @@ -12,7 +12,7 @@ if _PY.major == 3 and _PY.minor == 5 and _PY.micro in (0, 1): - def overload(func): # pragma: no cover + def overload(func): # pragma: no cover # noqa: F811 return func diff --git a/fs/_url_tools.py b/fs/_url_tools.py index 4c6fd73f..64c58bd6 100644 --- a/fs/_url_tools.py +++ b/fs/_url_tools.py @@ -1,9 +1,10 @@ import re import six import platform +import typing -if False: # typing.TYPE_CHECKING - from typing import Text, Union, BinaryIO +if typing.TYPE_CHECKING: + from typing import Text _WINDOWS_PLATFORM = platform.system() == "Windows" diff --git a/fs/appfs.py b/fs/appfs.py index 0657faf5..dafe2e98 100644 --- a/fs/appfs.py +++ b/fs/appfs.py @@ -15,7 +15,7 @@ from ._repr import make_repr from appdirs import AppDirs -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Optional, Text diff --git a/fs/base.py b/fs/base.py index fae7ce12..a4b7aefb 100644 --- a/fs/base.py +++ b/fs/base.py @@ -28,7 +28,7 @@ from .time import datetime_to_epoch from .walk import Walker -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from datetime import datetime from threading import RLock from typing import ( @@ -84,7 +84,7 @@ def _method(*args, **kwargs): """.format( method.__name__ ) - if getattr(_method, "__doc__"): + if hasattr(_method, "__doc__"): _method.__doc__ += deprecated_msg return _method @@ -1624,7 +1624,8 @@ def hash(self, path, name): Arguments: path(str): A path on the filesystem. - name(str): One of the algorithms supported by the hashlib module, e.g. `"md5"` + name(str): + One of the algorithms supported by the hashlib module, e.g. `"md5"` Returns: str: The hex digest of the hash. diff --git a/fs/compress.py b/fs/compress.py index cf0f130a..2110403b 100644 --- a/fs/compress.py +++ b/fs/compress.py @@ -22,8 +22,8 @@ from .errors import NoSysPath, MissingInfoNamespace from .walk import Walker -if False: # typing.TYPE_CHECKING - from typing import BinaryIO, Optional, Text, Tuple, Type, Union +if typing.TYPE_CHECKING: + from typing import BinaryIO, Optional, Text, Tuple, Union from .base import FS ZipTime = Tuple[int, int, int, int, int, int] diff --git a/fs/copy.py b/fs/copy.py index 9b171d32..80fcdc6b 100644 --- a/fs/copy.py +++ b/fs/copy.py @@ -11,10 +11,9 @@ from .tools import is_thread_safe from .walk import Walker -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Callable, Optional, Text, Union from .base import FS - from .walk import Walker _OnCopy = Callable[[FS, Text, FS, Text], object] diff --git a/fs/error_tools.py b/fs/error_tools.py index f3fa7194..28c200bf 100644 --- a/fs/error_tools.py +++ b/fs/error_tools.py @@ -4,24 +4,24 @@ from __future__ import print_function from __future__ import unicode_literals -import collections import errno import platform import sys +import typing from contextlib import contextmanager -from six import reraise, PY3 +from six import reraise from . import errors -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from types import TracebackType - from typing import Iterator, Optional, Mapping, Text, Type, Union + from typing import Iterator, Optional, Text, Type, Union -if PY3: +try: from collections.abc import Mapping -else: - from collections import Mapping +except ImportError: + from collections import Mapping # noqa: E811 _WINDOWS_PLATFORM = platform.system() == "Windows" diff --git a/fs/errors.py b/fs/errors.py index e5452e06..b70b62e3 100644 --- a/fs/errors.py +++ b/fs/errors.py @@ -17,7 +17,7 @@ import six from six import text_type -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Optional, Text diff --git a/fs/filesize.py b/fs/filesize.py index ff2ecf63..a80fd9e1 100644 --- a/fs/filesize.py +++ b/fs/filesize.py @@ -16,7 +16,7 @@ import typing -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Iterable, SupportsInt, Text @@ -34,7 +34,8 @@ def _to_str(size, suffixes, base): elif size < base: return "{:,} bytes".format(size) - for i, suffix in enumerate(suffixes, 2): + # TODO (dargueta): Don't rely on unit or suffix being defined in the loop. + for i, suffix in enumerate(suffixes, 2): # noqa: B007 unit = base ** i if size < unit: break diff --git a/fs/ftpfs.py b/fs/ftpfs.py index 8ee1cb79..11d2c4cc 100644 --- a/fs/ftpfs.py +++ b/fs/ftpfs.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import calendar -import ftplib import io import itertools import socket @@ -36,7 +35,7 @@ from .path import split from . import _ftp_parse as ftp_parse -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: import ftplib from typing import ( Any, @@ -45,7 +44,6 @@ ContextManager, Iterable, Iterator, - Collection, Container, Dict, List, @@ -103,7 +101,7 @@ def manage_ftp(ftp): finally: try: ftp.quit() - except: # pragma: no cover + except Exception: # pragma: no cover pass @@ -442,8 +440,15 @@ def _manage_ftp(self): def ftp_url(self): # type: () -> Text """Get the FTP url this filesystem will open.""" - _host_part = self.host if self.port == 21 else "{}:{}".format(self.host, self.port) - _user_part = "" if self.user == "anonymous" or self.user is None else "{}:{}@".format(self.user, self.passwd) + if self.port == 21: + _host_part = self.host + else: + _host_part = "{}:{}".format(self.host, self.port) + + if self.user == "anonymous" or self.user is None: + _user_part = "" + else: + _user_part = "{}:{}@".format(self.user, self.passwd) url = "ftp://{}{}".format(_user_part, _host_part) return url @@ -575,7 +580,7 @@ def _parse_mlsx(cls, lines): details["created"] = cls._parse_ftp_time(facts["create"]) yield raw_info - if False: # typing.TYPE_CHECKING + if typing.TYPE_CHECKING: def opendir(self, path, factory=None): # type: (_F, Text, Optional[_OpendirFactory]) -> SubFS[_F] diff --git a/fs/glob.py b/fs/glob.py index bff4790f..ac12125e 100644 --- a/fs/glob.py +++ b/fs/glob.py @@ -1,8 +1,8 @@ from __future__ import unicode_literals from collections import namedtuple -from typing import Iterator, List import re +import typing from .lrucache import LRUCache from ._repr import make_repr @@ -14,10 +14,9 @@ Counts = namedtuple("Counts", ["files", "directories", "data"]) LineCounts = namedtuple("LineCounts", ["lines", "non_blank"]) -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Iterator, List, Optional, Pattern, Text, Tuple from .base import FS - from .info import Info _PATTERN_CACHE = LRUCache( @@ -180,7 +179,7 @@ def count(self): directories = 0 files = 0 data = 0 - for path, info in self._make_iter(namespaces=["details"]): + for _path, info in self._make_iter(namespaces=["details"]): if info.is_dir: directories += 1 else: diff --git a/fs/info.py b/fs/info.py index 194dd48f..13f7b17f 100644 --- a/fs/info.py +++ b/fs/info.py @@ -18,7 +18,7 @@ from .time import epoch_to_datetime from ._typing import overload, Text -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from datetime import datetime from typing import Any, Callable, List, Mapping, Optional, Union @@ -69,16 +69,16 @@ def __eq__(self, other): return self.raw == getattr(other, "raw", None) @overload - def _make_datetime(self, t): # pragma: no cover + def _make_datetime(self, t): # type: (None) -> None pass - @overload - def _make_datetime(self, t): # pragma: no cover + @overload # noqa: F811 + def _make_datetime(self, t): # type: (int) -> datetime pass - def _make_datetime(self, t): + def _make_datetime(self, t): # noqa: F811 # type: (Optional[int]) -> Optional[datetime] if t is not None: return self._to_datetime(t) @@ -86,16 +86,16 @@ def _make_datetime(self, t): return None @overload - def get(self, namespace, key): # pragma: no cover + def get(self, namespace, key): # type: (Text, Text) -> Any pass - @overload - def get(self, namespace, key, default): # pragma: no cover + @overload # noqa: F811 + def get(self, namespace, key, default): # type: (Text, Text, T) -> Union[Any, T] pass - def get(self, namespace, key, default=None): + def get(self, namespace, key, default=None): # noqa: F811 # type: (Text, Text, Optional[Any]) -> Optional[Any] """Get a raw info value. diff --git a/fs/iotools.py b/fs/iotools.py index 87e6997a..26402ff3 100644 --- a/fs/iotools.py +++ b/fs/iotools.py @@ -10,11 +10,10 @@ from .mode import Mode -if False: # typing.TYPE_CHECKING - from io import RawIOBase, IOBase +if typing.TYPE_CHECKING: + from io import RawIOBase from typing import ( Any, - BinaryIO, Iterable, Iterator, IO, diff --git a/fs/memoryfs.py b/fs/memoryfs.py index dcc03050..0814b2e0 100644 --- a/fs/memoryfs.py +++ b/fs/memoryfs.py @@ -23,7 +23,7 @@ from .path import split from ._typing import overload -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, BinaryIO, @@ -228,22 +228,22 @@ def size(self): _bytes_file.seek(0, os.SEEK_END) return _bytes_file.tell() - @overload - def get_entry(self, name, default): # pragma: no cover + @overload # noqa: F811 + def get_entry(self, name, default): # type: (Text, _DirEntry) -> _DirEntry pass - @overload - def get_entry(self, name): # pragma: no cover + @overload # noqa: F811 + def get_entry(self, name): # type: (Text) -> Optional[_DirEntry] pass - @overload - def get_entry(self, name, default): # pragma: no cover + @overload # noqa: F811 + def get_entry(self, name, default): # type: (Text, None) -> Optional[_DirEntry] pass - def get_entry(self, name, default=None): + def get_entry(self, name, default=None): # noqa: F811 # type: (Text, Optional[_DirEntry]) -> Optional[_DirEntry] assert self.is_dir, "must be a directory" return self._dir.get(name, default) @@ -377,7 +377,7 @@ def listdir(self, path): raise errors.DirectoryExpected(path) return dir_entry.list() - if False: # typing.TYPE_CHECKING + if typing.TYPE_CHECKING: def opendir(self, path, factory=None): # type: (_M, Text, Optional[_OpendirFactory]) -> SubFS[_M] diff --git a/fs/mirror.py b/fs/mirror.py index 98f3d5f1..ceb8ccd3 100644 --- a/fs/mirror.py +++ b/fs/mirror.py @@ -19,7 +19,6 @@ from __future__ import print_function from __future__ import unicode_literals -from contextlib import contextmanager import typing from ._bulk import Copier @@ -29,7 +28,7 @@ from .tools import is_thread_safe from .walk import Walker -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Callable, Optional, Text, Union from .base import FS from .info import Info diff --git a/fs/mode.py b/fs/mode.py index 76b665d6..5e8c795d 100644 --- a/fs/mode.py +++ b/fs/mode.py @@ -15,8 +15,8 @@ from ._typing import Text -if False: # typing.TYPE_CHECKING - from typing import Container, FrozenSet, Set, Union +if typing.TYPE_CHECKING: + from typing import FrozenSet, Set, Union __all__ = ["Mode", "check_readable", "check_writable", "validate_openbin_mode"] diff --git a/fs/mountfs.py b/fs/mountfs.py index aa314ed5..d51d7d9d 100644 --- a/fs/mountfs.py +++ b/fs/mountfs.py @@ -18,7 +18,7 @@ from .mode import validate_open_mode from .mode import validate_openbin_mode -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, BinaryIO, diff --git a/fs/move.py b/fs/move.py index 5da6b82d..4f6fc2ab 100644 --- a/fs/move.py +++ b/fs/move.py @@ -10,7 +10,7 @@ from .copy import copy_file from .opener import manage_fs -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from .base import FS from typing import Text, Union diff --git a/fs/multifs.py b/fs/multifs.py index 60a3ad40..e68d2c00 100644 --- a/fs/multifs.py +++ b/fs/multifs.py @@ -17,7 +17,7 @@ from .opener import open_fs from .path import abspath, normpath -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, BinaryIO, diff --git a/fs/opener/appfs.py b/fs/opener/appfs.py index 93cffef0..fccf603e 100644 --- a/fs/opener/appfs.py +++ b/fs/opener/appfs.py @@ -12,7 +12,7 @@ from .registry import registry from .errors import OpenerError -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text, Union from .parse import ParseResult from ..appfs import _AppFS diff --git a/fs/opener/base.py b/fs/opener/base.py index 952eea53..cd970399 100644 --- a/fs/opener/base.py +++ b/fs/opener/base.py @@ -7,8 +7,8 @@ import six -if False: # typing.TYPE_CHECKING - from typing import List, Text, Union +if typing.TYPE_CHECKING: + from typing import List, Text from ..base import FS from .parse import ParseResult diff --git a/fs/opener/ftpfs.py b/fs/opener/ftpfs.py index 4c30c962..f5beab21 100644 --- a/fs/opener/ftpfs.py +++ b/fs/opener/ftpfs.py @@ -6,17 +6,15 @@ from __future__ import print_function from __future__ import unicode_literals -import six - import typing from .base import Opener from .registry import registry -from ..errors import FSError, CreateFailed +from ..errors import CreateFailed -if False: # typing.TYPE_CHECKING - from typing import List, Text, Union - from ..ftpfs import FTPFS +if typing.TYPE_CHECKING: + from typing import Text, Union + from ..ftpfs import FTPFS # noqa: F401 from ..subfs import SubFS from .parse import ParseResult diff --git a/fs/opener/memoryfs.py b/fs/opener/memoryfs.py index 8b8976c3..696ee06a 100644 --- a/fs/opener/memoryfs.py +++ b/fs/opener/memoryfs.py @@ -11,10 +11,10 @@ from .base import Opener from .registry import registry -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text from .parse import ParseResult - from ..memoryfs import MemoryFS + from ..memoryfs import MemoryFS # noqa: F401 @registry.install diff --git a/fs/opener/osfs.py b/fs/opener/osfs.py index 986de249..00cb63ee 100644 --- a/fs/opener/osfs.py +++ b/fs/opener/osfs.py @@ -11,10 +11,10 @@ from .base import Opener from .registry import registry -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text from .parse import ParseResult - from ..osfs import OSFS + from ..osfs import OSFS # noqa: F401 @registry.install diff --git a/fs/opener/parse.py b/fs/opener/parse.py index 61f99f2c..e9423807 100644 --- a/fs/opener/parse.py +++ b/fs/opener/parse.py @@ -14,7 +14,7 @@ from .errors import ParseError -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Optional, Text diff --git a/fs/opener/registry.py b/fs/opener/registry.py index 0ed74339..50f2976c 100644 --- a/fs/opener/registry.py +++ b/fs/opener/registry.py @@ -10,20 +10,18 @@ import contextlib import typing -import six import pkg_resources from .base import Opener from .errors import UnsupportedProtocol, EntryPointError from .parse import parse_fs_url -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Callable, Dict, Iterator, List, - Optional, Text, Type, Tuple, @@ -279,8 +277,6 @@ def manage_fs( _fs = self.open_fs(fs_url, create=create, writeable=writeable, cwd=cwd) try: yield _fs - except: - raise finally: _fs.close() diff --git a/fs/opener/tarfs.py b/fs/opener/tarfs.py index 867ca80f..3ff91f55 100644 --- a/fs/opener/tarfs.py +++ b/fs/opener/tarfs.py @@ -12,10 +12,10 @@ from .registry import registry from .errors import NotWriteable -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text from .parse import ParseResult - from ..tarfs import TarFS + from ..tarfs import TarFS # noqa: F401 @registry.install diff --git a/fs/opener/tempfs.py b/fs/opener/tempfs.py index 5fe47a08..ffa17983 100644 --- a/fs/opener/tempfs.py +++ b/fs/opener/tempfs.py @@ -11,10 +11,10 @@ from .base import Opener from .registry import registry -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text from .parse import ParseResult - from ..tempfs import TempFS + from ..tempfs import TempFS # noqa: F401 @registry.install diff --git a/fs/opener/zipfs.py b/fs/opener/zipfs.py index 714fe384..81e48455 100644 --- a/fs/opener/zipfs.py +++ b/fs/opener/zipfs.py @@ -12,10 +12,10 @@ from .registry import registry from .errors import NotWriteable -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Text from .parse import ParseResult - from ..zipfs import ZipFS + from ..zipfs import ZipFS # noqa: F401 @registry.install diff --git a/fs/osfs.py b/fs/osfs.py index 2a711bd7..ec68d0ad 100644 --- a/fs/osfs.py +++ b/fs/osfs.py @@ -50,11 +50,10 @@ from .errors import FileExpected, NoURL from ._url_tools import url_quote -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, BinaryIO, - Callable, Collection, Dict, Iterator, @@ -151,7 +150,8 @@ def __init__( try: # https://stackoverflow.com/questions/7870041/check-if-file-system-is-case-insensitive-in-python - # I don't know of a better way of detecting case insensitivity of a filesystem + # I don't know of a better way of detecting case insensitivity of a + # filesystem with tempfile.NamedTemporaryFile(prefix="TmP") as _tmp_file: _meta["case_insensitive"] = os.path.exists(_tmp_file.name.lower()) except Exception: @@ -396,7 +396,7 @@ def removedir(self, path): # --- Type hint for opendir ------------------------------ - if False: # typing.TYPE_CHECKING + if typing.TYPE_CHECKING: def opendir(self, path, factory=None): # type: (_O, Text, Optional[_OpendirFactory]) -> SubFS[_O] @@ -672,8 +672,7 @@ def validatepath(self, 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 - ), + 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 --git a/fs/path.py b/fs/path.py index 3783dd13..49f04bd6 100644 --- a/fs/path.py +++ b/fs/path.py @@ -16,7 +16,7 @@ from .errors import IllegalBackReference -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import List, Text, Tuple @@ -68,7 +68,7 @@ def normpath(path): ... IllegalBackReference: path 'foo/../../bar' contains back-references outside of filesystem" - """ + """ # noqa: E501 if path in "/": return path diff --git a/fs/permissions.py b/fs/permissions.py index 7c8b2030..19934465 100644 --- a/fs/permissions.py +++ b/fs/permissions.py @@ -5,14 +5,14 @@ from __future__ import unicode_literals import typing -from typing import Container, Iterable +from typing import Iterable import six from ._typing import Text -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Iterator, List, Optional, Tuple, Type, Union diff --git a/fs/subfs.py b/fs/subfs.py index d0d0d386..7172008e 100644 --- a/fs/subfs.py +++ b/fs/subfs.py @@ -11,9 +11,9 @@ from .wrapfs import WrapFS from .path import abspath, join, normpath, relpath -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: + from .base import FS # noqa: F401 from typing import Text, Tuple - from .base import FS _F = typing.TypeVar("_F", bound="FS", covariant=True) diff --git a/fs/tarfs.py b/fs/tarfs.py index 250291a1..20073c9d 100644 --- a/fs/tarfs.py +++ b/fs/tarfs.py @@ -20,16 +20,15 @@ from .info import Info from .iotools import RawWrapper from .opener import open_fs -from .path import relpath, basename, isbase, normpath, parts, frombase -from .wrapfs import WrapFS from .permissions import Permissions from ._url_tools import url_quote +from .path import relpath, basename, isbase, normpath, parts, frombase +from .wrapfs import WrapFS -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from tarfile import TarInfo from typing import ( Any, - AnyStr, BinaryIO, Collection, Dict, @@ -39,8 +38,7 @@ Tuple, Union, ) - from .info import Info, RawInfo - from .permissions import Permissions + from .info import RawInfo from .subfs import SubFS T = typing.TypeVar("T", bound="ReadTarFS") @@ -143,7 +141,7 @@ def __new__( else: return ReadTarFS(file, encoding=encoding) - if False: # typing.TYPE_CHECKING + if typing.TYPE_CHECKING: def __init__( self, diff --git a/fs/tempfs.py b/fs/tempfs.py index 293a692e..748463c1 100644 --- a/fs/tempfs.py +++ b/fs/tempfs.py @@ -21,7 +21,7 @@ from . import errors from .osfs import OSFS -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import Optional, Text diff --git a/fs/test.py b/fs/test.py index 31271b6c..146938a8 100644 --- a/fs/test.py +++ b/fs/test.py @@ -485,8 +485,8 @@ def test_getinfo(self): # Raw info should be serializable try: json.dumps(info) - except: - assert False, "info should be JSON serializable" + except (TypeError, ValueError): + raise AssertionError("info should be JSON serializable") # Non existant namespace is not an error no_info = self.fs.getinfo("foo", "__nosuchnamespace__").raw @@ -1286,7 +1286,7 @@ def test_desc(self): def test_scandir(self): # Check exception for scanning dir that doesn't exist with self.assertRaises(errors.ResourceNotFound): - for info in self.fs.scandir("/foobar"): + for _info in self.fs.scandir("/foobar"): pass # Check scandir returns an iterable @@ -1307,7 +1307,7 @@ def test_scandir(self): self.assertTrue(isinstance(iter_scandir, collections_abc.Iterable)) scandir = sorted( - [r.raw for r in iter_scandir], key=lambda info: info["basic"]["name"] + (r.raw for r in iter_scandir), key=lambda info: info["basic"]["name"] ) # Filesystems may send us more than we ask for @@ -1337,7 +1337,7 @@ def test_scandir(self): self.assertEqual(len(page2), 1) page3 = list(self.fs.scandir("/", page=(4, 6))) self.assertEqual(len(page3), 0) - paged = set(r.name for r in itertools.chain(page1, page2)) + paged = {r.name for r in itertools.chain(page1, page2)} self.assertEqual(paged, {"foo", "bar", "dir"}) def test_filterdir(self): diff --git a/fs/tools.py b/fs/tools.py index 4b842029..8a16d289 100644 --- a/fs/tools.py +++ b/fs/tools.py @@ -4,7 +4,6 @@ from __future__ import print_function from __future__ import unicode_literals -import io import typing from . import errors @@ -15,7 +14,7 @@ from .path import normpath from .path import recursepath -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import IO, List, Optional, Text from .base import FS diff --git a/fs/tree.py b/fs/tree.py index a10beca9..faee5472 100644 --- a/fs/tree.py +++ b/fs/tree.py @@ -12,7 +12,7 @@ from fs.path import abspath, join, normpath -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import List, Optional, Text, TextIO, Tuple from .base import FS from .info import Info diff --git a/fs/walk.py b/fs/walk.py index 11dd88c7..3e44537d 100644 --- a/fs/walk.py +++ b/fs/walk.py @@ -18,7 +18,7 @@ from .path import combine from .path import normpath -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, Callable, diff --git a/fs/wildcard.py b/fs/wildcard.py index b9f58591..6c710cad 100644 --- a/fs/wildcard.py +++ b/fs/wildcard.py @@ -9,10 +9,9 @@ from functools import partial from .lrucache import LRUCache -from . import path -if False: # typing.TYPE_CHECKING - from typing import Callable, Iterable, MutableMapping, Text, Tuple, Pattern +if typing.TYPE_CHECKING: + from typing import Callable, Iterable, Text, Tuple, Pattern _PATTERN_CACHE = LRUCache(1000) # type: LRUCache[Tuple[Text, bool], Pattern] diff --git a/fs/wrap.py b/fs/wrap.py index d8aa7054..7026bcbc 100644 --- a/fs/wrap.py +++ b/fs/wrap.py @@ -24,7 +24,7 @@ from .info import Info from .mode import check_writable -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from datetime import datetime from typing import ( Any, @@ -37,8 +37,8 @@ Text, Tuple, ) - from .base import FS - from .info import Info, RawInfo + from .base import FS # noqa: F401 + from .info import RawInfo from .subfs import SubFS from .permissions import Permissions diff --git a/fs/wrapfs.py b/fs/wrapfs.py index 6565a4ce..c09e9cf3 100644 --- a/fs/wrapfs.py +++ b/fs/wrapfs.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals -import copy import typing import six @@ -16,7 +15,7 @@ from .path import abspath, normpath from .error_tools import unwrap_errors -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from datetime import datetime from threading import RLock from typing import ( @@ -25,7 +24,6 @@ BinaryIO, Callable, Collection, - Dict, Iterator, Iterable, IO, @@ -33,7 +31,6 @@ Mapping, Optional, Text, - TextIO, Tuple, Union, ) diff --git a/fs/zipfs.py b/fs/zipfs.py index c347731c..1eefcf6b 100644 --- a/fs/zipfs.py +++ b/fs/zipfs.py @@ -24,7 +24,7 @@ from .wrapfs import WrapFS from ._url_tools import url_quote -if False: # typing.TYPE_CHECKING +if typing.TYPE_CHECKING: from typing import ( Any, BinaryIO, @@ -181,7 +181,7 @@ def __new__( else: return ReadZipFS(file, encoding=encoding) - if False: # typing.TYPE_CHECKING + if typing.TYPE_CHECKING: def __init__( self, diff --git a/setup.cfg b/setup.cfg index 230c6017..a207101e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,7 +45,24 @@ exclude_lines = pragma: no cover if False: @typing.overload + @overload [tool:pytest] markers = slow: marks tests as slow (deselect with '-m "not slow"') + +[flake8] +extend-ignore = E203,E402,W503 +max-line-length = 88 +per-file-ignores = + fs/__init__.py:F401 + fs/*/__init__.py:F401 + tests/*:E501 + fs/opener/*:F811 + fs/_fscompat.py:F401 + +[isort] +default_section = THIRD_PARTY +known_first_party = fs +known_standard_library = typing +line_length = 88 diff --git a/tests/test_archives.py b/tests/test_archives.py index c0bfff3b..0740e455 100644 --- a/tests/test_archives.py +++ b/tests/test_archives.py @@ -10,7 +10,6 @@ from fs.enums import ResourceType from fs import walk from fs import errors -from fs.memoryfs import MemoryFS from fs.test import UNICODE_TEXT diff --git a/tests/test_copy.py b/tests/test_copy.py index 160820fa..63e550e9 100644 --- a/tests/test_copy.py +++ b/tests/test_copy.py @@ -8,8 +8,6 @@ import shutil import calendar -from six import PY2 - import fs.copy from fs import open_fs @@ -356,7 +354,7 @@ def test_copy_dir_if_newer_same_fs(self): src_file1 = self._touch(src_dir, "src" + os.sep + "file1.txt") self._write_file(src_file1) - dst_dir = self._create_sandbox_dir(home=src_dir) + self._create_sandbox_dir(home=src_dir) src_fs = open_fs("osfs://" + src_dir) diff --git a/tests/test_errors.py b/tests/test_errors.py index 0b78fd15..1ed98c54 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -56,7 +56,7 @@ def test_catch_all(self): def test(x): raise errors[x] - for index, exc in enumerate(errors): + for index, _exc in enumerate(errors): try: test(index) except Exception as e: diff --git a/tests/test_ftpfs.py b/tests/test_ftpfs.py index 139bc059..7207e9e9 100644 --- a/tests/test_ftpfs.py +++ b/tests/test_ftpfs.py @@ -124,7 +124,9 @@ def test_manager_with_host(self): with self.assertRaises(errors.RemoteConnectionError) as err_info: with ftp_errors(mem_fs): raise socket.error - self.assertEqual(str(err_info.exception), "unable to connect to ftp.example.com") + self.assertEqual( + str(err_info.exception), "unable to connect to ftp.example.com" + ) @pytest.mark.slow @@ -178,20 +180,34 @@ def tearDown(self): super(TestFTPFS, self).tearDown() def test_ftp_url(self): - self.assertEqual(self.fs.ftp_url, "ftp://{}:{}@{}:{}".format(self.user, self.pasw, self.server.host, self.server.port)) + self.assertEqual( + self.fs.ftp_url, + "ftp://{}:{}@{}:{}".format( + self.user, self.pasw, self.server.host, self.server.port + ), + ) def test_geturl(self): self.fs.makedir("foo") self.fs.create("bar") self.fs.create("foo/bar") self.assertEqual( - self.fs.geturl('foo'), "ftp://{}:{}@{}:{}/foo".format(self.user, self.pasw, self.server.host, self.server.port) + self.fs.geturl("foo"), + "ftp://{}:{}@{}:{}/foo".format( + self.user, self.pasw, self.server.host, self.server.port + ), ) self.assertEqual( - self.fs.geturl('bar'), "ftp://{}:{}@{}:{}/bar".format(self.user, self.pasw, self.server.host, self.server.port) + self.fs.geturl("bar"), + "ftp://{}:{}@{}:{}/bar".format( + self.user, self.pasw, self.server.host, self.server.port + ), ) self.assertEqual( - self.fs.geturl('foo/bar'), "ftp://{}:{}@{}:{}/foo/bar".format(self.user, self.pasw, self.server.host, self.server.port) + self.fs.geturl("foo/bar"), + "ftp://{}:{}@{}:{}/foo/bar".format( + self.user, self.pasw, self.server.host, self.server.port + ), ) def test_host(self): @@ -299,11 +315,7 @@ def tearDownClass(cls): super(TestAnonFTPFS, cls).tearDownClass() def make_fs(self): - return open_fs( - "ftp://{}:{}".format( - self.server.host, self.server.port - ) - ) + return open_fs("ftp://{}:{}".format(self.server.host, self.server.port)) def tearDown(self): shutil.rmtree(self._temp_path) @@ -311,12 +323,23 @@ def tearDown(self): super(TestAnonFTPFS, self).tearDown() def test_ftp_url(self): - self.assertEqual(self.fs.ftp_url, "ftp://{}:{}".format(self.server.host, self.server.port)) + self.assertEqual( + self.fs.ftp_url, "ftp://{}:{}".format(self.server.host, self.server.port) + ) def test_geturl(self): self.fs.makedir("foo") self.fs.create("bar") self.fs.create("foo/bar") - self.assertEqual(self.fs.geturl('foo'), "ftp://{}:{}/foo".format(self.server.host, self.server.port)) - self.assertEqual(self.fs.geturl('bar'), "ftp://{}:{}/bar".format(self.server.host, self.server.port)) - self.assertEqual(self.fs.geturl('foo/bar'), "ftp://{}:{}/foo/bar".format(self.server.host, self.server.port)) + self.assertEqual( + self.fs.geturl("foo"), + "ftp://{}:{}/foo".format(self.server.host, self.server.port), + ) + self.assertEqual( + self.fs.geturl("bar"), + "ftp://{}:{}/bar".format(self.server.host, self.server.port), + ) + self.assertEqual( + self.fs.geturl("foo/bar"), + "ftp://{}:{}/foo/bar".format(self.server.host, self.server.port), + ) diff --git a/tests/test_opener.py b/tests/test_opener.py index 11bc26a5..fc450751 100644 --- a/tests/test_opener.py +++ b/tests/test_opener.py @@ -29,7 +29,7 @@ def test_registry_repr(self): def test_parse_not_url(self): with self.assertRaises(errors.ParseError): - parsed = opener.parse("foo/bar") + opener.parse("foo/bar") def test_parse_simple(self): parsed = opener.parse("osfs://foo/bar") diff --git a/tests/test_path.py b/tests/test_path.py index d57c278a..e5969d29 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals, print_function +from __future__ import absolute_import, unicode_literals, print_function """ fstests.test_path: testcases for the fs path functions @@ -8,7 +8,29 @@ import unittest -from fs.path import * +from fs.path import ( + abspath, + basename, + combine, + dirname, + forcedir, + frombase, + isabs, + isbase, + isdotfile, + isparent, + issamedir, + iswildcard, + iteratepath, + join, + normpath, + parts, + recursepath, + relativefrom, + relpath, + split, + splitext, +) class TestPathFunctions(unittest.TestCase): diff --git a/tests/test_tarfs.py b/tests/test_tarfs.py index c3570bdb..a90dc0ea 100644 --- a/tests/test_tarfs.py +++ b/tests/test_tarfs.py @@ -163,13 +163,13 @@ def remove_archive(self): def test_read_from_fileobject(self): try: tarfs.TarFS(open(self._temp_path, "rb")) - except: + except Exception: self.fail("Couldn't open tarfs from fileobject") def test_read_from_filename(self): try: tarfs.TarFS(self._temp_path) - except: + except Exception: self.fail("Couldn't open tarfs from filename") def test_read_non_existent_file(self): diff --git a/tests/test_tree.py b/tests/test_tree.py index 805ae708..2a4f942c 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -1,3 +1,4 @@ +from __future__ import print_function from __future__ import unicode_literals import io diff --git a/tox.ini b/tox.ini index f5a803a9..4a848442 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = {py27,py34,py35,py36,py37}{,-scandir},pypy,typecheck +envlist = {py27,py34,py35,py36,py37}{,-scandir},pypy,typecheck,lint sitepackages = False skip_missing_interpreters=True @@ -14,3 +14,14 @@ deps = -r {toxinidir}/testrequirements.txt commands = make typecheck whitelist_externals = make + +[testenv:lint] +python = python37 +deps = + flake8 + # flake8-builtins + flake8-bugbear + flake8-comprehensions + # flake8-isort + flake8-mutable +commands = flake8 fs tests