{"id":861,"library":"fasteners","title":"Fasteners","description":"Fasteners is a Python package that provides useful cross-platform synchronization primitives. It extends Python's standard library by offering inter-process exclusive locks, inter-process reader-writer locks, and thread-based reader-writer locks. The library aims to simplify concurrent programming across processes and threads. The current version is 0.20, with releases occurring periodically, often tied to Python version support updates.","status":"active","version":"0.20","language":"python","source_language":"en","source_url":"https://github.com/harlowja/fasteners","tags":["concurrency","locking","threading","multiprocessing","inter-process"],"install":[{"cmd":"pip install fasteners","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"symbol":"InterProcessLock","correct":"from fasteners import InterProcessLock"},{"symbol":"InterProcessReaderWriterLock","correct":"from fasteners import InterProcessReaderWriterLock"},{"symbol":"ReaderWriterLock","correct":"from fasteners import ReaderWriterLock"},{"note":"While functional, importing the decorator directly is more explicit for linting and clarity.","wrong":"@fasteners.interprocess_locked","symbol":"interprocess_locked","correct":"from fasteners import interprocess_locked"},{"note":"While functional, importing the decorator directly is more explicit for linting and clarity.","wrong":"@fasteners.locked","symbol":"locked","correct":"from fasteners import locked"}],"quickstart":{"code":"import time\nimport fasteners\nimport os\n\n# For inter-process locks, a file path is required.\n# Use a temporary file path for demonstration.\nlock_file_path = os.path.join(os.getcwd(), 'my_app.lock')\n\n@fasteners.interprocess_locked(lock_file_path)\ndef protected_function(worker_id):\n    print(f\"Worker {worker_id}: Acquired lock. Performing exclusive task...\")\n    time.sleep(2)  # Simulate work\n    print(f\"Worker {worker_id}: Released lock.\")\n\nif __name__ == \"__main__\":\n    print(f\"Attempting to run protected_function for worker 1...\")\n    protected_function(1)\n    print(f\"Attempting to run protected_function for worker 2...\")\n    protected_function(2)\n\n    # Example with context manager for more control\n    print(\"\\n--- Using context manager ---\")\n    my_lock = fasteners.InterProcessLock(lock_file_path + '.ctx')\n    with my_lock:\n        print(\"Main process: Acquired lock via context manager.\")\n        time.sleep(1)\n    print(\"Main process: Released lock via context manager.\")\n    \n    # Clean up lock files (optional, as fasteners typically handles this on exit)\n    if os.path.exists(lock_file_path):\n        os.remove(lock_file_path)\n    if os.path.exists(lock_file_path + '.ctx'):\n        os.remove(lock_file_path + '.ctx')","lang":"python","description":"This quickstart demonstrates using `fasteners.interprocess_locked` as a decorator and `fasteners.InterProcessLock` as a context manager to ensure exclusive execution across processes using a file-based lock. If you run multiple instances of this script simultaneously, only one will execute the protected section at a time."},"warnings":[{"fix":"Ensure your project uses a Python version compatible with your installed `fasteners` version. Refer to the official documentation or release notes for precise compatibility matrix.","message":"Python version support is periodically dropped. Version 0.20 removed support for Python 3.8, 3.9, and PyPy 3.9. Previous versions (0.19, 0.18) also dropped support for older Python releases.","severity":"breaking","affected_versions":"0.18, 0.19, 0.20"},{"fix":"Avoid recursive acquisition of `InterProcessLock`. Design your code so that a process either acquires the lock once or uses alternative reentrant locking mechanisms if recursion is necessary.","message":"`InterProcessLock` instances are *not reentrant*. Attempting to acquire a lock already held by the same process can lead to deadlocks or crashes upon release.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure distinct acquisition patterns. If you need to upgrade a read lock to a write lock (or downgrade), you must explicitly release the first lock before attempting to acquire the second.","message":"`InterProcessReaderWriterLock` instances are *not upgradable*. You cannot acquire a read lock while holding a write lock, or vice versa, without risking deadlocks or crashes.","severity":"gotcha","affected_versions":"All versions"},{"fix":"When using inter-process locks, ensure that any code within the locked section that involves multiple threads in the *same process* is protected by standard Python `threading` locks (e.g., `threading.Lock`) to prevent race conditions.","message":"`InterProcessLock` and `InterProcessReaderWriterLock` provide guarantees *only between processes*, not between threads within a single process. They are not inherently thread-safe for intra-process concurrency.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always use an absolute and consistent file path for your inter-process lock files across all participating processes. Consider using `os.path.join` with a well-known directory or a configuration variable to ensure consistency.","message":"When using `InterProcessLock` or `InterProcessReaderWriterLock`, the `path` argument to the constructor is critical. Different processes must use the exact same string path to refer to the same underlying lock. Mismatched paths will result in independent locks.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T20:30:41.277Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"Install the package using pip: `pip install fasteners`","cause":"The 'fasteners' package is not installed in the Python environment being used.","error":"ModuleNotFoundError: No module named 'fasteners'"},{"fix":"Instantiate the lock class by adding parentheses: `lock = fasteners.InterProcessLock('path/to/lock.file')` instead of `lock = fasteners.InterProcessLock`","cause":"This error occurs when trying to call the `acquire` method on the `InterProcessLock` or `InterProcessReaderWriterLock` class itself, instead of an instantiated object of that class.","error":"AttributeError: 'builtin_function_or_method' object has no attribute 'acquire'"},{"fix":"Design code to avoid recursive acquisition of `InterProcessLock`. If reentrancy is required, consider using Python's standard library `threading.RLock` for thread-level reentrant locks, or refactor the process-level logic.","cause":"The `fasteners.InterProcessLock` is not reentrant, meaning a process cannot acquire a lock it already holds. Attempting to do so will result in a deadlock or crash.","error":"fasteners InterProcessLock reentrant deadlock"},{"fix":"Explicitly release the first lock (e.g., read lock) before attempting to acquire the second lock (e.g., write lock). Ensure distinct acquisition patterns to prevent concurrent upgrades/downgrades.","cause":"The `fasteners.InterProcessReaderWriterLock` does not support upgrading a read lock to a write lock (or downgrading a write lock to a read lock) while holding the initial lock. This can lead to deadlocks or crashes.","error":"fasteners InterProcessReaderWriterLock upgrade deadlock"},{"fix":"Always check the boolean return value of `acquire(timeout=...)` to determine if the lock was successfully obtained, and handle the case where it returns `False`. Example: `if lock.acquire(timeout=10): ... else: handle_timeout()`","cause":"The `acquire()` method of `InterProcessLock` or `InterProcessReaderWriterLock` returns `False` if the lock cannot be acquired within the specified timeout, rather than raising an exception, which can lead to unexpected behavior if not handled.","error":"fasteners.InterProcessLock acquire timeout"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.20","cli_name":"","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","installed_version":"0.20","pypi_latest":"0.20","is_stale":false,"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.03,"mem_mb":2,"disk_size":"17.9M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":2,"disk_size":"17.9M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.5,"import_time_s":0.02,"mem_mb":2,"disk_size":"18M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.02,"mem_mb":2,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.06,"mem_mb":2.2,"disk_size":"19.8M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":2.2,"disk_size":"19.8M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.5,"import_time_s":0.06,"mem_mb":2.2,"disk_size":"20M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2.2,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.05,"mem_mb":2,"disk_size":"11.7M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":2,"disk_size":"11.7M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.4,"import_time_s":0.05,"mem_mb":2,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":2,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.05,"mem_mb":2,"disk_size":"11.4M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":2,"disk_size":"11.3M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.4,"import_time_s":0.04,"mem_mb":1.8,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.8,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.03,"mem_mb":1.9,"disk_size":"17.4M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.9,"disk_size":"17.4M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.8,"import_time_s":0.03,"mem_mb":1.9,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"fasteners","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.9,"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}]}}