portalocker.portalocker module

Module portalocker.

This module provides cross-platform file locking functionality.

On POSIX systems locking is provided by fcntl.flock (or fcntl.lockf via LockfLocker), with no extra dependencies.

On Windows the default locker is MsvcrtLocker, which needs no extra dependencies for exclusive locks (it uses the built-in msvcrt module). Shared locks require the Win32 API (win32file.LockFileEx/UnlockFileEx) provided by the optional pywin32 package, installable through the win32 extra:

pip install "portalocker[win32]"

Without pywin32, acquiring a shared lock on Windows raises ImportError. Win32Locker can be used directly to lock through the Win32 API exclusively; it always requires pywin32.

This version uses classes to encapsulate locking logic, while maintaining the original external API, including the LOCKER constant for specific backwards compatibility (POSIX) and Windows behavior.

class portalocker.portalocker.BaseLocker[source]

Bases: object

Base class for locker implementations.

A locker is the thin layer between portalocker.lock and the platform’s locking system call. Each platform branch of this module defines its own subclasses - Win32Locker and MsvcrtLocker on Windows, PosixLocker and friends on POSIX - and LOCKER names the one the module-level lock / unlock dispatch to.

Subclass it to plug in a custom mechanism: implement both methods, then assign the class or an instance of it to LOCKER. Both forms are accepted (see _resolve_locker_pair); the class form is instantiated once, on first use, and cached.

lock(file_obj, flags)[source]

Lock file_obj according to flags.

Parameters:
Raises:

NotImplementedError – Always; subclasses must override this.

Return type:

None

unlock(file_obj)[source]

Release a lock previously taken by lock.

Parameters:

file_obj (IO[Any] | TextIOWrapper | int | HasFileno) – The same file object, fileno() provider or raw file descriptor that was passed to lock.

Raises:

NotImplementedError – Always; subclasses must override this.

Return type:

None

class portalocker.portalocker.FlockLocker[source]

Bases: PosixLocker

FlockLocker is a PosixLocker implementation using fcntl.flock.

class portalocker.portalocker.LockCallable(*args, **kwargs)[source]

Bases: Protocol

Call signature of the locking half of a LOCKER pair.

LOCKER may be set to a (lock, unlock) tuple of two plain callables instead of to a BaseLocker; this protocol describes the first element. It is a typing construct only: it types LockerType and the pair returned by _resolve_locker_pair, and nothing checks it at runtime.

The bound lock method of every locker in this module matches it, which is why (locker.lock, locker.unlock) is a valid LOCKER.

See also

UnlockCallable: the unlocking half of the same pair.

class portalocker.portalocker.LockfLocker[source]

Bases: PosixLocker

LockfLocker is a PosixLocker implementation using fcntl.lockf.

class portalocker.portalocker.PosixLocker[source]

Bases: BaseLocker

Locker implementation using the LOCKER constant.

Wraps a fcntl-style callable with the parts every POSIX lock needs: extracting the file descriptor, rejecting a non-blocking request that names no lock type, and translating OSError into AlreadyLocked / LockException.

Which callable it wraps depends on the class. FlockLocker and LockfLocker bind fcntl.flock and fcntl.lockf respectively, while a plain PosixLocker follows the module-level LOCKER - so LOCKER selects the primitive for the default dispatch, and the subclasses pin one regardless of it. Both primitives are exposed because a program usually has to match whatever the other processes sharing the file already use. The subclasses honouring their own callable is a 4.0.0 fix; before that they silently used the global LOCKER too.

Example

>>> import fcntl
>>> from portalocker.portalocker import (
...     FlockLocker,
...     LockfLocker,
...     PosixLocker,
... )
>>> PosixLocker().locker is fcntl.flock
True
>>> FlockLocker().locker is fcntl.flock
True
>>> LockfLocker().locker is fcntl.lockf
True
lock(file_obj, flags)[source]

Lock file_obj by calling locker with flags.

