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

Class AsyncReadWriteLock

src/filelock/_async_read_write.py:38–210  ·  view source on GitHub ↗

Async wrapper around :class:`ReadWriteLock` for use in ``asyncio`` applications. Because Python's :mod:`sqlite3` module has no async API, all blocking SQLite operations are dispatched to a thread pool via ``loop.run_in_executor()``. Reentrancy, upgrade/downgrade rules, and singleton be

Source from the content-addressed store, hash-verified

36
37
38class AsyncReadWriteLock:
39 """
40 Async wrapper around :class:`ReadWriteLock` for use in ``asyncio`` applications.
41
42 Because Python's :mod:`sqlite3` module has no async API, all blocking SQLite operations are dispatched to a thread
43 pool via ``loop.run_in_executor()``. Reentrancy, upgrade/downgrade rules, and singleton behavior are delegated
44 to the underlying :class:`ReadWriteLock`.
45
46 :param lock_file: path to the SQLite database file used as the lock
47 :param timeout: maximum wait time in seconds; ``-1`` means block indefinitely
48 :param blocking: if ``False``, raise :class:`~filelock.Timeout` immediately when the lock is unavailable
49 :param is_singleton: if ``True``, reuse existing :class:`ReadWriteLock` instances for the same resolved path
50 :param loop: event loop for ``run_in_executor``; ``None`` uses the running loop
51 :param executor: executor for ``run_in_executor``. When ``None`` a dedicated single-thread executor is created
52 and owned by this lock, ensuring every operation runs on the same thread (required for SQLite affinity); it
53 is shut down by :meth:`close`. A caller-supplied executor is used as-is and never shut down here, so when no
54 executor is passed remember to call :meth:`close` to release the owned one.
55
56 .. versionadded:: 3.21.0
57
58 """
59
60 def __init__( # noqa: PLR0913
61 self,
62 lock_file: str | os.PathLike[str],
63 timeout: float = -1,
64 *,
65 blocking: bool = True,
66 is_singleton: bool = True,
67 loop: asyncio.AbstractEventLoop | None = None,
68 executor: futures.Executor | None = None,
69 ) -> None:
70 self._lock = ReadWriteLock(lock_file, timeout, blocking=blocking, is_singleton=is_singleton)
71 self._loop = loop
72 self._owns_executor = executor is None
73 self._executor = executor or ThreadPoolExecutor(max_workers=1)
74
75 @property
76 def lock_file(self) -> str:
77 """The path to the lock file."""
78 return self._lock.lock_file
79
80 @property
81 def timeout(self) -> float:
82 """The default timeout."""
83 return self._lock.timeout
84
85 @property
86 def blocking(self) -> bool:
87 """Whether blocking is enabled by default."""
88 return self._lock.blocking
89
90 @property
91 def loop(self) -> asyncio.AbstractEventLoop | None:
92 """The event loop (or ``None`` for the running loop)."""
93 return self._loop
94
95 @property

Callers 15

test_reentrant_readFunction · 0.90
test_reentrant_writeFunction · 0.90
test_upgrade_prohibitedFunction · 0.90
test_non_blocking_readFunction · 0.90
test_non_blocking_writeFunction · 0.90
test_timeout_expiresFunction · 0.90

Calls

no outgoing calls

Tested by 15

test_reentrant_readFunction · 0.72
test_reentrant_writeFunction · 0.72
test_upgrade_prohibitedFunction · 0.72
test_non_blocking_readFunction · 0.72
test_non_blocking_writeFunction · 0.72
test_timeout_expiresFunction · 0.72

Used in the wild real call sites across dependent graphs

searching dependent graphs…