Skip to content

Commit b3ceac3

Browse files
committed
CRAI suggestions
1 parent 49618e5 commit b3ceac3

File tree

1 file changed

+28
-5
lines changed

1 file changed

+28
-5
lines changed

plugwise_usb/helpers/cache.py

Lines changed: 28 additions & 5 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+
"""Helper function to ensure persisted 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

@@ -98,15 +110,15 @@ async def write_cache(self, data: dict[str, str], rewrite: bool = False) -> None
98110
if not rewrite:
99111
current_data = await self.read_cache()
100112

101-
processed_keys: list[str] = []
113+
processed_keys: set[str] = set()
102114
data_to_write: list[str] = []
103115

104116
# Prepare data exactly as in original implementation
105117
for _cur_key, _cur_val in current_data.items():
106118
_write_val = _cur_val
107119
if _cur_key in data:
108120
_write_val = data[_cur_key]
109-
processed_keys.append(_cur_key)
121+
processed_keys.add(_cur_key)
110122
data_to_write.append(f"{_cur_key}{CACHE_KEY_SEPARATOR}{_write_val}\n")
111123

112124
# Write remaining new data
@@ -129,16 +141,27 @@ async def write_cache(self, data: dict[str, str], rewrite: bool = False) -> None
129141
file=str(temp_path),
130142
mode="w",
131143
encoding=UTF8,
144+
newline="\n",
132145
) as temp_file:
133146
await temp_file.writelines(data_to_write)
134147
await temp_file.flush()
135148
# Ensure data reaches disk before rename
136-
loop = get_running_loop()
137-
await loop.run_in_executor(None, os_fsync, temp_file.fileno())
149+
try:
150+
loop = get_running_loop()
151+
await loop.run_in_executor(None, os_fsync, temp_file.fileno())
152+
except (OSError, TypeError, AttributeError):
153+
# If fsync fails due to fileno() issues or other problems,
154+
# continue without it. flush() provides reasonable durability.
155+
pass
138156

139157
# Atomic rename (overwrites atomically on all platforms)
140158
temp_path.replace(cache_file_path)
141159
temp_path = None # Successfully renamed
160+
if os_name != "nt":
161+
# Ensure directory entry is persisted on POSIX
162+
await loop.run_in_executor(
163+
None, _fsync_parent_dir, cache_file_path.parent
164+
)
142165

143166
if not self._cache_file_exists:
144167
self._cache_file_exists = True
@@ -165,7 +188,7 @@ async def read_cache(self) -> dict[str, str]:
165188
"""Return current data from cache file."""
166189
if not self._initialized:
167190
raise CacheError(
168-
f"Unable to save cache. Initialize cache file '{self._file_name}' first."
191+
f"Unable to read cache. Initialize cache file '{self._file_name}' first."
169192
)
170193
current_data: dict[str, str] = {}
171194
if self._cache_file is None:

0 commit comments

Comments
 (0)