portalocker

Cross-platform file locking for Python, with Redis-backed distributed locks built in.

Library
PyPI
v4.3.0
326stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
80/100Excellent
Development Activity96
Maintenance72
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
89/100Excellent
Architecture85
Code Quality96
Innovation90
Learning Curve85

Portalocker gives Python programs a single, cross-platform API for file locking, wrapping the POSIX fcntl/flock primitives and the Windows msvcrt/pywin32 APIs behind the same Lock and RLock context managers. It handles the retry semantics — timeout, check interval, fail-when-locked — so a process contending for a lock backs off and retries automatically instead of leaving that logic to every caller.

Beyond ordinary file locks, portalocker adds NamedBoundedSemaphore for capping concurrent access across processes, PidFileLock for the classic PID-file singleton pattern with the ability to inspect who currently holds the lock, and a RedisLock built on Redis pubsub for coordinating processes that share no filesystem at all. The library ships fully typed, is tested to 100% branch coverage across Linux, macOS, and Windows, and can be vendored down to a single combined portalocker.py file for projects that cannot take a dependency.

What You Get

  • Cross-platform Lock/RLock context managers wrapping fcntl (POSIX) and msvcrt/pywin32 (Windows)
  • PidFileLock for PID-file-based singleton processes, exposing the current holder’s PID
  • BoundedSemaphore/NamedBoundedSemaphore for capping concurrent access across processes via a directory of lock files
  • RedisLock, a pubsub-based distributed lock for coordinating processes with no shared filesystem
  • open_atomic helper for atomic file writes via temp-file-then-rename
  • Full type hints (py.typed) verified under mypy strict, pyright, pyrefly, and ty

Common Use Cases

  • Preventing concurrent writers from corrupting a shared cache or log file
  • Enforcing a single running instance of a script or daemon via a PID file
  • Rate-limiting concurrent access to a resource pool with NamedBoundedSemaphore
  • Coordinating locks across machines with no shared disk using RedisLock
  • Writing files atomically so readers never see partial content

Under The Hood

Architecture The modules form a clean layered stack: constants.py defines the LockFlags enum; portalocker.py holds the platform-specific low-level lock/unlock primitives (dispatching to fcntl on POSIX or msvcrt/pywin32 on Windows) behind LockCallable/UnlockCallable protocols and never imports the layer above it; utils.py defines the abstract LockBase, which owns the timeout/check-interval/fail-when-locked retry loop, with every concrete class (Lock, RLock, TemporaryFileLock, PidFileLock, BoundedSemaphore, NamedBoundedSemaphore) inheriting that same retry generator; redis.py implements an independent pubsub-based RedisLock that is imported lazily so its absence never breaks the package; and init.py re-exports the public surface, substituting a stub RedisLock class (whose constructor raises a clear ImportError) when the optional redis dependency is missing. exceptions.py is a separate hierarchy (BaseLockException -> LockException -> AlreadyLocked/LockLostError) with custom pickling behavior so exceptions survive a multiprocessing round trip intact.

Tech Stack Pure Python with zero mandatory runtime dependencies, requiring Python 3.10+; optional extras add redis>=5.0 for RedisLock and pywin32>=226 for Windows shared locks. Packaging is PEP 621-only (pyproject.toml, no setup.py) built with uv_build, Astral’s native build backend. Type-checking runs four independent checkers in CI — mypy in strict mode, pyright/basedpyright, pyrefly, and ty — alongside ruff for lint/format and codespell for spelling. Testing uses pytest with pytest-cov enforcing 100% branch coverage, pytest-timeout, pytest-rerunfailures, and a custom coverage-conditional-plugin for OS-specific branch exclusion. Docs are built with Sphinx and the furo theme, hosted on ReadTheDocs; release automation runs through lefthook git hooks and a tag-triggered, preflight-gated GitHub Actions publish workflow.

Code Quality The test suite spans dozens of files covering timeout behavior, Windows-specific locking, version metadata, and write-mode semantics, plus doctests embedded directly in docstrings and README.rst that execute as part of the suite so the documentation cannot silently drift from the code. Error handling is explicit and typed throughout, with structured exception attributes (fh, fh_name, strerror) rather than swallowed failures. Every public class and function carries a Google-style docstring with Args/Returns/Raises/Examples sections, naming is consistent and descriptive, and the CI matrix runs across Ubuntu, macOS, and Windows on Python 3.10 through 3.14 plus PyPy, spinning up a live Redis server for the distributed-lock tests.

API Design Every lock type shares the same context-manager protocol and constructor conventions (timeout, check_interval, fail_when_locked), so swapping between a plain file lock, a PID-file lock, and a distributed Redis lock requires minimal code changes. The common case needs no configuration at all, and the library degrades gracefully when optional extras are absent — importing the package never fails just because redis or pywin32 isn’t installed. Documentation is unusually thorough for a small library, with a dedicated docs site covering quickstart, migration, platform notes, and troubleshooting alongside the doctested README, and a small maintainer-only CLI exists solely to vendor the package into a single combined file.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search