From d821c6140e2c49c7dc15f382fe153bcea75df010 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 07:37:35 -0400 Subject: [PATCH 01/13] updated nomenclature to allign with softlock, added test, added changelog --- tests/test_filelock.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index ef8d59db..becae172 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -1,5 +1,6 @@ from __future__ import annotations +import fcntl import inspect import logging import os From 09786a5a83ab613a7ec43439277754c021f5eede Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 08:16:42 -0400 Subject: [PATCH 02/13] moved fcntl import to the test def and added type hints --- tests/test_filelock.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index becae172..807bc69a 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -1,6 +1,5 @@ from __future__ import annotations -import fcntl import inspect import logging import os @@ -12,7 +11,7 @@ from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode from types import TracebackType -from typing import Callable, Iterator, Tuple, Type, Union +from typing import Callable, IO, Iterator, Tuple, Type, Union import pytest from _pytest.logging import LogCaptureFixture From 4dfc98f3eb5b95933bd7796c0602a8af05c670b7 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 08:58:21 -0400 Subject: [PATCH 03/13] another type attempt --- tests/test_filelock.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index 807bc69a..1e3c69a3 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -11,7 +11,7 @@ from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode from types import TracebackType -from typing import Callable, IO, Iterator, Tuple, Type, Union +from typing import Callable, IO, Iterator, Tuple, Type, TYPE_CHECKING, Union import pytest from _pytest.logging import LogCaptureFixture @@ -26,6 +26,9 @@ WindowsFileLock, ) +if TYPE_CHECKING: + from _typeshed import HasFileno + @pytest.mark.parametrize( ("lock_type", "path_type"), From 206189792b59b50c3d2b0145dcd16f5955b567b1 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 09:04:32 -0400 Subject: [PATCH 04/13] flake fixes --- tests/test_filelock.py | 2 +- whitelist.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index 1e3c69a3..ba368dd8 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -11,7 +11,7 @@ from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode from types import TracebackType -from typing import Callable, IO, Iterator, Tuple, Type, TYPE_CHECKING, Union +from typing import Callable, Iterator, Tuple, Type, TYPE_CHECKING, Union import pytest from _pytest.logging import LogCaptureFixture diff --git a/whitelist.txt b/whitelist.txt index b55c5489..dfd87763 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -10,6 +10,7 @@ filemode frameinfo fspath getframeinfo +hasfileno intersphinx intervall isabstract @@ -30,5 +31,6 @@ skipif stacklevel trunc typehints +typeshed unlck win32 From 1906eccce711ecdb0ba8416dab7bea1281abb2f2 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 09:05:50 -0400 Subject: [PATCH 05/13] flake fixes --- whitelist.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/whitelist.txt b/whitelist.txt index dfd87763..25244a77 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -7,10 +7,10 @@ enosys extlinks filelock filemode +fileno frameinfo fspath getframeinfo -hasfileno intersphinx intervall isabstract From 8f97f7367119a7404bc3961741fb3f69496e9f5b Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 14:50:06 -0400 Subject: [PATCH 06/13] changes to resolve issue 147 --- docs/changelog.rst | 4 ++++ src/filelock/_soft.py | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 176b9944..6fa3cedd 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,9 @@ Changelog ========= +v3.10.6 (2023-03-25) +-------------------- +- Enhance the robustness of the try/catch block in _soft.py. by :user: `jahrules`. + v3.10.5 (2023-03-25) -------------------- - Add explicit error check as certain UNIX filesystems do not support flock. by :user:`jahrules`. diff --git a/src/filelock/_soft.py b/src/filelock/_soft.py index 6d953407..420cfcfe 100644 --- a/src/filelock/_soft.py +++ b/src/filelock/_soft.py @@ -2,7 +2,7 @@ import os import sys -from errno import EACCES, EEXIST, ENOENT +from errno import EACCES, EEXIST from ._api import BaseFileLock from ._util import raise_on_exist_ro_file @@ -23,13 +23,13 @@ def _acquire(self) -> None: try: fd = os.open(self._lock_file, flags, self._mode) except OSError as exception: - if exception.errno == EEXIST: # expected if cannot lock + if ( + (exception.errno == EEXIST) or # expected if cannot lock + (exception.errno == EACCES and sys.platform == "win32") # pragma: win32 no cover + ): pass - elif exception.errno == ENOENT: # No such file or directory - parent directory is missing + else: raise - elif exception.errno == EACCES and sys.platform != "win32": # pragma: win32 no cover - # Permission denied - parent dir is R/O - raise # note windows does not allow you to make a folder r/o only files else: self._lock_file_fd = fd From fa8fd02ca33e2247674a845746ff8f52929245b5 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 14:53:47 -0400 Subject: [PATCH 07/13] fix typo --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 6fa3cedd..c760d183 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,7 +2,7 @@ Changelog ========= v3.10.6 (2023-03-25) -------------------- -- Enhance the robustness of the try/catch block in _soft.py. by :user: `jahrules`. +- Enhance the robustness of the try/catch block in _soft.py. by :user:`jahrules`. v3.10.5 (2023-03-25) -------------------- From 68edf85359b28777b613222a79dc9f8c4c761983 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 17:14:21 -0400 Subject: [PATCH 08/13] flake 8 fix --- tests/test_filelock.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index ba368dd8..ef8d59db 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -11,7 +11,7 @@ from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode from types import TracebackType -from typing import Callable, Iterator, Tuple, Type, TYPE_CHECKING, Union +from typing import Callable, Iterator, Tuple, Type, Union import pytest from _pytest.logging import LogCaptureFixture @@ -26,9 +26,6 @@ WindowsFileLock, ) -if TYPE_CHECKING: - from _typeshed import HasFileno - @pytest.mark.parametrize( ("lock_type", "path_type"), From 196cc697f3d32b4edc4e1d5bd022a87aaea53c54 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 17:38:55 -0400 Subject: [PATCH 09/13] test for OSError in SoftFileLock --- tests/test_filelock.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index ef8d59db..ab862b87 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -504,3 +504,11 @@ def test_flock_not_implemented_unix(tmp_path: Path, mocker: MockerFixture) -> No with pytest.raises(NotImplementedError): with FileLock(str(tmp_path / "a.lock")): pass + + +def test_soft_errors(tmp_path: Path, mocker: MockerFixture) -> None: + mocker.patch("os.open", side_effect=OSError(ENOSYS, "mock error")) + lock_path = tmp_path / "a.lock" + lock = SoftFileLock(str(lock_path)) + with pytest.raises(OSError): + lock.acquire() From f268a29d6348ee430bb12889809b409be7550e79 Mon Sep 17 00:00:00 2001 From: Gregory Taeger Date: Sat, 25 Mar 2023 17:56:41 -0400 Subject: [PATCH 10/13] flake8 fix --- tests/test_filelock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index ab862b87..5e93ee57 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -510,5 +510,5 @@ def test_soft_errors(tmp_path: Path, mocker: MockerFixture) -> None: mocker.patch("os.open", side_effect=OSError(ENOSYS, "mock error")) lock_path = tmp_path / "a.lock" lock = SoftFileLock(str(lock_path)) - with pytest.raises(OSError): + with pytest.raises(OSError, match="mock error"): lock.acquire() From 63147705c029336f575861d7c0b4c964580487fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 21:57:54 +0000 Subject: [PATCH 11/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/filelock/_soft.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/filelock/_soft.py b/src/filelock/_soft.py index 420cfcfe..a4f93e91 100644 --- a/src/filelock/_soft.py +++ b/src/filelock/_soft.py @@ -23,10 +23,9 @@ def _acquire(self) -> None: try: fd = os.open(self._lock_file, flags, self._mode) except OSError as exception: - if ( - (exception.errno == EEXIST) or # expected if cannot lock - (exception.errno == EACCES and sys.platform == "win32") # pragma: win32 no cover - ): + if (exception.errno == EEXIST) or ( # expected if cannot lock + exception.errno == EACCES and sys.platform == "win32" + ): # pragma: win32 no cover pass else: raise From 1b46ee1542618a91bd4dddb9fdb322112b17d518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sat, 25 Mar 2023 20:19:25 -0700 Subject: [PATCH 12/13] PR Feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- tests/test_filelock.py | 25 +++++++++++-------------- whitelist.txt | 3 --- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tests/test_filelock.py b/tests/test_filelock.py index 5e93ee57..e635dd5d 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -185,7 +185,7 @@ def __init__(self, target: Callable[[], None], name: str) -> None: def run(self) -> None: try: super().run() - except Exception: # pragma: no cover + except RuntimeError: # pragma: no cover self.ex = sys.exc_info() # pragma: no cover def join(self, timeout: float | None = None) -> None: @@ -337,8 +337,8 @@ def test_context_release_on_exc(lock_type: type[BaseFileLock], tmp_path: Path) - with lock as lock_1: assert lock is lock_1 assert lock.is_locked - raise Exception - except Exception: + raise ValueError + except ValueError: assert not lock.is_locked @@ -352,8 +352,8 @@ def test_acquire_release_on_exc(lock_type: type[BaseFileLock], tmp_path: Path) - with lock.acquire() as lock_1: assert lock is lock_1 assert lock.is_locked - raise Exception - except Exception: + raise ValueError + except ValueError: assert not lock.is_locked @@ -385,9 +385,8 @@ def test_del(lock_type: type[BaseFileLock], tmp_path: Path) -> None: def test_cleanup_soft_lock(tmp_path: Path) -> None: # tests if the lock file is removed after use lock_path = tmp_path / "a" - lock = SoftFileLock(str(lock_path)) - with lock: + with SoftFileLock(lock_path): assert lock_path.exists() assert not lock_path.exists() @@ -399,9 +398,9 @@ def test_poll_intervall_deprecated(lock_type: type[BaseFileLock], tmp_path: Path with pytest.deprecated_call(match="use poll_interval instead of poll_intervall") as checker: lock.acquire(poll_intervall=0.05) # the deprecation warning will be captured by the checker - frameinfo = getframeinfo(stack()[0][0]) # get frameinfo of current file and lineno (+1 than the above lineno) + frame_info = getframeinfo(stack()[0][0]) # get frame info of current file and lineno (+1 than the above lineno) for warning in checker: - if warning.filename == frameinfo.filename and warning.lineno + 1 == frameinfo.lineno: # pragma: no cover + if warning.filename == frame_info.filename and warning.lineno + 1 == frame_info.lineno: # pragma: no cover break else: # pragma: no cover pytest.fail("No warnings of stacklevel=2 matching.") @@ -490,7 +489,7 @@ def test_wrong_platform(tmp_path: Path) -> None: assert inspect.isabstract(BaseFileLock) lock_type = UnixFileLock if sys.platform == "win32" else WindowsFileLock - lock = lock_type(str(tmp_path / "lockfile")) + lock = lock_type(tmp_path / "lockfile") with pytest.raises(NotImplementedError): lock.acquire() @@ -502,13 +501,11 @@ def test_wrong_platform(tmp_path: Path) -> None: def test_flock_not_implemented_unix(tmp_path: Path, mocker: MockerFixture) -> None: mocker.patch("fcntl.flock", side_effect=OSError(ENOSYS, "mock error")) with pytest.raises(NotImplementedError): - with FileLock(str(tmp_path / "a.lock")): + with FileLock(tmp_path / "a.lock"): pass def test_soft_errors(tmp_path: Path, mocker: MockerFixture) -> None: mocker.patch("os.open", side_effect=OSError(ENOSYS, "mock error")) - lock_path = tmp_path / "a.lock" - lock = SoftFileLock(str(lock_path)) with pytest.raises(OSError, match="mock error"): - lock.acquire() + SoftFileLock(tmp_path / "a.lock").acquire() diff --git a/whitelist.txt b/whitelist.txt index 25244a77..d5c4d2e4 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -7,8 +7,6 @@ enosys extlinks filelock filemode -fileno -frameinfo fspath getframeinfo intersphinx @@ -31,6 +29,5 @@ skipif stacklevel trunc typehints -typeshed unlck win32 From a7ab6ca93f6c935ae7c0af43a52d9977c78d9377 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sat, 25 Mar 2023 20:23:01 -0700 Subject: [PATCH 13/13] PR Feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bernát Gábor --- src/filelock/_soft.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/filelock/_soft.py b/src/filelock/_soft.py index a4f93e91..697f6c4c 100644 --- a/src/filelock/_soft.py +++ b/src/filelock/_soft.py @@ -21,16 +21,15 @@ def _acquire(self) -> None: | os.O_TRUNC # truncate the file to zero byte ) try: - fd = os.open(self._lock_file, flags, self._mode) - except OSError as exception: - if (exception.errno == EEXIST) or ( # expected if cannot lock - exception.errno == EACCES and sys.platform == "win32" + file_handler = os.open(self._lock_file, flags, self._mode) + except OSError as exception: # re-raise unless expected exception + if not ( + exception.errno == EEXIST # lock already exist + or (exception.errno == EACCES and sys.platform == "win32") # has no access to this lock ): # pragma: win32 no cover - pass - else: raise else: - self._lock_file_fd = fd + self._lock_file_fd = file_handler def _release(self) -> None: os.close(self._lock_file_fd) # type: ignore # the lock file is definitely not None