Skip to content

Commit 7b04466

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 71f4501 commit 7b04466

File tree

1 file changed

+75
-45
lines changed

1 file changed

+75
-45
lines changed

src/filelock/_read_write.py

Lines changed: 75 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
1+
from __future__ import annotations
2+
3+
import logging
14
import os
25
import sqlite3
36
import threading
4-
import logging
5-
from _error import Timeout
6-
from filelock._api import AcquireReturnProxy, BaseFileLock
7-
from typing import Literal, Any
87
from contextlib import contextmanager
8+
from typing import Any, Literal
99
from weakref import WeakValueDictionary
1010

11+
from _error import Timeout
12+
13+
from filelock._api import AcquireReturnProxy
14+
1115
_LOGGER = logging.getLogger("filelock")
1216

1317
# PRAGMA busy_timeout=N delegates to https://www.sqlite.org/c3ref/busy_timeout.html,
1418
# which accepts an int argument, which has the maximum value of 2_147_483_647 on 32-bit
1519
# systems. Use even a lower value to be safe. This 2 bln milliseconds is about 23 days.
1620
_MAX_SQLITE_TIMEOUT_MS = 2_000_000_000 - 1
1721

22+
1823
def timeout_for_sqlite(timeout: float = -1, blocking: bool = True) -> int:
1924
if blocking is False:
2025
return 0
2126
if timeout == -1:
2227
return _MAX_SQLITE_TIMEOUT_MS
2328
if timeout < 0:
24-
raise ValueError("timeout must be a non-negative number or -1")
25-
29+
msg = "timeout must be a non-negative number or -1"
30+
raise ValueError(msg)
31+
2632
assert timeout >= 0
2733
timeout_ms = int(timeout * 1000)
2834
if timeout_ms > _MAX_SQLITE_TIMEOUT_MS or timeout_ms < 0:
@@ -33,9 +39,16 @@ def timeout_for_sqlite(timeout: float = -1, blocking: bool = True) -> int:
3339

3440
class _ReadWriteLockMeta(type):
3541
"""Metaclass that redirects instance creation to get_lock() when is_singleton=True."""
36-
def __call__(cls, lock_file: str | os.PathLike[str],
37-
timeout: float = -1, blocking: bool = True,
38-
is_singleton: bool = True, *args: Any, **kwargs: Any) -> "ReadWriteLock":
42+
43+
def __call__(
44+
cls,
45+
lock_file: str | os.PathLike[str],
46+
timeout: float = -1,
47+
blocking: bool = True,
48+
is_singleton: bool = True,
49+
*args: Any,
50+
**kwargs: Any,
51+
) -> ReadWriteLock:
3952
if is_singleton:
4053
return cls.get_lock(lock_file, timeout, blocking)
4154
return super().__call__(lock_file, timeout, blocking, is_singleton, *args, **kwargs)
@@ -47,16 +60,22 @@ class ReadWriteLock(metaclass=_ReadWriteLockMeta):
4760
_instances_lock = threading.Lock()
4861

4962
@classmethod
50-
def get_lock(cls, lock_file: str | os.PathLike[str],
51-
timeout: float = -1, blocking: bool = True) -> "ReadWriteLock":
63+
def get_lock(cls, lock_file: str | os.PathLike[str], timeout: float = -1, blocking: bool = True) -> ReadWriteLock:
5264
"""Return the one-and-only ReadWriteLock for a given file."""
5365
normalized = os.path.abspath(lock_file)
5466
with cls._instances_lock:
5567
if normalized not in cls._instances:
5668
cls._instances[normalized] = cls(lock_file, timeout, blocking)
5769
instance = cls._instances[normalized]
5870
if instance.timeout != timeout or instance.blocking != blocking:
59-
raise ValueError("Singleton lock created with timeout=%s, blocking=%s, cannot be changed to timeout=%s, blocking=%s", instance.timeout, instance.blocking, timeout, blocking)
71+
msg = "Singleton lock created with timeout=%s, blocking=%s, cannot be changed to timeout=%s, blocking=%s"
72+
raise ValueError(
73+
msg,
74+
instance.timeout,
75+
instance.blocking,
76+
timeout,
77+
blocking,
78+
)
6079
return instance
6180

