lloom-client 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
lloom/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """lloom client package."""
2
+
3
+ __version__ = "0.1.0"
lloom/_fs.py ADDED
@@ -0,0 +1,52 @@
1
+ """Shared crash-safe filesystem helpers (client)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import uuid
7
+ from pathlib import Path
8
+
9
+
10
+ def fsync_dir(path: Path | str) -> None:
11
+ """fsync a directory so a just-created/renamed entry survives a host
12
+ crash (fsyncing file contents alone does not persist the name)."""
13
+ fd = os.open(Path(path), os.O_RDONLY)
14
+ try:
15
+ os.fsync(fd)
16
+ except OSError:
17
+ pass # some filesystems refuse directory fsync; best effort
18
+ finally:
19
+ os.close(fd)
20
+
21
+
22
+ def atomic_write_text(path: Path | str, text: str, mode: int = 0o600) -> None:
23
+ """Crash-safe text write: unique temp file in the same folder,
24
+ flush+fsync, then atomic ``os.replace`` (same filesystem) so readers
25
+ never see a partial file under the final name, and an fsync of the
26
+ parent directory so the new name itself survives a host crash. The
27
+ unique temp name keeps concurrent writers to the same target from
28
+ clobbering each other's temp files; the temp is removed if any step
29
+ fails — a failed write leaves no ``.tmp`` leftovers and the previous
30
+ content (if any) untouched.
31
+ """
32
+ path = Path(path)
33
+ path.parent.mkdir(parents=True, exist_ok=True)
34
+ tmp = path.with_name(f".{path.name}.{os.getpid()}.{uuid.uuid4().hex}.tmp")
35
+ try:
36
+ # newline="": no translation — "\n" stays "\n" (and "\r" untouched)
37
+ # on every platform, preserving byte-exact mail file contents
38
+ fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, mode)
39
+ # respect a restrictive umask only for widening: never more permissive
40
+ os.fchmod(fd, mode)
41
+ with os.fdopen(fd, "w", encoding="utf-8", newline="") as fh:
42
+ fh.write(text)
43
+ fh.flush()
44
+ os.fsync(fh.fileno())
45
+ os.replace(tmp, path)
46
+ fsync_dir(path.parent)
47
+ except BaseException:
48
+ try:
49
+ os.unlink(tmp)
50
+ except OSError:
51
+ pass
52
+ raise