From 51e6e0456dc41bd2deae6f7a8be9b7518653418c Mon Sep 17 00:00:00 2001 From: mrbean-bremen Date: Mon, 27 Jan 2025 20:49:49 +0100 Subject: [PATCH] Add CI tests for Python 3.14 pre-release - work around new class checks in pathlib --- .github/workflows/testsuite.yml | 6 +++--- CHANGES.md | 5 +++++ pyfakefs/fake_filesystem_unittest.py | 5 +++++ pyfakefs/fake_pathlib.py | 13 +++++++++++++ pyfakefs/tests/fake_pathlib_test.py | 5 +++-- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/.github/workflows/testsuite.yml b/.github/workflows/testsuite.yml index 162b1d44..8231af29 100644 --- a/.github/workflows/testsuite.yml +++ b/.github/workflows/testsuite.yml @@ -32,7 +32,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, macOS-latest, windows-latest] - python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"] + python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13", "3.14"] include: - python-version: "pypy-3.7" os: ubuntu-22.04 @@ -86,14 +86,14 @@ jobs: fi shell: bash - name: Install extra dependencies - if: ${{ matrix.python-version != 'pypy-3.10' }} + if: ${{ matrix.python-version != '3.14' }} run: | pip install -r extra_requirements.txt pip install -r legacy_requirements.txt pip install zstandard cffi # needed to test #910 shell: bash - name: Run unit tests with extra packages as non-root user - if: ${{ matrix.python-version != 'pypy-3.10' }} + if: ${{ matrix.python-version != '3.14' }} run: | export PYTHON_ZSTANDARD_IMPORT_POLICY=cffi # needed to test #910 python -m pyfakefs.tests.all_tests diff --git a/CHANGES.md b/CHANGES.md index 220100a4..c6229bb8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,11 @@ The released versions correspond to PyPI releases. * the default for `FakeFilesystem.shuffle_listdir_results` will change to `True` to reflect the real filesystem behavior +## Unreleased + +### Changes +* added some preliminary support for Python 3.14 + ## [Version 5.7.4](https://pypi.python.org/pypi/pyfakefs/5.7.4) (2025-01-14) Minor bugfix release. diff --git a/pyfakefs/fake_filesystem_unittest.py b/pyfakefs/fake_filesystem_unittest.py index 983c5824..e42eaa02 100644 --- a/pyfakefs/fake_filesystem_unittest.py +++ b/pyfakefs/fake_filesystem_unittest.py @@ -993,6 +993,11 @@ def setUp(self, doctester: Any = None) -> None: # do not use the fd functions, as they may not be available in the target OS if hasattr(shutil, "_use_fd_functions"): shutil._use_fd_functions = False # type: ignore[module-attr] + # in Python 3.14, _rmtree_impl is set at load time based on _use_fd_functions + # the safe version cannot be used at the moment as it used asserts of type + # 'assert func is os.rmtree', which do not work with the fake versions + if hasattr(shutil, "_rmtree_impl"): + shutil._rmtree_impl = shutil._rmtree_unsafe # type: ignore[attr-defined] with warnings.catch_warnings(): # ignore warnings, see #542 and #614 diff --git a/pyfakefs/fake_pathlib.py b/pyfakefs/fake_pathlib.py index 3697085e..15322dae 100644 --- a/pyfakefs/fake_pathlib.py +++ b/pyfakefs/fake_pathlib.py @@ -964,6 +964,19 @@ def group(self): return grp.getgrgid(self.stat().st_gid).gr_name + if sys.version_info >= (3, 14): + # in Python 3.14, case-sensitivity is checked using an is-check + # (self.parser is posixpath) if not given, which we cannot fake + # therefore we already provide the case sensitivity under Posix + def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False): + if case_sensitive is None: + case_sensitive = True + return super().glob( # pytype: disable=wrong-keyword-args + pattern, + case_sensitive=case_sensitive, + recurse_symlinks=recurse_symlinks, + ) + Path = FakePath def __getattr__(self, name): diff --git a/pyfakefs/tests/fake_pathlib_test.py b/pyfakefs/tests/fake_pathlib_test.py index cb15f9b8..fa8fedf4 100644 --- a/pyfakefs/tests/fake_pathlib_test.py +++ b/pyfakefs/tests/fake_pathlib_test.py @@ -996,8 +996,8 @@ def test_glob(self): sorted(path.glob("*.py")), ) - @unittest.skipIf(not is_windows, "Windows specific test") def test_glob_case_windows(self): + self.check_windows_only() self.create_file(self.make_path("foo", "setup.py")) self.create_file(self.make_path("foo", "all_tests.PY")) self.create_file(self.make_path("foo", "README.md")) @@ -1012,9 +1012,10 @@ def test_glob_case_windows(self): sorted(path.glob("*.py")), ) - @unittest.skipIf(is_windows, "Posix specific test") def test_glob_case_posix(self): self.check_posix_only() + if sys.platform == "win32" and sys.version_info < (3, 12): + self.skipTest(reason="Ignoring inconsistent path delimiters") self.create_file(self.make_path("foo", "setup.py")) self.create_file(self.make_path("foo", "all_tests.PY")) self.create_file(self.make_path("foo", "README.md"))