{"id":2851,"library":"zc-lockfile","title":"zc.lockfile","description":"The zc.lockfile package provides a basic, portable implementation of interprocess locks using file-locking primitives. It is not specifically for locking files themselves, but rather for providing general-purpose interprocess locks with a file-based mechanism. Currently at version 4.0, the library is actively maintained with updates primarily focused on Python version compatibility and bug fixes.","status":"active","version":"4.0","language":"en","source_language":"en","source_url":"https://github.com/zopefoundation/zc.lockfile","tags":["concurrency","locking","inter-process","file-lock","zope"],"install":[{"cmd":"pip install zc.lockfile","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"LockFile","correct":"from zc.lockfile import LockFile"},{"symbol":"LockError","correct":"from zc.lockfile import LockError"}],"quickstart":{"code":"import zc.lockfile\nimport os\nimport time\n\nlock_file_path = \"my_app.lock\"\nlock = None\n\ntry:\n    # Attempt to acquire the lock\n    lock = zc.lockfile.LockFile(lock_file_path)\n    print(f\"Process {os.getpid()}: Acquired lock on {lock_file_path}\")\n\n    # Simulate critical section work\n    print(f\"Process {os.getpid()}: Doing some critical work...\")\n    time.sleep(2) # Simulate work\n    print(f\"Process {os.getpid()}: Critical work complete.\")\n\nexcept zc.lockfile.LockError:\n    print(f\"Process {os.getpid()}: Could not acquire lock on {lock_file_path}. Another process holds it.\")\nexcept Exception as e:\n    print(f\"An unexpected error occurred: {e}\")\nfinally:\n    if lock:\n        lock.close()\n        print(f\"Process {os.getpid()}: Released lock on {lock_file_path}\")\n        # Optionally remove the lock file if it should not persist\n        # In a real application, consider if other processes might still need to check for its existence\n        try:\n            os.remove(lock_file_path)\n            print(f\"Process {os.getpid()}: Removed lock file {lock_file_path}\")\n        except OSError as e:\n            print(f\"Process {os.getpid()}: Error removing lock file {lock_file_path}: {e}\")","lang":"python","description":"This quickstart demonstrates how to acquire and release an inter-process lock using `zc.lockfile.LockFile`. It includes proper error handling for when a lock cannot be acquired and ensures the lock is released in a `finally` block to prevent deadlocks. It also shows how to optionally remove the lock file after use."},"warnings":[{"fix":"Update code to use new-style class patterns and explicitly handle lock file content if custom writing behavior was implicitly relied upon.","message":"In version 2.0, `zc.lockfile.LockFile` changed from an old-style to a new-style class. Additionally, `SimpleLockFile` was extracted, altering implicit behavior for writing to the lock file. Code relying on old-style class introspection or the previous implicit lock file writing mechanism will break.","severity":"breaking","affected_versions":"2.0+"},{"fix":"Ensure your packaging environment and tools are compatible with PEP 420 native namespaces. Direct `from zc.lockfile import LockFile` imports should generally be unaffected.","message":"Version 4.0 replaced the `pkg_resources` namespace with PEP 420 native namespace packaging. This change affects how the package is discovered and imported in certain environments, particularly complex Zope setups or systems with custom package loaders.","severity":"breaking","affected_versions":"4.0+"},{"fix":"Always ensure `lock.close()` is called, typically within a `try...finally` block, to guarantee the lock is released. `zc.lockfile.LockFile` does not implement the context manager protocol, so a `with` statement cannot be used directly.","message":"Failing to call `lock.close()` will leave the lock file on the filesystem. This prevents other processes from acquiring the lock indefinitely, even if the original holding process terminates or crashes, leading to resource leaks or deadlocks.","severity":"gotcha","affected_versions":"All"},{"fix":"If lock files should not persist, add an `os.remove(lock_file_path)` call after `lock.close()` (and potentially wrap it in a `try...except OSError` block for robustness).","message":"The `lock.close()` method releases the lock but *does not remove the lock file* from the filesystem. The file persists by design. If the lock file is no longer needed after the lock is released, it must be explicitly removed.","severity":"gotcha","affected_versions":"All"},{"fix":"Leverage the `zc.lockfile` feature to include hostname (which often corresponds to container ID) in the lock file to aid in identifying the lock's origin in distributed or containerized setups.","message":"In containerized environments (e.g., Docker), process IDs (PIDs) can be misleading or identical across different containers on the same host. Relying solely on PIDs within lock files for debugging or identification can be problematic.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-10T00:00:00.000Z","next_check":"2026-07-09T00:00:00.000Z"}