aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormrbean-bremen <mrbean-bremen@users.noreply.github.com>2023-05-03 20:36:14 +0200
committerGitHub <noreply@github.com>2023-05-03 20:36:14 +0200
commit33846b5ef3df436e5c23e69beaf496c4511ee254 (patch)
treee19bf88409dbfa83133a7db9c25f62d9e8e950a9
parent0396c996d01d21e4d9ccde9bd1c346894275db08 (diff)
downloadpyfakefs-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.yml15
-rw-r--r--CHANGES.md3
-rwxr-xr-xpyfakefs/__init__.py2
-rw-r--r--pyfakefs/fake_file.py4
-rw-r--r--pyfakefs/fake_filesystem.py16
-rw-r--r--pyfakefs/fake_filesystem_unittest.py32
-rw-r--r--pyfakefs/fake_io.py2
-rw-r--r--pyfakefs/fake_open.py13
-rw-r--r--pyfakefs/fake_os.py4
-rw-r--r--pyfakefs/fake_path.py3
-rw-r--r--pyfakefs/fake_pathlib.py38
-rw-r--r--pyfakefs/helpers.py4
-rw-r--r--pyfakefs/mox3_stubout.py2
-rw-r--r--pyfakefs/patched_packages.py2
-rw-r--r--pyfakefs/tests/test_utils.py3
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:
diff --git a/CHANGES.md b/CHANGES.md
index cbbdc27..002175e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -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