Skip to content

Commit 77779bb

Browse files
committed
CRAI suggestions
1 parent 49618e5 commit 77779bb

File tree

1 file changed

+31
-6
lines changed

1 file changed

+31
-6
lines changed

plugwise_usb/helpers/cache.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
from contextlib import suppress
77
import logging
88
from os import (
9+
O_RDONLY as os_O_RDONLY,
10+
close as os_close,
911
fsync as os_fsync,
1012
getenv as os_getenv,
1113
getpid as os_getpid,
1214
name as os_name,
15+
open as os_open,
1316
)
1417
from os.path import expanduser as os_path_expand_user, join as os_path_join
1518
from pathlib import Path
@@ -27,6 +30,15 @@
2730
_LOGGER = logging.getLogger(__name__)
2831

2932

33+
def _fsync_parent_dir(path: Path) -> None:
34+
"""Ensure persistence on POSIX."""
35+
fd = os_open(str(path), os_O_RDONLY)
36+
try:
37+
os_fsync(fd)
38+
finally:
39+
os_close(fd)
40+
41+
3042
class PlugwiseCache:
3143
"""Base class to cache plugwise information."""
3244

@@ -87,7 +99,9 @@ def _get_writable_os_dir(self) -> str:
8799
)
88100
return os_path_join(os_path_expand_user("~"), CACHE_DIR)
89101

90-
async def write_cache(self, data: dict[str, str], rewrite: bool = False) -> None:
102+
async def write_cache(
103+
self, data: dict[str, str], rewrite: bool = False
104+
) -> None: # noqa: PLR0912
91105
"""Save information to cache file atomically using aiofiles + temp file."""
92106
if not self._initialized:
93107
raise CacheError(
@@ -98,15 +112,15 @@ async def write_cache(self, data: dict[str, str], rewrite: bool = False) -> None
98112
if not rewrite:
99113
current_data = await self.read_cache()
100114

101-
processed_keys: list[str] = []
115+
processed_keys: set[str] = set()
102116
data_to_write: list[str] = []
103117

104118
# Prepare data exactly as in original implementation
105119
for _cur_key, _cur_val in current_data.items():
106120
_write_val = _cur_val
107121
if _cur_key in data:
108122
_write_val = data[_cur_key]
109-
processed_keys.append(_cur_key)
123+
processed_keys.add(_cur_key)
110124
data_to_write.append(f"{_cur_key}{CACHE_KEY_SEPARATOR}{_write_val}\n")
111125

112126
# Write remaining new data
@@ -129,16 +143,27 @@ async def write_cache(self, data: dict[str, str], rewrite: bool = False) -> None
129143
file=str(temp_path),
130144
mode="w",
131145
encoding=UTF8,
146+
newline="\n",
132147
) as temp_file:
133148
await temp_file.writelines(data_to_write)
134149
await temp_file.flush()
135150
# Ensure data reaches disk before rename
136-
loop = get_running_loop()
137-
await loop.run_in_executor(None, os_fsync, temp_file.fileno())
151+
try:
152+
loop = get_running_loop()
153+
await loop.run_in_executor(None, os_fsync, temp_file.fileno())
154+
except (OSError, TypeError, AttributeError):
155+
# If fsync fails due to fileno() issues or other problems,
156+
# continue without it. flush() provides reasonable durability.
157+
pass
138158

139159
# Atomic rename (overwrites atomically on all platforms)
140160
temp_path.replace(cache_file_path)
141161
temp_path = None # Successfully renamed
162+
if os_name != "nt":
163+
# Ensure directory entry is persisted on POSIX
164+
await loop.run_in_executor(
165+
None, _fsync_parent_dir, cache_file_path.parent
166+
)
142167

143168
if not self._cache_file_exists:
144169
self._cache_file_exists = True
@@ -165,7 +190,7 @@ async def read_cache(self) -> dict[str, str]:
165190
"""Return current data from cache file."""
166191
if not self._initialized:
167192
raise CacheError(
168-
f"Unable to save cache. Initialize cache file '{self._file_name}' first."
193+
f"Unable to read cache. Initialize cache file '{self._file_name}' first."
169194
)
170195
current_data: dict[str, str] = {}
171196
if self._cache_file is None:

0 commit comments

Comments
 (0)