Source code for inet_nm.filelock
"""
This module provides a simple implementation of a file-based locking mechanism.
The main class `FileLock` uses OS-level file system operations for locking
and unlocking.
This kind of lock can be used to prevent the simultaneous execution of a piece
of code by different processes.
"""
import os
import time
[docs]
class FileLockTimeout(Exception):
"""
Exception raised when a file lock operation fails.
Attributes:
message -- explanation of the error
"""
def __init__(self, message="Timeout occurred."):
"""Initialize the exception."""
self.message = message
super().__init__(self.message)
[docs]
class FileLock:
"""
Provides a context manager-based file lock mechanism.
Attributes:
file_name: The name of the file to be used as the lock.
timeout (int): The maximum time to wait for the lock to be released.
"""
def __init__(self, file_name: str, timeout: int = 10) -> None:
"""
Construct a new FileLock object.
Args:
file_name: The name of the file to be used as the lock.
timeout: The maximum time to wait for the lock to be released.
"""
self.file_name = file_name
self.timeout = timeout
self.fd = None
self._lock_held = False
[docs]
def acquire(self, timeout: int = None, poll_interval: float = 0.05) -> None:
"""
Acquire the file lock.
If the lock is currently in use, wait until it is released,
or until the specified timeout has passed.
Args:
timeout: The maximum time to wait for the lock to be released.
Default is None, which means use self.timeout.
poll_interval: Time interval to check the lock file's existence.
Raises:
FileLockTimeout: If the timeout has passed and the lock
has not been released.
"""
timeout = timeout or self.timeout
start_time = time.time()
while True:
try:
os.umask(0)
self.fd = os.open(
self.file_name, flags=os.O_CREAT | os.O_EXCL | os.O_RDWR, mode=0o777
)
self._lock_held = True
break
except FileExistsError:
if timeout is None:
time.sleep(poll_interval)
elif time.time() - start_time >= timeout:
msg = f"Timeout trying to lock {self.file_name}"
raise FileLockTimeout(msg)
else:
time.sleep(poll_interval)
[docs]
def release(self, force: bool = False) -> None:
"""
Release the file lock.
Args:
force: If True, force release the lock even if the lock is
held by others.
"""
if self._lock_held:
os.close(self.fd)
os.unlink(self.file_name)
elif force:
try:
os.unlink(self.file_name)
except OSError:
pass
self._lock_held = False
@property
def is_locked(self) -> bool:
"""
Check if the file lock is locked.
Returns:
bool: True if the lock file exists, False otherwise.
"""
return os.path.exists(self.file_name)
def __enter__(self) -> "FileLock":
"""Acquire the lock when entering the context."""
self.acquire()
return self
def __exit__(self, type, value, traceback) -> None:
"""Release the lock when exiting the context."""
self.release()