6281
def __init__(
@@ -76,7 +95,7 @@ def __init__(
7695
self._internal_lock = threading.Lock()
7796
self._lock_level = 0 # Reentrance counter.
7897
# _current_mode holds the active lock mode ("read" or "write") or None if no lock is held.
79-
self._current_mode: Literal["read", "write", None] = None
98+
self._current_mode: Literal["read", "write"] | None = None
8099
# _lock_level is the reentrance counter.
81100
self._lock_level = 0
82101
self.con = sqlite3.connect(self.lock_file, check_same_thread=False)
@@ -92,16 +111,19 @@ def __init__(
92111
# acquire, so crashes cannot adversely affect the DB. Even journal_mode=OFF would probably
93112
# be fine, too, but the SQLite documentation says that ROLLBACK becomes *undefined behaviour*
94113
# with journal_mode=OFF which sounds scarier.
95-
self.con.execute('PRAGMA journal_mode=MEMORY;')
114+
self.con.execute("PRAGMA journal_mode=MEMORY;")
96115

97116
def acquire_read(self, timeout: float = -1, blocking: bool = True) -> AcquireReturnProxy:
98-
"""Acquire a read lock. If a lock is already held, it must be a read lock.
99-
Upgrading from read to write is prohibited."""
117+
"""
118+
Acquire a read lock. If a lock is already held, it must be a read lock.
119+
Upgrading from read to write is prohibited.
120+
"""
100121
with self._internal_lock:
101122
if self._lock_level > 0:
102123
# Must already be in read mode.
103124
if self._current_mode != "read":
104-
raise RuntimeError("Cannot acquire read lock when a write lock is held (no upgrade allowed)")
125+
msg = "Cannot acquire read lock when a write lock is held (no upgrade allowed)"
126+
raise RuntimeError(msg)
105127
self._lock_level += 1
106128
return AcquireReturnProxy(lock=self)
107129

@@ -117,36 +139,40 @@ def acquire_read(self, timeout: float = -1, blocking: bool = True) -> AcquireRet
117139
if self._lock_level > 0:
118140
# Must already be in read mode.
119141
if self._current_mode != "read":
120-
raise RuntimeError("Cannot acquire read lock when a write lock is held (no upgrade allowed)")
142+
msg = "Cannot acquire read lock when a write lock is held (no upgrade allowed)"
143+
raise RuntimeError(msg)
121144
self._lock_level += 1
122145
return AcquireReturnProxy(lock=self)
123-
124-
self.con.execute('PRAGMA busy_timeout=?;', (timeout_ms,))
125-
self.con.execute('BEGIN TRANSACTION;')
146+
147+
self.con.execute("PRAGMA busy_timeout=?;", (timeout_ms,))
148+
self.con.execute("BEGIN TRANSACTION;")
126149
# Need to make SELECT to compel SQLite to actually acquire a SHARED db lock.
127150
# See https://www.sqlite.org/lockingv3.html#transaction_control
128-
self.con.execute('SELECT name from sqlite_schema LIMIT 1;')
151+
self.con.execute("SELECT name from sqlite_schema LIMIT 1;")
129152

130153
with self._internal_lock:
131154
self._current_mode = "read"
132155
self._lock_level = 1
133-
156+
134157
return AcquireReturnProxy(lock=self)
135158

136159
except sqlite3.OperationalError as e:
137-
if 'database is locked' not in str(e):
160+
if "database is locked" not in str(e):
138161
raise # Re-raise unexpected errors.
139162
raise Timeout(self.lock_file)
140163
finally:
141164
self._transaction_lock.release()
142165

143166
def acquire_write(self, timeout: float = -1, blocking: bool = True) -> AcquireReturnProxy:
144-
"""Acquire a write lock. If a lock is already held, it must be a write lock.
145-
Upgrading from read to write is prohibited."""
167+
"""
168+
Acquire a write lock. If a lock is already held, it must be a write lock.
169+
Upgrading from read to write is prohibited.
170+
"""
146171
with self._internal_lock:
147172
if self._lock_level > 0:
148173
if self._current_mode != "write":
149-
raise RuntimeError("Cannot acquire write lock: already holding a read lock (no upgrade allowed)")
174+
msg = "Cannot acquire write lock: already holding a read lock (no upgrade allowed)"
175+
raise RuntimeError(msg)
150176
self._lock_level += 1
151177
return AcquireReturnProxy(lock=self)
152178

@@ -158,21 +184,24 @@ def acquire_write(self, timeout: float = -1, blocking: bool = True) -> AcquireRe
158184
with self._internal_lock:
159185
if self._lock_level > 0:
160186
if self._current_mode != "write":
161-
raise RuntimeError("Cannot acquire write lock: already holding a read lock (no upgrade allowed)")
187+
msg = "Cannot acquire write lock: already holding a read lock (no upgrade allowed)"
188+
raise RuntimeError(
189+
msg
190+
)
162191
self._lock_level += 1
163192
return AcquireReturnProxy(lock=self)
164-
165-
self.con.execute('PRAGMA busy_timeout=?;', (timeout_ms,))
166-
self.con.execute('BEGIN EXCLUSIVE TRANSACTION;')
193+
194+
self.con.execute("PRAGMA busy_timeout=?;", (timeout_ms,))
195+
self.con.execute("BEGIN EXCLUSIVE TRANSACTION;")
167196

168197
with self._internal_lock:
169198
self._current_mode = "write"
170199
self._lock_level = 1
171-
200+
172201
return AcquireReturnProxy(lock=self)
173202

174203
except sqlite3.OperationalError as e:
175-
if 'database is locked' not in str(e):
204+
if "database is locked" not in str(e):
176205
raise # Re-raise if it is an unexpected error.
177206
raise Timeout(self.lock_file)
178207
finally:
@@ -183,7 +212,8 @@ def release(self, force: bool = False) -> None:
183212
if self._lock_level == 0:
184213
if force:
185214
return
186-
raise RuntimeError("Cannot release a lock that is not held")
215+
msg = "Cannot release a lock that is not held"
216+
raise RuntimeError(msg)
187217
if force:
188218
self._lock_level = 0
189219
else:
@@ -200,10 +230,11 @@ def release(self, force: bool = False) -> None:
200230
# (We provide two context managers as helpers.)
201231

202232
@contextmanager
203-
def read_lock(self, timeout: float | None = None,
204-
blocking: bool | None = None):
205-
"""Context manager for acquiring a read lock.
206-
Attempts to upgrade to write lock are disallowed."""
233+
def read_lock(self, timeout: float | None = None, blocking: bool | None = None):
234+
"""
235+
Context manager for acquiring a read lock.
236+
Attempts to upgrade to write lock are disallowed.
237+
"""
207238
if timeout is None:
208239
timeout = self.timeout
209240
if blocking is None:
@@ -215,10 +246,11 @@ def read_lock(self, timeout: float | None = None,
215246
self.release()
216247

217248
@contextmanager
218-
def write_lock(self, timeout: float | None = None,
219-
blocking: bool | None = None):
220-
"""Context manager for acquiring a write lock.
221-
Acquiring read locks on the same file while helding a write lock is prohibited."""
249+
def write_lock(self, timeout: float | None = None, blocking: bool | None = None):
250+
"""
251+
Context manager for acquiring a write lock.
252+
Acquiring read locks on the same file while helding a write lock is prohibited.
253+
"""
222254
if timeout is None:
223255
timeout = self.timeout
224256
if blocking is None:
@@ -228,9 +260,7 @@ def write_lock(self, timeout: float | None = None,
228260
yield
229261
finally:
230262
self.release()
231-
263+
232264
def __del__(self) -> None:
233265
"""Called when the lock object is deleted."""
234266
self.release(force=True)
235-
236-

0 commit comments

Comments
 (0)