unstale

pypi / portalocker

portalocker

What changed in portalocker 3 to 4, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-29.

30 breaking2 security5 deprecations20 new APIs and options1 performance9 behavior and defaults1 tooling46 fixes and other

See which of these apply to your code, ranked, in your agent:

npx @unstale/cli init

@unstale/cli 0.2.9 on npm

portalocker 4113 changes

Breaking changes 29

  • Reacquiring a semaphore instance that already holds a slot now raises LockException instead of AssertionError.

    4.2.0release notes

  • Lock resolves its path with os.path.abspath at construction, so filename now contains an absolute path and later chdir calls do not redirect lock-file operations.

    4.2.0release notes

  • Flags are validated on every platform before system calls; UNBLOCK, SHARED | EXCLUSIVE, and flags naming no lock type raise RuntimeError.

    4.2.0release notes

  • On POSIX, modes containing w now clear O_APPEND after deferred truncation, so positioned writes behave like builtin open(mode='w'). Windows append semantics remain.

    4.2.0release notes

  • An exception from the with-block now takes precedence over a release error, which is chained as its context.

    4.2.0release notes

  • Only AlreadyLocked contention is retried. Other LockException failures now raise immediately, and custom lockers must raise AlreadyLocked for contention to be retried.

    4.2.0release notes

  • The finalizer that released locks and closed filehandles when a wrapper was collected has been removed, restoring the 3.2.0 semantics.

    4.2.0release notes

  • Deleting a lock stored as a class attribute now releases the lock itself instead of calling release on its owner.

    4.2.0release notes

  • Fallback LK_* values now match the system constants, and are stored on the locker instance rather than added to the shared msvcrt module.

    4.2.0release notes

  • Release failures no longer mask the with-body exception; they are chained to it, and release errors follow raise_on_release_error.

    4.2.0release notes

  • Plain LockException failures from the sidecar are no longer normalized to AlreadyLocked; terminal backend failures propagate as themselves.

    4.2.0release notes

  • PID parsing now accepts only plain positive ASCII decimal values; other inputs are reported as unreadable.

    4.2.0release notes

  • Context entry now raises AlreadyLocked when another process holds the lock but its PID is missing, unreadable, or invalid, instead of returning None.

    4.2.0release notes

  • An existing destination now raises FileExistsError on entry instead of AssertionError.

    4.2.0release notes

  • Legacy universal-newline U mode strings have been removed from the Mode literal, narrowing the static typing contract without changing runtime behavior.

    4.2.0release notes

  • The subscription uses a dedicated connection that never retries or reconnects; holders on flaky networks lose their locks rather than silently retaining an invalid hold.

    4.2.0release notes

  • A clean with-block exit raises LockLostError after releasing if the lock was lost; release itself does not raise due to loss.

    4.2.0release notes

  • Acquiring an instance that already holds a lock raises portalocker.LockException instead of AssertionError.

    4.2.0release notes

  • Forked children release only local references to inherited held locks rather than unsubscribing and releasing the parent's lock; a child needing a lock must create its own instance.

    4.2.0release notes

  • Worker failures are scoped to the affected lock: waiter subscription failures retry within the timeout, while a held lock's worker death marks it lost.

    4.2.0release notes

  • Without the optional Redis dependency, RedisLock is now a stub class whose constructor raises ImportError with the dependency and install command; callers should catch ImportError rather than compare it with None.

    4.2.0release notes

  • An inconsistent held-count state with no filehandle now raises LockException instead of relying on an assert that python -O removes.

    4.2.0release notes

  • Reacquiring a valid held lock is an idempotent no-op; if its path was externally unlinked or replaced, acquisition raises LockException without closing the held handle.

    4.2.0release notes

  • A failing POSIX module-level unlock raises portalocker.LockException instead of raw OSError; the original error remains available through args[0] and __cause__.

    4.2.0release notes

  • On POSIX, publication now raises FileExistsError and preserves a destination created while the context was open.

    4.0.0release notes

  • Windows shared locks require this optional extra; otherwise an informative ImportError is raised.

    4.0.0release notes

  • Exceptions now populate .strerror and pass the message as a second positional argument, matching the Windows contract; their str() output changes to a 2-tuple repr.

    4.0.0release notes

  • Python 3.10 or later is required; Python 3.9 support has been dropped.

    4.0.0release notes

  • No longer installed by default on Windows; exclusive locks use the dependency-free msvcrt-based locker, while shared locks require portalocker[win32].

    4.0.0release notes

