From f0cd6b49e5c4215137e5c24ac0b46752f0c61e69 Mon Sep 17 00:00:00 2001 From: David Hotham Date: Sat, 10 Sep 2022 13:10:36 +0100 Subject: [PATCH] switch from lockfile to filelock lockfile has long been deprecated, among the advantages of filelock are that locks are automatically released on process exit --- cachecontrol/caches/file_cache.py | 24 +++++++----------------- dev_requirements.txt | 2 +- docs/storage.rst | 6 +++--- docs/usage.rst | 2 +- setup.py | 2 +- tests/test_storage_filecache.py | 24 ++++++------------------ tox.ini | 2 +- 7 files changed, 20 insertions(+), 42 deletions(-) diff --git a/cachecontrol/caches/file_cache.py b/cachecontrol/caches/file_cache.py index f1ddb2eb..f82e7b85 100644 --- a/cachecontrol/caches/file_cache.py +++ b/cachecontrol/caches/file_cache.py @@ -66,33 +66,23 @@ def __init__( forever=False, filemode=0o0600, dirmode=0o0700, - use_dir_lock=None, lock_class=None, ): - if use_dir_lock is not None and lock_class is not None: - raise ValueError("Cannot use use_dir_lock and lock_class together") - try: - from lockfile import LockFile - from lockfile.mkdirlockfile import MkdirLockFile + if lock_class is None: + from filelock import FileLock + lock_class = FileLock except ImportError: notice = dedent( """ NOTE: In order to use the FileCache you must have - lockfile installed. You can install it via pip: - pip install lockfile + filelock installed. You can install it via pip: + pip install filelock """ ) raise ImportError(notice) - else: - if use_dir_lock: - lock_class = MkdirLockFile - - elif lock_class is None: - lock_class = LockFile - self.directory = directory self.forever = forever self.filemode = filemode @@ -133,9 +123,9 @@ def _write(self, path, data: bytes): except (IOError, OSError): pass - with self.lock_class(path) as lock: + with self.lock_class(path + ".lock"): # Write our actual file - with _secure_open_write(lock.path, self.filemode) as fh: + with _secure_open_write(path, self.filemode) as fh: fh.write(data) def _delete(self, key, suffix): diff --git a/dev_requirements.txt b/dev_requirements.txt index ce7f9994..46d00b04 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -11,7 +11,7 @@ mock cherrypy sphinx redis -lockfile +filelock bumpversion twine black diff --git a/docs/storage.rst b/docs/storage.rst index e15787df..a2fc3fce 100644 --- a/docs/storage.rst +++ b/docs/storage.rst @@ -28,7 +28,7 @@ FileCache ========= The `FileCache` is similar to the caching mechanism provided by -httplib2_. It requires `lockfile`_ be installed as it prevents +httplib2_. It requires `filelock`_ be installed as it prevents multiple threads from writing to the same file at the same time. .. note:: @@ -64,7 +64,7 @@ This is similar to ``FileCache``, but far more memory efficient, and therefore r The body of the request is stored in a separate file than metadata, and streamed in and out. -It requires `lockfile`_ be installed as it prevents multiple threads from writing to the same file at the same time. +It requires `filelock`_ be installed as it prevents multiple threads from writing to the same file at the same time. .. note:: @@ -127,7 +127,7 @@ Third-Party Cache Providers .. _httplib2: https://github.com/httplib2/httplib2 -.. _lockfile: https://github.com/smontanaro/pylockfile +.. _filelock: https://github.com/tox-dev/py-filelock .. _requests 2.1: http://docs.python-requests.org/en/latest/community/updates/#id2 .. _redis: https://github.com/andymccurdy/redis-py .. _cachecontrol-django: https://github.com/glassesdirect/cachecontrol-django diff --git a/docs/usage.rst b/docs/usage.rst index f908d38e..744d93c2 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -62,7 +62,7 @@ the provided `FileCache` from CacheControl: :: from cachecontrol import CacheControl - # NOTE: This requires lockfile be installed + # NOTE: This requires filelock be installed from cachecontrol.caches import FileCache sess = CacheControl(requests.Session(), diff --git a/setup.py b/setup.py index 187a7c15..dee97600 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ description="httplib2 caching for requests", long_description=long_description, install_requires=["requests", "msgpack>=0.5.2"], - extras_require={"filecache": ["lockfile>=0.9"], "redis": ["redis>=2.10.5"]}, + extras_require={"filecache": ["filelock>=3.8.0"], "redis": ["redis>=2.10.5"]}, entry_points={"console_scripts": ["doesitcache = cachecontrol._cmd:main"]}, python_requires=">=3.6", classifiers=[ diff --git a/tests/test_storage_filecache.py b/tests/test_storage_filecache.py index 33e17549..8c93284a 100644 --- a/tests/test_storage_filecache.py +++ b/tests/test_storage_filecache.py @@ -14,8 +14,7 @@ import requests from cachecontrol import CacheControl from cachecontrol.caches import FileCache, SeparateBodyFileCache -from lockfile import LockFile -from lockfile.mkdirlockfile import MkdirLockFile +from filelock import FileLock def randomdata(): @@ -94,21 +93,10 @@ def test_key_length(self, sess): assert len(self.cache.encode(url0)) < 200 assert len(self.cache.encode(url0)) == len(self.cache.encode(url1)) - def test_cant_use_dir_and_lock_class(self, tmpdir): - with pytest.raises(ValueError): - self.FileCacheClass(str(tmpdir), use_dir_lock=True, lock_class=object()) - - @pytest.mark.parametrize( - ("value", "expected"), - [(None, LockFile), (True, MkdirLockFile), (False, LockFile)], - ) - def test_simple_lockfile_arg(self, tmpdir, value, expected): - if value is not None: - cache = self.FileCacheClass(str(tmpdir), use_dir_lock=value) - else: - cache = self.FileCacheClass(str(tmpdir)) - - assert issubclass(cache.lock_class, expected) + def test_simple_lockfile_arg(self, tmpdir): + cache = self.FileCacheClass(str(tmpdir)) + + assert issubclass(cache.lock_class, FileLock) cache.close() def test_lock_class(self, tmpdir): @@ -134,7 +122,7 @@ class TestFileCache(FileCacheTestsMixin): """ Tests for ``FileCache``. """ - + FileCacheClass = FileCache def test_body_stored_inline(self, sess): diff --git a/tox.ini b/tox.ini index 3c6f1711..d3768132 100644 --- a/tox.ini +++ b/tox.ini @@ -18,5 +18,5 @@ deps = pytest mock cherrypy redis - lockfile + filelock commands = py.test {posargs:tests/}