diff options
author | mrbean-bremen <mrbean-bremen@users.noreply.github.com> | 2023-05-03 20:36:14 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-03 20:36:14 +0200 |
commit | 33846b5ef3df436e5c23e69beaf496c4511ee254 (patch) | |
tree | e19bf88409dbfa83133a7db9c25f62d9e8e950a9 | |
parent | 0396c996d01d21e4d9ccde9bd1c346894275db08 (diff) | |
download | pyfakefs-33846b5ef3df436e5c23e69beaf496c4511ee254.tar.gz |
Add pytype CI and pytype ignore comments where needed (#824)
- add pytype ignores where needed to silence pytype
- fix a few problems found by pytype
- add pytype run in CI (excluding tests)
-rw-r--r-- | .github/workflows/testsuite.yml | 15 | ||||
-rw-r--r-- | CHANGES.md | 3 | ||||
-rwxr-xr-x | pyfakefs/__init__.py | 2 | ||||
-rw-r--r-- | pyfakefs/fake_file.py | 4 | ||||
-rw-r--r-- | pyfakefs/fake_filesystem.py | 16 | ||||
-rw-r--r-- | pyfakefs/fake_filesystem_unittest.py | 32 | ||||
-rw-r--r-- | pyfakefs/fake_io.py | 2 | ||||
-rw-r--r-- | pyfakefs/fake_open.py | 13 | ||||
-rw-r--r-- | pyfakefs/fake_os.py | 4 | ||||
-rw-r--r-- | pyfakefs/fake_path.py | 3 | ||||
-rw-r--r-- | pyfakefs/fake_pathlib.py | 38 | ||||
-rw-r--r-- | pyfakefs/helpers.py | 4 | ||||
-rw-r--r-- | pyfakefs/mox3_stubout.py | 2 | ||||
-rw-r--r-- | pyfakefs/patched_packages.py | 2 | ||||
-rw-r--r-- | pyfakefs/tests/test_utils.py | 3 |
15 files changed, 91 insertions, 52 deletions
diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 4b4f1aa..d138058 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -4,6 +4,21 @@ on: [push, pull_request] jobs: + pytype: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + - name: install pytype + run: pip install pytype pytest scandir pathlib2 pandas xlrd django + - name: Run pytype + run: | + pytype pyfakefs --keep-going --exclude pyfakefs/tests/* --exclude pyfakefs/pytest_tests/* + tests: runs-on: ${{ matrix.os }} strategy: @@ -7,6 +7,9 @@ The released versions correspond to PyPI releases. * Re-create temp directory if it had been created before on resetting file system (see [#814](../../issues/814)). +### Infrastructure +* Added pytype check for non-test modules in CI (see [#599](../../issues/599)). + ## [Version 5.2.2](https://pypi.python.org/pypi/pyfakefs/5.2.2) (2023-04-13) Fixes a regression in 5.2.0 diff --git a/pyfakefs/__init__.py b/pyfakefs/__init__.py index 3a8d6d5..e8b4e1e 100755 --- a/pyfakefs/__init__.py +++ b/pyfakefs/__init__.py @@ -1 +1 @@ -from ._version import __version__ # noqa: F401 +from pyfakefs._version import __version__ # noqa: F401 diff --git a/pyfakefs/fake_file.py b/pyfakefs/fake_file.py index 0a866b1..82eb2d7 100644 --- a/pyfakefs/fake_file.py +++ b/pyfakefs/fake_file.py @@ -352,7 +352,7 @@ class FakeFile: @property def path(self) -> AnyStr: """Return the full path of the current object.""" - names: List[AnyStr] = [] + names: List[AnyStr] = [] # pytype: disable=invalid-annotation obj: Optional[FakeFile] = self while obj: names.insert(0, matching_string(self.name, obj.name)) # type: ignore @@ -1280,7 +1280,7 @@ class FakePipeWrapper: def read(self, numBytes: int = -1) -> bytes: """Read from the real pipe.""" if self.real_file: - return self.real_file.read(numBytes) + return self.real_file.read(numBytes) # pytype: disable=bad-return-type return os.read(self.fd, numBytes) def flush(self) -> None: diff --git a/pyfakefs/fake_filesystem.py b/pyfakefs/fake_filesystem.py index cacdb9c..9f170d1 100644 --- a/pyfakefs/fake_filesystem.py +++ b/pyfakefs/fake_filesystem.py @@ -550,11 +550,11 @@ class FakeFilesystem: """Return the fake directory object of the mount point where the current working directory points to.""" - def object_from_path(file_path): + def object_from_path(file_path) -> FakeDirectory: path_components = self._path_components(file_path) target = self.root for component in path_components: - target = target.get_entry(component) + target = cast(FakeDirectory, target.get_entry(component)) return target path = to_string(self.cwd) @@ -926,8 +926,12 @@ class FakeFilesystem: drive, path_str = self.splitdrive(path_str) sep = self.get_path_separator(path_str) is_absolute_path = path_str.startswith(sep) - path_components: List[AnyStr] = path_str.split(sep) - collapsed_path_components: List[AnyStr] = [] + path_components: List[AnyStr] = path_str.split( + sep + ) # pytype: disable=invalid-annotation + collapsed_path_components: List[ + AnyStr + ] = [] # pytype: disable=invalid-annotation dot = matching_string(path_str, ".") dotdot = matching_string(path_str, "..") for component in path_components: @@ -1473,7 +1477,7 @@ class FakeFilesystem: resolved_components = self._resolve_components(path_components) path = self._components_to_path(resolved_components) # after resolving links, we have to check again for Windows root - return self.replace_windows_root(path) + return self.replace_windows_root(path) # pytype: disable=bad-return-type def _components_to_path(self, component_folders): sep = ( @@ -1580,7 +1584,7 @@ class FakeFilesystem: link_path = sep.join(components) # Don't call self.NormalizePath(), as we don't want to prepend # self.cwd. - return self.normpath(link_path) + return self.normpath(link_path) # pytype: disable=bad-return-type raise ValueError("Invalid link") def get_object_from_normpath( diff --git a/pyfakefs/fake_filesystem_unittest.py b/pyfakefs/fake_filesystem_unittest.py index 0e18055..ea5edef 100644 --- a/pyfakefs/fake_filesystem_unittest.py +++ b/pyfakefs/fake_filesystem_unittest.py @@ -78,11 +78,7 @@ from pyfakefs.fake_filesystem import ( from pyfakefs.helpers import IS_PYPY from pyfakefs.mox3_stubout import StubOutForTesting -try: - from importlib.machinery import ModuleSpec -except ImportError: - ModuleSpec = object # type: ignore[assignment, misc] - +from importlib.machinery import ModuleSpec from importlib import reload from pyfakefs import fake_filesystem, fake_io, fake_os, fake_open, fake_path, fake_file @@ -677,16 +673,18 @@ class Patcher: # `from os import stat` # each patched function name has to be looked up separately for mod_name, fake_module in self._fake_module_classes.items(): - if hasattr(fake_module, "dir") and inspect.isfunction(fake_module.dir): - for fct_name in fake_module.dir(): - module_attr = (getattr(fake_module, fct_name), mod_name) - self._fake_module_functions.setdefault(fct_name, {})[ - mod_name - ] = module_attr - if mod_name == "os": + if hasattr(fake_module, "dir"): + module_dir = fake_module.dir + if inspect.isfunction(module_dir): + for fct_name in fake_module.dir(): + module_attr = (getattr(fake_module, fct_name), mod_name) self._fake_module_functions.setdefault(fct_name, {})[ - OS_MODULE + mod_name ] = module_attr + if mod_name == "os": + self._fake_module_functions.setdefault(fct_name, {})[ + OS_MODULE + ] = module_attr # special handling for functions in os.path fake_module = fake_filesystem.FakePathModule @@ -909,7 +907,9 @@ class Patcher: for (name, ft_name, ft_mod), modules in self.FS_FUNCTIONS.items(): method, mod_name = self._fake_module_functions[ft_name][ft_mod] fake_module = self.fake_modules[mod_name] - attr = method.__get__(fake_module, fake_module.__class__) + attr = method.__get__( + fake_module, fake_module.__class__ + ) # pytype: disable=attribute-error for module in modules: self._stubs.smart_set(module, name, attr) @@ -927,7 +927,9 @@ class Patcher: for fct, idx, ft in self.FS_DEFARGS: method, mod_name = self._fake_module_functions[ft.__name__][ft.__module__] fake_module = self.fake_modules[mod_name] - attr = method.__get__(fake_module, fake_module.__class__) + attr = method.__get__( + fake_module, fake_module.__class__ + ) # pytype: disable=attribute-error new_defaults = [] assert fct.__defaults__ is not None for i, d in enumerate(fct.__defaults__): diff --git a/pyfakefs/fake_io.py b/pyfakefs/fake_io.py index 0677bd4..2f78230 100644 --- a/pyfakefs/fake_io.py +++ b/pyfakefs/fake_io.py @@ -102,7 +102,7 @@ class FakeIoModule: for sn in self.skip_names ] ): - return io.open( + return io.open( # pytype: disable=wrong-arg-count file, mode, buffering, diff --git a/pyfakefs/fake_open.py b/pyfakefs/fake_open.py index ea6da28..912ada9 100644 --- a/pyfakefs/fake_open.py +++ b/pyfakefs/fake_open.py @@ -283,7 +283,9 @@ class FakeFileOpen: if self.filesystem.islink(file_path): link_object = self.filesystem.resolve(file_path, follow_symlinks=False) assert link_object.contents is not None - target_path = cast(AnyStr, link_object.contents) + target_path = cast( + AnyStr, link_object.contents + ) # pytype: disable=invalid-annotation else: target_path = file_path if self.filesystem.ends_with_path_separator(target_path): @@ -317,10 +319,15 @@ class FakeFileOpen: ) assert file_object is not None path = file_object.name - return file_object, cast(AnyStr, path), filedes, cast(AnyStr, path) + return ( + file_object, + cast(AnyStr, path), # pytype: disable=invalid-annotation + filedes, + cast(AnyStr, path), # pytype: disable=invalid-annotation + ) # open a file file by path - file_path = cast(AnyStr, file_) + file_path = cast(AnyStr, file_) # pytype: disable=invalid-annotation if file_path == self.filesystem.dev_null.name: file_object = self.filesystem.dev_null real_path = file_path diff --git a/pyfakefs/fake_os.py b/pyfakefs/fake_os.py index a28939d..989d5c9 100644 --- a/pyfakefs/fake_os.py +++ b/pyfakefs/fake_os.py @@ -503,7 +503,9 @@ class FakeOsModule: path_str = self.filesystem.cwd if path is None else path file_obj = self.filesystem.resolve( - cast(AnyStr, path_str), follow_symlinks, allow_fd=True + cast(AnyStr, path_str), # pytype: disable=invalid-annotation + follow_symlinks, + allow_fd=True, ) return list(file_obj.xattr.keys()) diff --git a/pyfakefs/fake_path.py b/pyfakefs/fake_path.py index 514fb38..10d6722 100644 --- a/pyfakefs/fake_path.py +++ b/pyfakefs/fake_path.py @@ -35,7 +35,6 @@ from typing import ( TYPE_CHECKING, ) -from pyfakefs import __version__ # noqa: F401 for upwards compatibility from pyfakefs.helpers import ( make_string_path, to_string, @@ -501,7 +500,7 @@ if sys.platform == "win32": Args: filesystem: FakeFilesystem used to provide file system information """ - import nt + import nt # type:ignore[import] self.filesystem = filesystem self.nt_module: Any = nt diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py index 62a3d3c..fbca1bb 100644 --- a/pyfakefs/fake_pathlib.py +++ b/pyfakefs/fake_pathlib.py @@ -90,12 +90,12 @@ def _wrap_binary_strfunc_reverse(strfunc): try: - accessor = pathlib._Accessor # type: ignore [attr-defined] + accessor = pathlib._Accessor # type: ignore[attr-defined] except AttributeError: accessor = object -class _FakeAccessor(accessor): # type: ignore [valid-type, misc] +class _FakeAccessor(accessor): # type: ignore[valid-type, misc] """Accessor which forwards some of the functions to FakeFilesystem methods. """ @@ -132,7 +132,7 @@ class _FakeAccessor(accessor): # type: ignore [valid-type, misc] if ( not kwargs["follow_symlinks"] - and os.os_module.chmod not in os.os_module.supports_follow_symlinks + and os.chmod not in os.supports_follow_symlinks ): raise NotImplementedError( "`follow_symlinks` for chmod() is not available " "on this system" @@ -185,9 +185,9 @@ class _FakeAccessor(accessor): # type: ignore [valid-type, misc] _fake_accessor = _FakeAccessor() if sys.version_info < (3, 12): - flavour = pathlib._Flavour # type: ignore [attr-defined] + flavour = pathlib._Flavour # type: ignore[attr-defined] - class _FakeFlavour(flavour): # type: ignore [valid-type, misc] + class _FakeFlavour(flavour): # type: ignore[valid-type, misc] """Fake Flavour implementation used by PurePath and _Flavour""" filesystem = None @@ -521,7 +521,7 @@ class FakePath(pathlib.Path): else FakePathlibModule.PosixPath ) if sys.version_info < (3, 12): - return cls._from_parts(args) + return cls._from_parts(args) # pytype: disable=attribute-error else: return object.__new__(cls) @@ -529,10 +529,10 @@ class FakePath(pathlib.Path): # Overwritten class methods to call _init to set the fake accessor, # which is not done in Python 3.10, and not needed from Python 3.11 on @classmethod - def _from_parts(cls, args, init=False): # pylint: disable=unused-argument + def _from_parts(cls, args): self = object.__new__(cls) self._init() - drv, root, parts = self._parse_args(args) + drv, root, parts = self._parse_args(args) # pytype: disable=attribute-error self._drv = drv self._root = root self._parts = parts @@ -594,7 +594,9 @@ class FakePath(pathlib.Path): ) strict = True self._raise_on_closed() - path = self._flavour.resolve(self, strict=strict) + path = self._flavour.resolve( + self, strict=strict + ) # pytype: disable=attribute-error if path is None: self.stat() path = str(self.absolute()) @@ -620,14 +622,16 @@ class FakePath(pathlib.Path): OSError: if the target object is a directory, the path is invalid or permission is denied. """ - with FakeFileOpen(self.filesystem)(self._path(), mode="rb") as f: + with FakeFileOpen(self.filesystem)( + self._path(), mode="rb" + ) as f: # pytype: disable=attribute-error return f.read() def read_text(self, encoding=None, errors=None): """ Open the fake file in text mode, read it, and close the file. """ - with FakeFileOpen(self.filesystem)( + with FakeFileOpen(self.filesystem)( # pytype: disable=attribute-error self._path(), mode="r", encoding=encoding, errors=errors ) as f: return f.read() @@ -642,7 +646,9 @@ class FakePath(pathlib.Path): """ # type-check for the buffer interface before truncating the file view = memoryview(data) - with FakeFileOpen(self.filesystem)(self._path(), mode="wb") as f: + with FakeFileOpen(self.filesystem)( + self._path(), mode="wb" + ) as f: # pytype: disable=attribute-error return f.write(view) def write_text(self, data, encoding=None, errors=None, newline=None): @@ -667,7 +673,7 @@ class FakePath(pathlib.Path): raise TypeError( "write_text() got an unexpected " "keyword argument 'newline'" ) - with FakeFileOpen(self.filesystem)( + with FakeFileOpen(self.filesystem)( # pytype: disable=attribute-error self._path(), mode="w", encoding=encoding, @@ -886,12 +892,12 @@ class RealPath(pathlib.Path): """Creates the correct subclass based on OS.""" if cls is RealPathlibModule.Path: cls = ( - RealPathlibModule.WindowsPath + RealPathlibModule.WindowsPath # pytype: disable=attribute-error if os.name == "nt" - else RealPathlibModule.PosixPath + else RealPathlibModule.PosixPath # pytype: disable=attribute-error ) if sys.version_info < (3, 12): - return cls._from_parts(args) + return cls._from_parts(args) # pytype: disable=attribute-error else: return object.__new__(cls) diff --git a/pyfakefs/helpers.py b/pyfakefs/helpers.py index de4a62a..5d5d590 100644 --- a/pyfakefs/helpers.py +++ b/pyfakefs/helpers.py @@ -120,7 +120,7 @@ def make_string_path(dir_name: os.PathLike) -> str: def make_string_path(dir_name: AnyPath) -> AnyStr: - return cast(AnyStr, os.fspath(dir_name)) + return cast(AnyStr, os.fspath(dir_name)) # pytype: disable=invalid-annotation def to_string(path: Union[AnyStr, Union[str, bytes]]) -> str: @@ -182,7 +182,7 @@ def matching_string( # type: ignore[misc] return string if isinstance(matched, bytes) and isinstance(string, str): return string.encode(locale.getpreferredencoding(False)) - return string + return string # pytype: disable=bad-return-type class FakeStatResult: diff --git a/pyfakefs/mox3_stubout.py b/pyfakefs/mox3_stubout.py index 4afca2b..c3f3a88 100644 --- a/pyfakefs/mox3_stubout.py +++ b/pyfakefs/mox3_stubout.py @@ -102,7 +102,7 @@ class StubOutForTesting: # function. We need to ensure that we put it back as a staticmethod. old_attribute = obj.__dict__.get(attr_name) if old_attribute is not None and isinstance(old_attribute, staticmethod): - orig_attr = staticmethod(orig_attr) + orig_attr = staticmethod(orig_attr) # pytype: disable=not-callable self.stubs.append((orig_obj, attr_name, orig_attr)) setattr(orig_obj, attr_name, new_attr) diff --git a/pyfakefs/patched_packages.py b/pyfakefs/patched_packages.py index ba1a26b..0d7651c 100644 --- a/pyfakefs/patched_packages.py +++ b/pyfakefs/patched_packages.py @@ -53,7 +53,7 @@ def get_modules_to_patch(): def get_classes_to_patch(): classes_to_patch = {} if patch_pandas: - classes_to_patch["TextFileReader"] = "pandas.io.parsers" + classes_to_patch["TextFileReader"] = ["pandas.io.parsers"] return classes_to_patch diff --git a/pyfakefs/tests/test_utils.py b/pyfakefs/tests/test_utils.py index 75a28ef..9555efb 100644 --- a/pyfakefs/tests/test_utils.py +++ b/pyfakefs/tests/test_utils.py @@ -12,7 +12,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +# Disable attribute errors - attributes not be found in mixin (shall be cleaned up...) +# pytype: disable=attribute-error """Common helper classes used in tests, or as test class base.""" import os import platform |