Security 2

  • Promotion confirmation and election changes prevent competing writers from becoming simultaneous exclusive holders; mixed-version protection is complete once all channel writers run 4.2 or later.

    4.2.0release notes

  • The unlock-then-unlink race is fixed: POSIX release unlinks before unlocking, and acquire re-verifies file identity after locking.

    4.0.0release notes

Deprecations 5

  • Passing a bool as check_interval is still honored but now warns; it raises TypeError in 5.0.

    4.4.0release notes

  • Passing a bool as timeout is still honored but now warns; it raises TypeError in 5.0.

    4.4.0release notes

  • The default-name DeprecationWarning now points to the constructing caller and deduplicates per call site.

    4.2.0release notes

  • Deprecated because the package has never raised this exception; instantiating it now emits DeprecationWarning.

    4.2.0release notes

  • Deprecated because its reap arm can kill live-but-slow holders; use the read-only probe() to inspect channel participants.

    4.2.0release notes

New APIs and options 20

  • Adds the BinaryMode alias, used to drive the filehandle typing overloads.

    4.3.0release notes

  • Adds the TextMode alias, used to drive the filehandle typing overloads.

    4.3.0release notes

  • RedisLock provides a check for verifying ownership during long critical sections.

    4.2.0release notes

  • Exposes the token for a fenced exclusive grant; it is None without a fenced grant and survives loss and release until the next acquire.

    4.2.0release notes

  • Opt-in fencing increments a never-expiring channel fence key after exclusive-grant confirmation and provides a token for downstream resources to reject stale writes.

    4.2.0release notes

  • Controls whether loss interrupts the main thread; it defaults to True in 4.2, warns when unset, and is scheduled to default to False in 5.0.

    4.2.0release notes

  • Lock exceptions preserve the file name as a string in fh_name; pickling and deep-copying drop the file handle while shallow copies share it.

    4.2.0release notes

  • RedisLock exposes whether its lock has been lost.

    4.2.0release notes

  • A callback runs exactly once per loss on the keep-alive thread; it may call release() on the lock.

    4.2.0release notes

  • A new exception reports RedisLock loss and carries channel, holder_id, and the causal exception as __cause__.

    4.2.0release notes

  • A read-only method reports who is on the channel without side effects.

    4.2.0release notes

  • The exception raised by a failed self-check becomes the cause of LockLostError.

    4.2.0release notes

  • Opt-in self-checks publish a liveness ping at each interval and require a response within the configured interval or unavailable_timeout, surfacing failures as lock loss.

    4.2.0release notes

  • RedisLock accepts a factory for deriving its dedicated subscription connection, supporting exotic setups such as Sentinel, cluster, and custom pools.

    4.2.0release notes

  • Exposes the competing PID when it is readable.

    4.0.0release notes

  • Cleanup failures remain suppressed by default, but callers can opt into reporting them; closing is always attempted and the file handle reference is cleared.

    4.0.0release notes

  • NamedBoundedSemaphore is now exported from the top-level portalocker namespace.

    4.0.0release notes

  • Adds ownership-only contexts; contention raises AlreadyLocked before entering the body.

    4.0.0release notes

  • Adds pidfile-based locking.

    4.0.0release notes

  • Adds shared readers; waiting writers gate new readers to prevent starvation, holder-specific heartbeats preserve stale-client cleanup, and legacy responses are treated as exclusive for mixed-version safety.

    4.0.0release notes

Performance 1

  • Probe reply draining collects in-flight and buffered replies in the same pass, sharply reducing probe duration and staleness windows.

    4.2.0release notes