Parameters:
  • file_obj (IO[Any] | TextIOWrapper | int | HasFileno) – An open file object, an object exposing fileno(), or a raw file descriptor.

  • flags (LockFlags) – The LockFlags combination to apply. LockFlags.NON_BLOCKING only says how to wait, so it has to be combined with LockFlags.SHARED or LockFlags.EXCLUSIVE to say what to take.

Raises:
  • RuntimeErrorLockFlags.NON_BLOCKING was passed on its own, without LockFlags.SHARED or LockFlags.EXCLUSIVE.

  • AlreadyLockedfcntl reported EACCES or EAGAIN, i.e. someone else holds a conflicting lock.

  • LockException – Any other OSError, or the EOFError seen on some network filesystems.

Return type:

None

Example

>>> from portalocker import LockFlags
>>> from portalocker.portalocker import PosixLocker
>>> locker = PosixLocker()
>>> with open('example.txt', 'w') as fh:
...     locker.lock(
...         fh, LockFlags.EXCLUSIVE | LockFlags.NON_BLOCKING
...     )
...     locker.unlock(fh)
property locker: Callable[[int | HasFileno, int], Any]

The fcntl-style callable this locker locks with.

Subclasses set _locker at class level and always return that. An unbound PosixLocker returns the module-level LOCKER, read on every access, so reassigning LOCKER redirects existing instances too.

Returns:

A callable taking (fd, operation), normally fcntl.flock or fcntl.lockf.

Example

>>> import fcntl
>>> from portalocker.portalocker import LockfLocker
>>> LockfLocker().locker is fcntl.lockf
True
unlock(file_obj)[source]

Release a lock by calling locker with LockFlags.UNBLOCK.

Unlike lock, this does not translate errors: an OSError from fcntl propagates to the caller unchanged.

Parameters:

file_obj (IO[Any] | TextIOWrapper | int | HasFileno) – The same file object, fileno() provider or raw file descriptor that was passed to lock.

Return type:

None

class portalocker.portalocker.UnlockCallable(*args, **kwargs)[source]

Bases: Protocol

Call signature of the unlocking half of a LOCKER pair.

The counterpart of LockCallable: the second element of a (lock, unlock) tuple assigned to LOCKER. It takes no flags because releasing a lock needs no options - the locker already knows what it took.

See also

LockCallable: the locking half of the same pair.

portalocker.portalocker.lock(file, flags)[source]

Lock file with the locker named by the module-level LOCKER.

This is the POSIX implementation of portalocker.lock; the Windows branch of this module defines a separate one. Every LockerType form is accepted:

  • a bare fcntl-style callable, the default (fcntl.flock), which is routed through a shared PosixLocker so that it still gets descriptor extraction, flag validation and error translation;

  • a (lock, unlock) tuple, a BaseLocker instance, or a BaseLocker subclass, all resolved by _resolve_locker_pair.

Honouring all of those forms is a 4.0.0 fix; earlier versions only honoured the bare callable here.

Parameters:
  • file (IO[Any] | TextIOWrapper | int | HasFileno) – An open file object, an object exposing fileno(), or a raw file descriptor.

  • flags (LockFlags) – The LockFlags combination to apply. LockFlags.NON_BLOCKING must be combined with LockFlags.SHARED or LockFlags.EXCLUSIVE.

Raises:
  • AlreadyLocked – The lock is held elsewhere and LockFlags.NON_BLOCKING was set.

  • LockException – The locking call failed for another reason.

Return type:

None

Example

>>> import portalocker
>>> with open('example.txt', 'w') as fh:
...     portalocker.lock(fh, portalocker.LockFlags.EXCLUSIVE)
...     portalocker.unlock(fh)
portalocker.portalocker.unlock(file)[source]

Release a lock taken by the POSIX lock.

Resolves LOCKER the same way lock does, so a lock and its unlock always go to the same implementation as long as LOCKER is not reassigned in between.

Parameters:

file (IO[Any] | TextIOWrapper | int | HasFileno) – The same file object, fileno() provider or raw file descriptor that was passed to lock.

Return type:

None

Example

>>> import portalocker
>>> with open('example.txt', 'w') as fh:
...     portalocker.lock(fh, portalocker.LockFlags.EXCLUSIVE)
...     portalocker.unlock(fh)