Abstract base class for a file lock object. Provides the common reentrant API and state management. Subclasses implement the locking mechanism (:class:`UnixFileLock `, :class:`WindowsFileLock `, :class:`SoftFileLock <filelock.SoftFil
| 585 | |
| 586 | |
| 587 | class BaseFileLock(contextlib.ContextDecorator, metaclass=FileLockMeta): # ruff:ignore[too-many-public-methods] # public config properties |
| 588 | """ |
| 589 | Abstract base class for a file lock object. |
| 590 | |
| 591 | Provides the common reentrant API and state management. Subclasses implement the locking mechanism |
| 592 | (:class:`UnixFileLock <filelock.UnixFileLock>`, :class:`WindowsFileLock <filelock.WindowsFileLock>`, |
| 593 | :class:`SoftFileLock <filelock.SoftFileLock>`). |
| 594 | |
| 595 | """ |
| 596 | |
| 597 | _instances: WeakValueDictionary[str, BaseFileLock] |
| 598 | _instances_lock: RLock |
| 599 | _instances_under_construction: set[str] |
| 600 | |
| 601 | #: How the cross-instance deadlock message names the conflicting holder; the async subclass says "task". |
| 602 | _deadlock_holder_desc: str = "FileLock instance in this thread" |
| 603 | |
| 604 | #: Whether an age-based :attr:`lifetime` lease may break this lock. Only existence locks set it (they reclaim by |
| 605 | #: unlinking a pathname); native OS locks leave it ``False`` since a kernel lock cannot be revoked by file age. |
| 606 | _lifetime_supported: bool = False |
| 607 | |
| 608 | #: Strict-lock and lease replacements for a backend with legacy age-based expiry. |
| 609 | _lifetime_replacements: tuple[str, str] | None = None |
| 610 | |
| 611 | #: Why a backend that refuses ``lifetime`` cannot honor it, named in the warning that drops the value. |
| 612 | _lifetime_unsupported_reason: str = "a native OS lock cannot be broken safely by file age" |
| 613 | |
| 614 | #: Async construction adds one metaclass frame before lifetime validation. |
| 615 | _constructor_lifetime_warning_stacklevel: int = 3 |
| 616 | |
| 617 | #: Whether :attr:`preserve_lock_file` may be ``True``. Native locks keep the pathname on release, so they support |
| 618 | #: it; existence locks unlink their marker to release and reject it. |
| 619 | _preserve_lock_file_supported: bool = True |
| 620 | |
| 621 | #: Whether an :attr:`on_acquired` hook may be set. Native locks lend the descriptor out; existence locks keep |
| 622 | #: protocol state in the marker and reject it. |
| 623 | _on_acquired_supported: bool = True |
| 624 | |
| 625 | #: Whether a shared instance serializes its physical acquire and release behind one gate. A backend that publishes |
| 626 | #: several files per owner needs it; a single-file backend is atomic and leaves it off to skip the gate entirely. |
| 627 | _serialize_transitions: bool = False |
| 628 | |
| 629 | #: Ceiling in seconds on the jittered backoff between contended acquisition retries. ``0`` keeps the fixed |
| 630 | #: poll cadence; a multi-file backend sets it so contending processes desynchronize instead of livelocking. |
| 631 | _poll_backoff_cap: float = 0.0 |
| 632 | |
| 633 | def __init_subclass__(cls, **kwargs: _SubclassValue) -> None: |
| 634 | """Give each lock subclass its own singleton registry and lock.""" |
| 635 | super().__init_subclass__(**kwargs) |
| 636 | cls._instances = WeakValueDictionary() |
| 637 | cls._instances_lock = RLock() |
| 638 | cls._instances_under_construction = set() |
| 639 | _register_fork_class(cls) |
| 640 | |
| 641 | @classmethod |
| 642 | def _reset_class_after_fork(cls) -> None: # pragma: forked child |
| 643 | cls._instances = WeakValueDictionary() |
| 644 | cls._instances_lock = RLock() |
nothing calls this directly
no outgoing calls
no test coverage detected