Behavior and default changes 9

  • Lock is generic over its filehandle type. Literal text and binary modes infer IO[str] and IO[bytes]; a bare Lock defaults to Lock[IO[str]], matching the default mode.

    4.3.0release notes

  • RLock is generic over its filehandle type. Literal text and binary modes infer IO[str] and IO[bytes]; a bare RLock defaults to the text filehandle type.

    4.3.0release notes

  • A second acquire on an instance that already holds the lock is now an idempotent no-op that does not touch the sidecar lock or PID file.

    4.2.0release notes

  • Publication falls back to an existence check and rename on filesystems without hard-link support; the fallback cannot reliably refuse concurrent publishers.

    4.2.0release notes

  • With fail_when_locked, acquisition raises only after a conclusive probe; inconclusive probes retry within timeout, and timeout=0 preserves strict single-attempt behavior.

    4.2.0release notes

  • Verification retries now share one deadline and receive only the remaining timeout budget.

    4.2.0release notes

  • The --output-file option now opens lazily.

    4.0.0release notes

  • With fail_when_locked=True, acquisition fails fast instead of polling for the full timeout.

    4.0.0release notes

  • No longer keeps a strong atexit reference to itself, allowing unused instances to be garbage collected while interpreter-exit cleanup continues via a weak reference.

    4.0.0release notes

Tooling 1

  • The build backend requirement is now uv_build>=0.11,<1, allowing other build frontends and distribution packagers to build the sdist.

    4.4.2release notes

