diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2191f6d..6429c5e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,6 +44,10 @@ repos: hooks: - id: tox-ini-fmt args: ["-p", "fix"] + - repo: https://github.com/tox-dev/pyproject-fmt + rev: "0.9.2" + hooks: + - id: pyproject-fmt - repo: https://github.com/PyCQA/flake8 rev: 6.0.0 hooks: diff --git a/docs/changelog.rst b/docs/changelog.rst index 4932919..176b994 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,5 +1,9 @@ Changelog ========= +v3.10.5 (2023-03-25) +-------------------- +- Add explicit error check as certain UNIX filesystems do not support flock. by :user:`jahrules`. + v3.10.4 (2023-03-24) -------------------- - Update os.open to preserve mode= for certain edge cases. by :user:`jahrules`. diff --git a/pyproject.toml b/pyproject.toml index da688b7..3ea4ea0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,8 +42,10 @@ optional-dependencies.docs = [ optional-dependencies.testing = [ "covdefaults>=2.3", "coverage>=7.2.2", + "diff-cover>=7.5", "pytest>=7.2.2", "pytest-cov>=4", + "pytest-mock>=3.10", "pytest-timeout>=2.1", ] urls.Documentation = "https://py-filelock.readthedocs.io" @@ -56,6 +58,21 @@ build.hooks.vcs.version-file = "src/filelock/version.py" build.targets.sdist.include = ["/src", "/tests"] version.source = "vcs" +[tool.black] +line-length = 120 + +[tool.isort] +profile = "black" +known_first_party = ["filelock"] +add_imports = ["from __future__ import annotations"] + +[tool.flake8] +max-complexity = 22 +max-line-length = 120 +unused-arguments-ignore-abstract-functions = true +noqa-require-code = true +dictionaries = ["en_US", "python", "technical", "django"] + [tool.coverage] html.show_contexts = true html.skip_covered = false @@ -65,14 +82,6 @@ report.fail_under = 76 run.parallel = true run.plugins = ["covdefaults"] -[tool.black] -line-length = 120 - -[tool.isort] -profile = "black" -known_first_party = ["filelock"] -add_imports = ["from __future__ import annotations"] - [tool.mypy] python_version = "3.11" show_error_codes = true @@ -81,10 +90,3 @@ overrides = [{ module = ["appdirs.*", "jnius.*"], ignore_missing_imports = true [tool.pep8] max-line-length = "120" - -[tool.flake8] -max-complexity = 22 -max-line-length = 120 -unused-arguments-ignore-abstract-functions = true -noqa-require-code = true -dictionaries = ["en_US", "python", "technical", "django"] diff --git a/src/filelock/_unix.py b/src/filelock/_unix.py index edfba4d..c2e270e 100644 --- a/src/filelock/_unix.py +++ b/src/filelock/_unix.py @@ -2,6 +2,7 @@ import os import sys +from errno import ENOSYS from typing import cast from ._api import BaseFileLock @@ -39,8 +40,10 @@ def _acquire(self) -> None: pass # This locked is not owned by this UID try: fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) - except OSError: + except OSError as exception: os.close(fd) + if exception.errno == ENOSYS: # NotImplemented error + raise NotImplementedError("FileSystem does not appear to support flock; user SoftFileLock instead") else: self._lock_file_fd = fd diff --git a/tests/test_filelock.py b/tests/test_filelock.py index c9dd600..ef8d59d 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -6,6 +6,7 @@ import sys import threading from contextlib import contextmanager +from errno import ENOSYS from inspect import getframeinfo, stack from pathlib import Path, PurePath from stat import S_IWGRP, S_IWOTH, S_IWUSR, filemode @@ -14,6 +15,7 @@ import pytest from _pytest.logging import LogCaptureFixture +from pytest_mock import MockerFixture from filelock import ( BaseFileLock, @@ -494,3 +496,11 @@ def test_wrong_platform(tmp_path: Path) -> None: lock.acquire() with pytest.raises(NotImplementedError): lock._release() + + +@pytest.mark.skipif(sys.platform == "win32", reason="flock not run on windows") +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")): + pass diff --git a/tox.ini b/tox.ini index e847fd1..602700f 100644 --- a/tox.ini +++ b/tox.ini @@ -29,6 +29,7 @@ commands = --cov-config=pyproject.toml --no-cov-on-fail --cov-report term-missing:skip-covered --cov-context=test \ --cov-report html:{envtmpdir}{/}htmlcov --cov-report xml:{toxworkdir}{/}coverage.{envname}.xml \ tests} + diff-cover --compare-branch {env:DIFF_AGAINST:origin/main} {toxworkdir}{/}coverage.{envname}.xml package = wheel wheel_build_env = .pkg diff --git a/whitelist.txt b/whitelist.txt index f912669..b55c548 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -3,6 +3,7 @@ autodoc autosectionlabel caplog eacces +enosys extlinks filelock filemode