_soft.py 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. from __future__ import annotations
  2. import os
  3. import sys
  4. from contextlib import suppress
  5. from errno import EACCES, EEXIST
  6. from pathlib import Path
  7. from ._api import BaseFileLock
  8. from ._util import ensure_directory_exists, raise_on_not_writable_file
  9. class SoftFileLock(BaseFileLock):
  10. """Simply watches the existence of the lock file."""
  11. def _acquire(self) -> None:
  12. raise_on_not_writable_file(self.lock_file)
  13. ensure_directory_exists(self.lock_file)
  14. # first check for exists and read-only mode as the open will mask this case as EEXIST
  15. flags = (
  16. os.O_WRONLY # open for writing only
  17. | os.O_CREAT
  18. | os.O_EXCL # together with above raise EEXIST if the file specified by filename exists
  19. | os.O_TRUNC # truncate the file to zero byte
  20. )
  21. try:
  22. file_handler = os.open(self.lock_file, flags, self._context.mode)
  23. except OSError as exception: # re-raise unless expected exception
  24. if not (
  25. exception.errno == EEXIST # lock already exist
  26. or (exception.errno == EACCES and sys.platform == "win32") # has no access to this lock
  27. ): # pragma: win32 no cover
  28. raise
  29. else:
  30. self._context.lock_file_fd = file_handler
  31. def _release(self) -> None:
  32. assert self._context.lock_file_fd is not None # noqa: S101
  33. os.close(self._context.lock_file_fd) # the lock file is definitely not None
  34. self._context.lock_file_fd = None
  35. with suppress(OSError): # the file is already deleted and that's what we want
  36. Path(self.lock_file).unlink()
  37. __all__ = [
  38. "SoftFileLock",
  39. ]