Fixes and other changes 46

  • Anchors a relative destination when the context is entered, so changing the working directory inside the body no longer causes FileNotFoundError or leaves the temporary file behind after a failing body. The yielded handle name and FileExistsError paths are now…

    4.4.1release notes

  • Cancellation during setup or between attempts releases resources, preserves the original exception, and permits reuse.

    4.3.1release notes

  • Polling retains a final read so buffered holder responses are processed before deciding that a holder is unavailable.

    4.3.1release notes

  • Retry sleeps are capped at the acquisition deadline, so a large check_interval no longer adds a full interval after timeout.

    4.3.1release notes

  • Lock now accepts subscription at runtime, allowing expressions such as Lock[typing.IO[bytes]] that raised TypeError in 4.2.0.

    4.3.0release notes

  • RLock.__init__ now initializes through Lock._init instead of Lock.__init__; monkeypatched constructors will notice.

    4.3.0release notes

  • RLock now accepts subscription at runtime.

    4.3.0release notes

  • Its filehandle type is pinned to IO[str].

    4.3.0release notes

  • Lock.acquire with fail_when_locked now propagates the locker's arguments so strerror is populated, while the original error remains in args[0] and __cause__.

    4.2.0release notes

  • Concurrent acquisition on one instance no longer leaks a slot: a losing thread returns its extra slot and receives LockException.

    4.2.0release notes

  • The blocking-mode timeout warning now fires at most once per lock instance and points to the caller, including through subclass constructors.

    4.2.0release notes

  • Concurrent acquire calls on one Lock instance are documented as unsupported; use one instance per thread because POSIX record locks are process-wide.

    4.2.0release notes

  • Failed acquisition paths, including interrupts, now unlock and close opened descriptors before returning or propagating; PidFileLock rolls back its sidecar too.

    4.2.0release notes

  • If file preparation fails after the lock is taken, the handle is now unlocked and closed before the original error escapes.

    4.2.0release notes

  • Concurrent or reentrant releases atomically claim lock state so only one caller tears the lock down.

    4.2.0release notes

  • Sleep intervals are capped by the remaining deadline, preventing acquisition from exceeding its timeout by up to a full check_interval.

    4.2.0release notes

  • Exceptions carrying open file handles can now cross multiprocessing boundaries without failing to pickle; detached handles whose name lookup fails no longer break exception construction.

    4.2.0release notes

  • Interpreter-exit cleanup now releases only locks constructed by the exiting process, avoiding removal of lock files inherited by a forked child.

    4.2.0release notes

  • PID publication now writes a neighboring temporary file and replaces the destination, so readers see either the old complete PID or the new complete PID.

    4.2.0release notes

  • Per-call timeout and check_interval arguments are now coalesced with instance attributes before constructing the sidecar Lock.

    4.2.0release notes

  • The sidecar reference is published only after successful acquisition; interrupted attempts roll back and release refuses to unlink files when the sidecar has no held handle.

    4.2.0release notes

  • PID files are read as bytes and validated as ASCII digits; undecodable content and digit runs longer than 4300 digits return None.

    4.2.0release notes

  • On Windows, the PID file is now unlinked before releasing the sidecar lock, preventing cleanup from deleting a successor's newly published PID.

    4.2.0release notes

  • The temporary file is created with mode 0o666 so the process umask determines destination permissions as with plain open.

    4.2.0release notes

  • Failed publication now keeps the temporary file and names its path in the exception; exceptions from the caller's body remove the temporary file, and closing the handle in the body no longer breaks publication.

    4.2.0release notes

  • The command now reads and assembles inputs before opening --output-file, preventing malformed input from truncating an existing output.

    4.2.0release notes

  • TemporaryFileLock and PidFileLock constructors now accept and forward this documented keyword; PidFileLock follows it when handling unlink errors.

    4.2.0release notes

  • Acquisition failures now clean up subscriptions and workers before propagating non-retryable errors, leaving the instance reusable.

    4.2.0release notes

  • RedisLock acquisition now waits for subscription confirmation, serializes promotions and ping answers, and checks subscriber counts again before pinging, closing races that could let two writers hold the lock.

    4.2.0release notes

  • Acquire counts and their transitions are protected by the instance state lock, preventing lost increments and handle closure while a hold remains outstanding.

    4.2.0release notes

  • A single module-level exit hook now releases held locks, replacing one never-unregistered callback per constructed instance.

    4.2.0release notes

  • Release errors now honor raise_on_release_error=False on teardown and are logged at warning level instead of disappearing.

    4.2.0release notes

  • TemporaryFileLock and PidFileLock now annotate filename as types.Filename, allowing pathlib.Path arguments to pass static type checking.

    4.2.0release notes

  • Each LockFileEx and UnlockFileEx call now receives a fresh OVERLAPPED structure instead of reusing a cached instance across calls and threads.

    4.2.0release notes

  • OSError from the Windows lock path is now wrapped in LockException, matching the unlock path.

    4.2.0release notes

  • No longer stays permanently Already locked after a non-contention error, such as a missing directory.

    4.0.0release notes

  • On POSIX, now uses its named syscall instead of silently using the global LOCKER.

    4.0.0release notes

  • The module-level POSIX lock() and unlock() now accept all documented LOCKER forms: tuple, instance, or class.

    4.0.0release notes

  • LockBase is now generic over the acquire return type; downstream Lock subclasses are unaffected.

    4.0.0release notes

  • Unexpected Win32 errors now raise LockException, matching the documented contract.

    4.0.0release notes

  • Windows locking now starts at byte 0 for raw file descriptors, preserving mutual exclusion on files larger than 64KiB; unexpected Win32 errors raise LockException.

    4.0.0release notes

  • The timeout is no longer ignored when fail_when_locked=False.

    4.0.0release notes

  • PID-publication failures now transactionally release the sidecar and preserve the publication error if cleanup also fails.

    4.0.0release notes

  • Vendored single-file output now correctly includes RedisLock instead of always producing None.

    4.0.0release notes

  • Fixes crashed-holder detection and cleanup: the liveness ping follows active subscription confirmation, pubsub connections do not leak on reap, internally created connections close on release, and failed acquisition rolls back for retry.

    4.0.0release notes

  • Release is a no-op when the object does not hold the lock, preventing a stale object from unlinking the current holder's lock file.

    4.0.0release notes

portalocker 31 changes

Breaking changes 1

  • Support for deprecated Python versions was dropped; only Python 3.9 and up are supported.

    3.0.0release notes