MCPcopy Create free account
hub / github.com/tox-dev/filelock / AsyncReadWriteLock

Class AsyncReadWriteLock

src/filelock/_async_read_write.py:40–314  ·  view source on GitHub ↗

Async wrapper around :class:`ReadWriteLock` for use in ``asyncio`` applications. This wrapper dispatches every blocking SQLite operation to a thread pool via ``loop.run_in_executor()`` because Python's :mod:`sqlite3` module has no async API. It delegates reentrancy, upgrade/downgrade r

Source from the content-addressed store, hash-verified

38
39
40class AsyncReadWriteLock:
41 """
42 Async wrapper around :class:`ReadWriteLock` for use in ``asyncio`` applications.
43
44 This wrapper dispatches every blocking SQLite operation to a thread pool via ``loop.run_in_executor()`` because
45 Python's :mod:`sqlite3` module has no async API. It delegates reentrancy, upgrade/downgrade rules, and singleton
46 behavior to the underlying :class:`ReadWriteLock`.
47
48 :param lock_file: path to the SQLite database file used as the lock
49 :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely
50 :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable
51 :param is_singleton: if ``True``, reuse existing :class:`ReadWriteLock` instances for the same resolved path
52 :param loop: event loop for ``run_in_executor``; ``None`` uses the running loop
53 :param executor: executor for ``run_in_executor``. When ``None`` this lock creates and owns a dedicated
54 single-thread executor so every operation runs on the same thread (SQLite affinity requires this) and shuts it
55 down in :meth:`close`. This lock uses a caller-supplied executor as-is and never shuts it down, so after passing
56 no executor call :meth:`close` to release the owned one.
57
58 .. versionadded:: 3.21.0
59
60 """
61
62 def __init__( # ruff:ignore[too-many-arguments] # public constructor: one parameter per documented lock option
63 self,
64 lock_file: str | os.PathLike[str],
65 timeout: float = -1,
66 *,
67 blocking: bool = True,
68 is_singleton: bool = True,
69 loop: asyncio.AbstractEventLoop | None = None,
70 executor: futures.Executor | None = None,
71 ) -> None:
72 creator_pid = os.getpid()
73 self._creator_pid = creator_pid
74 self._fork_invalidated = False
75 self._closed = False
76 _register_fork_object(self)
77 with _fork_transition():
78 self._lock = ReadWriteLock(lock_file, timeout, blocking=blocking, is_singleton=is_singleton)
79 self._loop = loop
80 self._owns_executor = executor is None
81 self._executor = executor or ThreadPoolExecutor(max_workers=1)
82 if os.getpid() != creator_pid: # pragma: forked child
83 msg = "AsyncReadWriteLock construction cannot continue after fork"
84 raise RuntimeError(msg)
85
86 @property
87 def lock_file(self) -> str:
88 """The path to the lock file."""
89 return self._lock.lock_file
90
91 @property
92 def timeout(self) -> float:
93 """The default timeout."""
94 return self._lock.timeout
95
96 @property
97 def blocking(self) -> bool:

Calls

no outgoing calls