diff --git a/docs/changelog.rst b/docs/changelog.rst index acd9c56..095acec 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,10 @@ Changelog ========= +v3.5.0 (2022-01-03) +------------------- +- Enable use as context decorator + v3.4.2 (2021-12-16) ------------------- - Drop support for python ``3.6`` diff --git a/docs/index.rst b/docs/index.rst index bc95510..73b4e36 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -67,6 +67,14 @@ locks: finally: lock.release() + + @lock + def decorated(): + print("You're a decorated Jedi!") + + + decorated() + The :meth:`acquire ` method accepts also a ``timeout`` parameter. If the lock cannot be acquired within ``timeout`` seconds, a :class:`Timeout ` exception is raised: diff --git a/src/filelock/_api.py b/src/filelock/_api.py index 3551d5d..d3cffc4 100644 --- a/src/filelock/_api.py +++ b/src/filelock/_api.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import logging import os import time @@ -35,7 +36,7 @@ def __exit__( self.lock.release() -class BaseFileLock(ABC): +class BaseFileLock(ABC, contextlib.ContextDecorator): """Abstract base class for a file lock object.""" def __init__(self, lock_file: str | os.PathLike[Any], timeout: float = -1) -> None: diff --git a/tests/test_filelock.py b/tests/test_filelock.py index 6991137..bce9e1e 100644 --- a/tests/test_filelock.py +++ b/tests/test_filelock.py @@ -368,3 +368,17 @@ def test_poll_intervall_deprecated(lock_type: type[BaseFileLock], tmp_path: Path break else: # pragma: no cover pytest.fail("No warnings of stacklevel=2 matching.") + + +@pytest.mark.parametrize("lock_type", [FileLock, SoftFileLock]) +def test_context_decorator(lock_type: type[BaseFileLock], tmp_path: Path) -> None: + lock_path = tmp_path / "a" + lock = lock_type(str(lock_path)) + + @lock + def decorated_method() -> None: + assert lock.is_locked + + assert not lock.is_locked + decorated_method() + assert not lock.is_locked