{"id":995,"library":"locket","title":"Locket","description":"Locket is a Python library (version 1.0.0, last released April 2022) that provides file-based locks for inter-process communication on both Linux and Windows. It offers a simple API for creating non-reentrant locks that behave similarly to `threading.Lock` instances, uniquely identified by the file path being locked. The library ensures that only one process can acquire a lock at a time for a given path, preventing conflicts when multiple processes access shared resources.","status":"maintenance","version":"1.0.0","language":"python","source_language":"en","source_url":"http://github.com/mwilliamson/locket.py","tags":["lock","filelock","lockfile","process","concurrency","inter-process communication","linux","windows"],"install":[{"cmd":"pip install locket","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Required runtime environment.","package":"python","optional":false}],"imports":[{"note":"The primary interface is through the `locket` module directly, often using `locket.lock_file()`.","symbol":"locket","correct":"import locket"},{"note":"The specific exception raised by locket operations.","symbol":"LockError","correct":"from locket import LockError"}],"quickstart":{"code":"import locket\nimport os\nimport time\n\n# Define a lock file path, using an environment variable for flexibility\nlock_file_path = os.environ.get('LOCKET_EXAMPLE_PATH', './my_app.lock')\n\nprint(f\"Attempting to acquire lock on {lock_file_path}...\")\ntry:\n    # Acquire the lock using a context manager, with a 5-second timeout\n    # If another process holds the lock, this will block for up to 5 seconds.\n    # If the lock cannot be acquired, a LockError is raised.\n    with locket.lock_file(lock_file_path, timeout=5):\n        print(f\"Lock acquired on {lock_file_path}. Performing critical action...\")\n        # Simulate work within the critical section\n        time.sleep(2)\n        print(\"Critical action complete. Lock will be released automatically.\")\nexcept locket.LockError:\n    print(f\"Could not acquire lock on {lock_file_path} within the timeout. Another process might hold it.\")\nexcept Exception as e:\n    print(f\"An unexpected error occurred: {e}\")\n\nprint(\"\\nDemonstrating explicit acquire/release (less recommended)...\")\nlock = None\ntry:\n    # Acquire the lock explicitly\n    lock = locket.lock_file(lock_file_path, timeout=1)\n    lock.acquire()\n    print(f\"Lock acquired on {lock_file_path} (manual). Performing critical action...\")\n    time.sleep(1)\n    print(\"Critical action complete (manual).\")\nfinally:\n    # Always ensure the lock is released, even if errors occur\n    if lock:\n        try:\n            lock.release()\n            print(\"Lock released (manual).\")\n        except locket.LockError:\n            print(\"Warning: Attempted to release an already unlocked lock. This should not happen if `release()` is paired with `acquire()`.\")\n","lang":"python","description":"This quickstart demonstrates how to use `locket.lock_file()` with a context manager for safe and automatic lock acquisition and release. It also shows the explicit `acquire()` and `release()` pattern, which requires careful handling to prevent deadlocks or `LockError` if `release()` is called on an unlocked lock. The `timeout` parameter prevents indefinite blocking."},"warnings":[{"fix":"Avoid recursive lock acquisition, or use `threading.RLock` if reentrant locking is strictly required within a single process.","message":"Locket provides non-reentrant locks. This means a thread cannot acquire a lock it already holds without blocking or raising a `LockError` if a timeout is specified. If you need reentrant behavior, use `threading.RLock` or ensure your code structure avoids re-acquiring the same lock.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Avoid inheriting locks across `fork` calls. Acquire locks *after* forking in each child process if separate locking is needed, or use `multiprocessing.Lock` for IPC within the `multiprocessing` module.","message":"The behavior of Locket's file-based locks after a process `fork` is undefined. This means using `locket` directly with `multiprocessing` modules that rely on forking might lead to unpredictable results or deadlocks.","severity":"breaking","affected_versions":"All versions"},{"fix":"Always pair `acquire()` with `release()`, ideally using a `try...finally` block or, preferably, the `with` statement (context manager) provided by `locket.lock_file()` to ensure automatic and safe release.","message":"Calling `release()` on an already unlocked lock will raise a `locket.LockError`. This typically indicates a logic error where `release()` is called more times than `acquire()` or when a lock is not held by the current process/thread.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Evaluate for your specific use case. For critical applications requiring active maintenance or features, consider alternatives like `fasteners` or `oslo.concurrency` (though `oslo.concurrency` might be more heavyweight for simple needs).","message":"The last release of Locket (version 1.0.0) was in April 2022. While functional, the library has not received recent updates, which might imply a maintenance-only status. Users should be aware that it may not receive updates for newer Python versions or address new edge cases/bugs promptly.","severity":"deprecated","affected_versions":"Post 1.0.0 development (lack of new versions)"}],"env_vars":null,"last_verified":"2026-05-12T22:26:59.412Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"Ensure `acquire()` and `release()` calls are properly paired, ideally by using the `with` statement for automatic and safe lock management. Example: `with locket.lock_file('path/to/lock/file'): # critical section`","cause":"This error occurs when `release()` is called on a `locket` lock that is not currently held by the calling process/thread, or if `release()` is called more times than `acquire()`.","error":"locket.LockError: attempted to release an unlocked lock"},{"fix":"Handle the `locket.LockError` in a `try...except` block to manage scenarios where the lock cannot be obtained immediately or within the timeout. You might retry after a delay or log the contention. Example: `try: with locket.lock_file('path/to/lock/file', timeout=5): # critical section except locket.LockError: print('Failed to acquire lock.')`","cause":"This error is raised when `locket.lock_file()` is called with a `timeout` parameter (including `timeout=0` for non-blocking) and the lock cannot be acquired within the specified time because another process holds it.","error":"locket.LockError: could not acquire lock"},{"fix":"Install the `locket` library using pip. Command: `pip install locket`","cause":"This error means the `locket` library is not installed in the Python environment where the code is being executed.","error":"ModuleNotFoundError: No module named 'locket'"},{"fix":"Refactor the code to avoid recursive lock acquisition. If reentrant behavior is genuinely required within a single process/thread, consider using `threading.RLock` instead of `locket`'s file-based locks for that specific critical section.","cause":"The `locket` library implements non-reentrant locks, meaning the same thread cannot acquire the same lock more than once without explicitly releasing it first. Attempting to do so will lead to blocking or a `LockError` if a timeout is set.","error":"Locket provides non-reentrant locks. This means a thread cannot acquire a lock it already holds without blocking or raising a `LockError` if a timeout is specified."},{"fix":"Avoid inheriting `locket` locks across `fork` calls. Acquire locks *after* forking in each child process if separate locking is needed, or use `multiprocessing.Lock` for inter-process communication specifically designed for use with `multiprocessing`.","cause":"When a process using `locket`'s file-based locks forks, the inherited lock state in the child process is undefined. This can lead to deadlocks or unpredictable behavior when both parent and child processes try to interact with the same lock.","error":"The behavior of Locket's file-based locks after a process `fork` is undefined."}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"1.0.0","cli_name":"","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"17.8M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"17.8M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0,"mem_mb":0.3,"disk_size":"18M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.3,"disk_size":"19.6M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.3,"disk_size":"19.6M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0,"mem_mb":0.3,"disk_size":"20M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"11.5M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"11.5M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0,"mem_mb":0.3,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"11.2M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.6,"disk_size":"11.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0,"mem_mb":0.4,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.01,"mem_mb":0.4,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"17.3M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"17.3M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0,"mem_mb":0.3,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0,"mem_mb":0.3,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":null,"tag_description":null,"results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}