Changelog¶
Unreleased (2026-07-21)¶
3.32.0 (2026-07-21)¶
SoftReadWriteLockcloses the directory handle it opens to scan for readers as soon as a scan stops early, rather than holding it until the generator is collected. PR #685Declare support for Python 3.15 and run the test suite against it and its free-threaded build, both currently in beta. PR #683
The source distribution ships the capability probes the tests import, and reading one no longer needs
coverageinstalled, so the suite runs from an unpacked sdist instead of failing on a missingcoverage_pragmas. PR #685
3.31.2 (2026-07-21)¶
filelockimports again on runtimes whoseerrnoomitsENOTSUP, such as GraalPy, where importing the package raisedImportError. It probes the code instead, preferringENOTSUP, falling back toEOPNOTSUPPwhere that name is absent, and dropping toENOSYS/EXDEVwhere neither exists. Platforms definingENOTSUPkeep their behavior. PR #681
3.31.1 (2026-07-20)¶
A
SoftFileLeaseacquired on one thread keeps its claim when another thread fails to acquire the same lease object, so its heartbeat carries on refreshing the marker instead of being torn down and letting a peer take the live claim. PR #680
3.31.0 (2026-07-18)¶
Support Termux/Android, whose CPython ships without
os.linkand reportssys.platform == "android".import filelockand bothFileLockandSoftFileLocknow work there,StrictSoftFileLockreports its missing hard-link support only when acquired, and process liveness reads/procon Android instead of PID-only checks. PR #678StrictSoftFileLockno longer lets two processes hold the lock at once under heavy contention. A holder now keeps its intent claim for the whole hold, so a contender whose directory scan races the holder’s freshly linked claim can no longer miss it and win alongside it. A held lock now exposes both anintentand aheldclaim. PR #678
3.30.3 (2026-07-17)¶
AsyncFileLockandAsyncSoftFileLockno longer raise a deadlockRuntimeErrorwhen a different asyncio task waits for a lock they hold; the check now scopes holders to the owning task, so only a same-task reacquire is refused. PR #676Keep both tables of contents on screen at any browser font size. The widened body column sized itself in
emagainst the reader’s font size while the breakpoints that fold the layout resolveemagainst a fixed 16px, so a reader whose default font is larger than 16px had the right-hand table of contents clipped off the edge. The body column now flexes instead, and the right-hand table of contents hides only at the mobile breakpoint. PR #673Color the mermaid diagrams from whichever theme is active. They previously carried a light palette baked into each diagram’s source, which stayed light on a dark page. PR #674
3.30.2 (2026-07-16)¶
Stop
SoftFileLeasedeleting a live marker whosemodeit does not implement. An unrecognized mode now names its owner instead of reading as malformed, so a record written by a newer filelock survives the grace window rather than being evicted after two seconds. PR #672Stop
StrictSoftFileLockandAsyncStrictSoftFileLockcalling themselves a native OS lock when they warn that they ignorelifetime; they now say a strict claim is only ever cleared byforce_break(). PR #672Cover every lock type in the tutorials and how-to guides, with examples drawn from projects that use filelock, and color the mermaid diagrams. Correct the claims that
StrictSoftFileLockexposesowner, thatSoftFileLockevicts a strict sentinel, thatReadWriteLockrequires a.dbextension, and that every log record isDEBUG. PR #672
3.30.1 (2026-07-16)¶
StrictSoftFileLockandAsyncStrictSoftFileLockno longer abort acquisition when a peer’s claim vanishes as an NFSv3 stale filehandle instead of a clean removal; the reader revalidates and skips it, so strict locks hold mutual exclusion across independent NFSv3 client caches. PR #669SoftFileLeasereads a marker whose lease duration isnanorinfas malformed rather than as a valid lease, so such a marker ages out through the grace window instead of raisingLeaseSettingsMismatchon every contender. PR #670
3.30.0 (2026-07-16)¶
Add
context_error_policyto surface body and release failures as aBaseExceptionGroup. PR #618Add
close_error_policyto control anos.close()failure after the OS unlock. PR #619Add
lock_descriptor()andunlock_descriptor()to lock a caller-owned file descriptor. PR #620Add
fallback_to_softto fail closed instead of downgrading toSoftFileLockonENOSYS. PR #622Add
preserve_lock_fileso native locks keep the lock pathname on release. PR #624Add an
on_acquiredhook that runs a callback on the locked descriptor once the lock is held. PR #625Add
StrictSoftFileLock, which treats every marker it did not publish as contention, andSoftFileLease, whose claim expires and whose holder learns throughon_compromisewhen it is lost.SoftFileLock(lifetime=...)now warns and names them. Both publish a recordSoftFileLockevicts, so do not mix contracts on one path. PR #636Add
StrictSoftFileLockandAsyncStrictSoftFileLockwith owner-specific hard-linked claims. Strict mode fails closed on claim damage, exposes each recovery token, and requires an exact claim name for a force break. PR #637Ignore
lifetimeon native locks with a warning; onlySoftFileLockhonors it. PR #593Stop mutating the Unix lock file before
fcntl.flock()is held. PR #594Bind the Windows reparse-point check to the locked handle to close a symlink-swap race. PR #596
Evict a non-regular soft lock file without reading it. PR #597
Write a soft lock’s holder record atomically so a short write cannot create overlapping holders. PR #614
Make native lock release transactional so a failed unlock is retried, not dropped. PR #615
Open the Windows lock file via
NtCreateFileso a real access denial is raised, not reported as a timeout. PR #617Canonicalize singleton keys so equivalent path spellings share an instance, without following a final symlink. PR #621
Preserve parent lock ownership across
fork(). A child closes an inherited descriptor only while its identity still matches, so it neither unlocks nor unlinks the parent’s lock. It clears inherited ownership state and singleton caches, then requires a new lock instance before acquiring. Fork-time construction replaces inherited cache mutexes and omits an instance whose construction crossed into the child from the cache. Iffstat()cannot establish the identity, child cleanup skips the descriptor number because an earlier fork callback may have reused it. Descriptor tracking also covers third-party backends that fail after assigning a descriptor. PR #634Open a SQLite connection per outer acquisition and close it on final release, so a forked child can no longer close its parent’s handle. A child rejects inherited databases until
exec(), and a PyPy child rejects read-write locks once the parent has used SQLite. PR #635Keep executor-backed lock operations alive until they finish when a caller cancels. Serialize acquisitions on the same async lock so cancellation rollback cannot release a later caller’s hold. Roll back acquisitions that finish after cancellation and surface release failures. SQLite read-write locks keep their state until rollback ends the transaction; callers can retry cleanup with
release(force=True)or another acquisition. PR #640Reject negative and non-finite
lifetimevalues during lock construction and assignment. PR #644Read the saved Windows process-probe error before deciding that a soft-lock holder has exited. PR #645
Reject non-default lock options that a narrow subclass constructor cannot honor, and forward all options through subclasses that accept arbitrary keyword arguments. PR #646
Release now removes the path identity that acquisition recorded instead of resolving a symlinked parent again. When acquisition raises, its rollback no longer deletes the holder’s deadlock record. PR #647
Remove the body error from implicit context on the release error before adding both errors to an exception group. PR #648
Relinquish a soft lock’s descriptor before one close attempt so a later release cannot close a reused descriptor number, and honor
close_error_policywhile still attempting marker cleanup. PR #649Raise
OSError(errno.ENOSYS)from descriptor locks whenfcntlis unavailable, and reject invalid blocking poll intervals before attempting a lock. PR #650SoftFileLockandSoftFileLeaserecord the holder’s process start time on every platform and reclaim a stale marker only when the recorded owner is provably gone. A reused PID on Unix no longer breaks a live lock or wedges acquisition, matching the recycled-PID detection Windows already had. PR #660SoftReadWriteLockandSoftFileLeaseride out a transient filesystem error during a heartbeat instead of dropping the lock or reporting a false compromise, and report a lost claim only once refresh cannot recover before the lease would lapse.SoftFileLeasealso reclaims a malformed or partial marker that used to block every contender, and a Linux marker distinguishes a PID reused across a reboot. PR #661BaseFileLock.__del__suppresses a release error rather than raising it during garbage collection, where it surfaced as an unraisable-exception warning attributed to unrelated code. PR #665Correct the Unix lock-file cleanup and
fcntl.flock()documentation. PR #623Drop automated bot entries from the changelog and link its code references to the API docs and the Python standard library. PR #638
Refresh the documentation to the current code: a new trust-boundaries and ownership-scope section (same-UID boundary, advisory native locks, strict claims and lease fencing, a filesystem support matrix, migration off timed stale breaking), the lock-selection flowchart and comparison tables extended with
StrictSoftFileLockandSoftFileLease, and the cross-platform process start token replacing the Windows-only description throughout. PR #663The filesystem support matrix records mutual exclusion measured across two independent client caches in CI: NFS (v4 and v3) for the native, soft, and strict locks, and SMB for the native and soft locks. PR #665
Build the changelog from towncrier news fragments, render pending fragments as an
Unreleaseddocs section, and refuse to publish a tag the changelog does not document. PR #626
3.29.7 (2026-07-07)¶
_util: drop the dead
st_mtime=0short-circuit inraise_on_not_writable_filePR #589 - by @HrachShahsoft_rw: evict a non-regular write marker without reading it PR #588
asyncio: detect cross-instance reentrant deadlocks before the poll loop PR #586 - by @HrachShah
3.29.6 (2026-07-06)¶
test: silence fork DeprecationWarning on 3.15 PR #585
_util: drop the dead
st_mtime=0short-circuit inraise_on_not_writable_filePR #582 - by @HrachShahserialize singleton construction in
FileLockMetaPR #581 - by @dxbjavidsurface GitHub Sponsors and thanks.dev
3.29.5 (2026-07-02)¶
lifetime: reject negative, non-numeric, and bool values at the setter PR #573 - by @HrachShah
roll back a read acquire’s open transaction when its SELECT fails PR #575 - by @dxbjavid
keep Unix lock files after release PR #577 - by @itscloud0
use a private break name in
break_lock_filePR #576 - by @dxbjaviddon’t complete a writer acquire on a peer’s reclaimed marker PR #571 - by @dxbjavid
don’t follow symlinks in
raise_on_not_writable_filePR #567 - by @dxbjavidonly unlink the writer marker on release if it is still ours PR #566 - by @dxbjavid
don’t follow symlinks when refreshing soft read/write lock markers PR #565 - by @dxbjavid
serialize read/write release rollback against a concurrent acquire PR #563 - by @dxbjavid
3.29.4 (2026-06-13)¶
3.29.3 (2026-06-10)¶
3.29.2 (2026-06-10)¶
3.29.1 (2026-06-03)¶
🐛 fix(soft): refuse to follow symlinks when reading the lock file PR #548 - by @dxbjavid
chore: improve filelock maintenance path PR #545 - by @lphuc2250gma
chore: improve filelock maintenance path PR #544 - by @lphuc2250gma
chore: improve filelock maintenance path PR #542 - by @lphuc2250gma
docs: clarify per-thread scope of
FileLockconfiguration PR #543 - by @Gares95
3.29.0 (2026-04-19)¶
3.28.0 (2026-04-14)¶
🐛 fix(ci): unbreak release workflow, publish to PyPI again PR #529
3.26.1 (2026-04-09)¶
🐛 fix(asyncio): add
__exit__toBaseAsyncFileLockand fix__del__loop handling PR #518 - by @naarob
3.26.0 (2026-04-06)¶
3.25.2 (2026-03-11)¶
🐛 fix(unix): suppress
EIOon close in Docker bind mounts PR #513
3.25.1 (2026-03-09)¶
3.25.0 (2026-03-01)¶
✨ feat(async): add
AsyncReadWriteLockPR #506Standardize .github files to .yaml suffix
Move SECURITY.md to .github/SECURITY.md
Add security policy
Add permissions to check workflow PR #500
3.24.3 (2026-02-19)¶
3.24.2 (2026-02-16)¶
🐛 fix(rw): close
sqlite3cursors and skipSoftFileLockWindows race PR #491🐛 fix(test): resolve flaky write non-starvation test PR #490
📝 docs: restructure using Diataxis framework PR #489
3.24.1 (2026-02-15)¶
🐛 fix(soft): resolve Windows deadlock and test race condition PR #488
3.24.0 (2026-02-14)¶
✨ feat(lock): add
lifetimeparameter for lock expiration (#68) PR #486🐛 fix(api): detect same-thread self-deadlock PR #481
✨ feat(mode): respect POSIX default ACLs (#378) PR #483
🐛 fix(win): eliminate lock file race in threaded usage PR #484
✨ feat(lock): add
poll_intervalto constructor PR #482🐛 fix(unix): auto-fallback to
SoftFileLockonENOSYSPR #480
3.23.0 (2026-02-14)¶
3.22.0 (2026-02-14)¶
3.21.2 (2026-02-13)¶
🐛 fix: catch
ImportErrorfor missingsqlite3C library PR #475
3.21.1 (2026-02-12)¶
🐛 fix: gracefully handle missing
sqlite3when importingReadWriteLockPR #473 - by @bayandin🐛 fix(ci): make release workflow robust
3.21.0 (2026-02-12)¶
🐛 fix(ci): make release workflow robust
👷 ci(release): commit changelog and use release config PR #472
👷 ci(release): consolidate to two jobs PR #471
✨ feat(unix): delete lock file on release PR #408 - by @sbc100
✨ feat(lock): add SQLite-based
ReadWriteLockPR #399 - by @leventov🔧 chore: modernize tooling and bump deps PR #470
v3.20.3 (2026-01-09)¶
Fix TOCTOU symlink vulnerability in
SoftFileLockPR #465.
v3.20.2 (2026-01-02)¶
Support Unix systems without
os.O_NOFOLLOWPR #463.
v3.20.1 (2025-12-15)¶
Fix TOCTOU symlink vulnerability in lock file creation PR #461.
v3.20.0 (2025-10-08)¶
v3.19.1 (2025-08-14)¶
Increase test coverage PR #434.
v3.19.0 (2025-08-13)¶
Add support for Python 3.14 PR #432.
v3.18.0 (2025-03-11)¶
v3.17.0 (2025-01-21)¶
Drop Python 3.8 support PR #388.
v3.16.1 (2024-09-17)¶
CI improvements PR #362.
v3.16.0 (2024-09-07)¶
Add Python 3.13 to CI PR #359.
v3.15.4 (2024-06-22)¶
Pass
file_lockas positional argument PR #347.
v3.15.3 (2024-06-19)¶
Fix
TypeError: _CountedFileLock.__init__() got an unexpected keyword argumentPR #345.
v3.15.2 (2024-06-19)¶
Use a metaclass to implement the singleton pattern PR #340.
v3.15.1 (2024-06-12)¶
Restore
__init__method; more robust initialization for singleton locks PR #338.
v3.15.0 (2024-06-11)¶
Add asyncio support PR #332.
Don’t re-initialize
BaseFileLockwhen returning existing singleton instance PR #334.
v3.14.0 (2024-04-27)¶
Add
blockingparameter on lock constructor PR #325.
v3.13.4 (2024-04-09)¶
Raise error on incompatible singleton
timeoutandmodearguments PR #320.
v3.13.3 (2024-03-25)¶
Make singleton class instance dict unique per subclass PR #318.
v3.13.2 (2024-03-25)¶
Fix permission denied error when lock file is placed in
/tmpPR #317.
v3.13.1 (2023-10-30)¶
v3.13.0 (2023-10-27)¶
Support reentrant locking on lock file path via optional
is_singletoninstance PR #283.
v3.12.4 (2023-09-13)¶
Change
typing-extensionsto be installed only with the[typing]extra PR #276.
v3.12.3 (2023-08-28)¶
v3.12.2 (2023-06-12)¶
v3.12.1 (2023-06-10)¶
v3.12.0 (2023-04-18)¶
Make the thread local behavior something the caller can enable/disable via a flag during the lock creation, it’s on by default.
Better error handling on Windows.
v3.11.0 (2023-04-06)¶
Make the lock thread local.
v3.10.7 (2023-03-27)¶
Use
os.fchmod()instead ofos.chmod()to work around bug in PyPy via Anaconda.
v3.10.6 (2023-03-25)¶
Enhance the robustness of the try/catch block in _soft.py. by @jahrules.
v3.10.5 (2023-03-25)¶
Add explicit error check as certain UNIX filesystems do not support flock. by @jahrules.
v3.10.4 (2023-03-24)¶
Update os.open to preserve mode= for certain edge cases. by @jahrules.
v3.10.3 (2023-03-23)¶
Fix permission issue - by @jahrules.
v3.10.2 (2023-03-22)¶
Bug fix for using filelock with threaded programs causing undesired file permissions - by @jahrules.
v3.10.1 (2023-03-22)¶
v3.10.0 (2023-03-15)¶
v3.9.1 (2023-03-14)¶
Use
time.perf_counter()instead oftime.monotonic()for calculating timeouts.
v3.9.0 (2022-12-28)¶
Move build backend to
hatchlingPR #185 - by @gaborbernat.
v3.8.1 (2022-12-04)¶
Fix mypy does not accept
FileLockas a valid type
v3.8.0 (2022-12-04)¶
Bump project dependencies
Add timeout unit to docstrings
Support 3.11
v3.7.1 (2022-05-31)¶
Make the readme documentation point to the index page
v3.7.0 (2022-05-13)¶
Add ability to return immediately when a lock cannot be obtained
v3.6.0 (2022-02-17)¶
Fix pylint warning “Abstract class
WindowsFileLockwith abstract methods instantiated” PR #135 - by @vonschultzFix pylint warning “Abstract class
UnixFileLockwith abstract methods instantiated” PR #135 - by @vonschultz
v3.5.1 (2022-02-16)¶
Use
time.monotonic()instead oftime.time()for calculating timeouts.
v3.5.0 (2022-02-15)¶
Enable use as context decorator
v3.4.2 (2021-12-16)¶
Drop support for python
3.6
v3.4.1 (2021-12-16)¶
Add
stacklevelto deprecation warnings for argument name change
v3.4.0 (2021-11-16)¶
Add correct spelling of poll interval parameter for
acquire()method, raise deprecation warning when using the misspelled form PR #119 - by @XuehaiPan.
v3.3.2 (2021-10-29)¶
Accept path types (like
pathlib.Pathandpathlib.PurePath) in the constructor forFileLockobjects.
v3.3.1 (2021-10-15)¶
Add changelog to the documentation PR #108 - by @gaborbernat
Leave the log level of the
filelocklogger as not set (previously was set to warning) PR #108 - by @gaborbernat
v3.3.0 (2021-10-03)¶
Drop python 2.7 and 3.5 support, add type hints PR #100 - by @gaborbernat
Document asyncio support - by @gaborbernat
v3.2.1 (2021-10-02)¶
v3.2.0 (2021-09-30)¶
Raise when trying to acquire in R/O or missing folder PR #96 - by @gaborbernat
Move lock acquire/release log from INFO to DEBUG PR #95 - by @gaborbernat
Fix spelling and remove ignored flake8 checks - by @gaborbernat
Split main module PR #94 - by @gaborbernat
Move test suite to pytest PR #93 - by @gaborbernat
v3.1.0 (2021-09-27)¶
Fixed link to LICENSE file PR #63 - by @sharkwouter
Adopt tox-dev organization best practices PR #87 - by @gaborbernat
Ownership moved from @benediktschmitt to the tox-dev organization (new primary maintainer @gaborbernat)
v3.0.12 (2019-05-18)¶
fixed setuptools and twine/warehouse error by making the license only 1 line long
update version for pypi upload
fixed python2 setup error
added test.py module to MANIFEST and made tests available in the setup commands issue #48
fixed documentation thanks to @AnkurTank issue #49
Update Trove classifiers for PyPI
test: Skip test_del on PyPy since it hangs
v3.0.10 (2018-11-01)¶
Fix README rendering on PyPI
v3.0.9 (2018-10-02)¶
PR #38 from cottsay/shebang
updated docs config for older sphinx compatibility
removed misleading shebang from module
v3.0.8 (2018-09-09)¶
updated use setuptools
v3.0.7 (2018-09-09)¶
fixed garbage collection (issue #37)
fix travis ci badge (use rst not markdown)
changed travis uri
v3.0.6 (2018-08-22)¶
clean up
Fixed unit test for Python 2.7
Added Travis banner
Added Travis CI support
v3.0.5 (2018-04-26)¶
Corrected the prequel reference
v3.0.4 (2018-02-01)¶
updated README
v3.0.3 (2018-01-30)¶
updated readme
v3.0.1 (2018-01-30)¶
updated README (added navigation)
updated documentation issue #22
fix the
SoftFileLocktest was influenced by the test forFileLockundo
cb1d83dissue #31
v3.0.0 (2018-01-05)¶
v2.0.13 (2017-11-05)¶
changed The logger is now acquired when first needed. issue #24
v2.0.12 (2017-09-02)¶
correct spelling mistake
v2.0.11 (2017-07-19)¶
added official support for python 2 issue #20
v2.0.10 (2017-06-07)¶
updated readme
v2.0.9 (2017-06-07)¶
v2.0.8 (2017-01-24)¶
Added logging
Removed unused imports
v2.0.7 (2016-11-05)¶
fixed issue #14 (moved license and readme file to
MANIFEST)
v2.0.6 (2016-05-01)¶
changed unlocking sequence to fix transient test failures
changed threads in tests so exceptions surface
added test lock file cleanup
v2.0.5 (2015-11-11)¶
Don’t remove file after releasing lock
updated docs
v2.0.4 (2015-07-29)¶
added the new classes to
__all__
v2.0.3 (2015-07-29)¶
added The
SoftFileLockis now always tested
v2.0.2 (2015-07-29)¶
The filelock classes are now always available and have been moved out of the
if msvrct: ... elif fcntl ... elseclauses.
v2.0.1 (2015-06-13)¶
v2.0.0 (2015-05-25)¶
added default timeout (fixes issue #2)
v1.0.3 (2015-04-22)¶
added new test case, fixed unhandled exception
v1.0.2 (2015-04-22)¶
fixed a timeout could still be thrown if the lock is already acquired
v1.0.1 (2015-04-22)¶
fixed issue #1
v1.0.0 (2015-04-07)¶
added lock counter, added unittest, updated to version 1
changed filenames
updated version for pypi
updated README, LICENSE (changed format from md to rst)
added MANIFEST to gitignore
added os independent file lock ; changed setup.py for pypi
Update README.md
initial version