_soft.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  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. flags = (
  15. os.O_WRONLY # open for writing only
  16. | os.O_CREAT
  17. | os.O_EXCL # together with above raise EEXIST if the file specified by filename exists
  18. | os.O_TRUNC # truncate the file to zero byte
  19. )
  20. o_nofollow = getattr(os, "O_NOFOLLOW", None)
  21. if o_nofollow is not None:
  22. flags |= o_nofollow
  23. try:
  24. file_handler = os.open(self.lock_file, flags, self._context.mode)
  25. except OSError as exception: # re-raise unless expected exception
  26. if not (
  27. exception.errno == EEXIST # lock already exist
  28. or (exception.errno == EACCES and sys.platform == "win32") # has no access to this lock
  29. ): # pragma: win32 no cover
  30. raise
  31. else:
  32. self._context.lock_file_fd = file_handler
  33. def _release(self) -> None:
  34. assert self._context.lock_file_fd is not None # noqa: S101
  35. os.close(self._context.lock_file_fd) # the lock file is definitely not None
  36. self._context.lock_file_fd = None
  37. with suppress(OSError): # the file is already deleted and that's what we want
  38. Path(self.lock_file).unlink()
  39. __all__ = [
  40. "SoftFileLock",
  41. ]