From fce84142d9fb516fca1c78ece67b36b0af00cbdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Thu, 2 Jul 2026 17:25:44 -0700 Subject: [PATCH] test: fix Windows type check for the waiter-fd test main's type-windows job broke after #577 merged: the waiter-fd test calls fcntl.flock/LOCK_EX/LOCK_NB, which ty rejects on Windows because pytest.mark.skipif does not narrow the platform for the type checker. Guard the Unix-only body behind a static sys.platform check so ty narrows fcntl away on Windows, mirroring the pattern in src/filelock/_unix.py. Also fold in two small test tidies: - hoist the cross-platform errno constants to the module imports - drop the mutable flag from the break-name test's lstat hook --- tests/test_filelock.py | 6 +++--- tests/test_util.py | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index 599f0c89..38d8bc35 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -7,7 +7,7 @@ import threading from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager -from errno import ENOSYS +from errno import EAGAIN, ENOSYS, EWOULDBLOCK from inspect import getframeinfo, stack from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode @@ -994,10 +994,10 @@ def test_lock_acquired_after_release_keeps_path(tmp_path: Path) -> None: assert lock_path.exists() -@pytest.mark.skipif(sys.platform == "win32", reason="Unix flock semantics") def test_waiter_fd_cannot_split_lock_after_release(tmp_path: Path) -> None: + if sys.platform == "win32": # pragma: win32 cover # Unix flock semantics; also narrows fcntl for the type checker + return import fcntl - from errno import EAGAIN, EWOULDBLOCK lock_path = tmp_path / "test.lock" first = FileLock(str(lock_path), is_singleton=False) diff --git a/tests/test_util.py b/tests/test_util.py index b65af49f..2cd34eee 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -78,12 +78,10 @@ def test_break_lock_file_break_path_not_targetable_by_a_peer(tmp_path: Path, moc # re-verify lstat and the unlink, and we would delete a live lock the inode check just approved. predictable = tmp_path / f"test.lock.break.{os.getpid()}" real_lstat = os.lstat - fired = {"x": False} def lstat_hook(path: str) -> os.stat_result: result = real_lstat(path) - if not fired["x"] and ".break." in path: - fired["x"] = True + if ".break." in path and not predictable.exists(): # once: the peer recreates a live lock at its own name lock.write_text("live", encoding="utf-8") lock.rename(predictable) return result