From 9135c6a18cefe76234fc583cbcc6fef00f89aaa5 Mon Sep 17 00:00:00 2001 From: "Ian C." <108159253+ic-dev21@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:28:55 -0500 Subject: [PATCH 1/2] Hilo_state corruption logic Add a recreation in case of corruption. --- pyhilo/const.py | 2 +- pyhilo/util/state.py | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/pyhilo/const.py b/pyhilo/const.py index f1a7870..3ab1571 100755 --- a/pyhilo/const.py +++ b/pyhilo/const.py @@ -1,7 +1,7 @@ import logging import platform -import uuid from typing import Final +import uuid import aiohttp diff --git a/pyhilo/util/state.py b/pyhilo/util/state.py index 11d8e3c..5b3789a 100644 --- a/pyhilo/util/state.py +++ b/pyhilo/util/state.py @@ -128,11 +128,37 @@ async def get_state(state_yaml: str) -> StateDict: state_yaml ): # noqa: PTH113 - isfile is fine and simpler in this case. return _get_defaults(StateDict) # type: ignore - async with aiofiles.open(state_yaml, mode="r") as yaml_file: - LOG.debug("Loading state from yaml") - content = await yaml_file.read() - state_yaml_payload: StateDict = yaml.safe_load(content) - return state_yaml_payload + + try: + async with aiofiles.open(state_yaml, mode="r") as yaml_file: + LOG.debug("Loading state from yaml") + content = await yaml_file.read() + state_yaml_payload: StateDict = yaml.safe_load(content) + + # Handle corrupted/empty YAML files + if state_yaml_payload is None: + LOG.warning( + "State file %s is corrupted or empty, reinitializing with defaults", + state_yaml, + ) + defaults = _get_defaults(StateDict) # type: ignore + async with aiofiles.open(state_yaml, mode="w") as yaml_file_write: + content = yaml.dump(defaults) + await yaml_file_write.write(content) + return defaults + + return state_yaml_payload + except yaml.YAMLError as e: + LOG.error( + "Failed to parse state file %s: %s. Reinitializing with defaults.", + state_yaml, + e, + ) + defaults = _get_defaults(StateDict) # type: ignore + async with aiofiles.open(state_yaml, mode="w") as yaml_file_write: + content = yaml.dump(defaults) + await yaml_file_write.write(content) + return defaults async def set_state( From 786626620dcd843deaef89e63f64ea3cace275ef Mon Sep 17 00:00:00 2001 From: "Ian C." <108159253+ic-dev21@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:51:11 -0500 Subject: [PATCH 2/2] Mypy linting Removed a few type: ignore and properly typed the rest. --- pyhilo/util/state.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyhilo/util/state.py b/pyhilo/util/state.py index bb2a9fb..1df2c2e 100644 --- a/pyhilo/util/state.py +++ b/pyhilo/util/state.py @@ -77,7 +77,7 @@ class StateDict(TypedDict, total=False): T = TypeVar("T", bound="StateDict") -def _get_defaults(cls: type[T]) -> dict[str, Any]: +def _get_defaults(cls: type[T]) -> T: """Generate a default dict based on typed dict This function recursively creates a nested dictionary structure that mirrors @@ -127,13 +127,13 @@ async def get_state(state_yaml: str) -> StateDict: if not isfile( state_yaml ): # noqa: PTH113 - isfile is fine and simpler in this case. - return _get_defaults(StateDict) # type: ignore + return _get_defaults(StateDict) try: async with aiofiles.open(state_yaml, mode="r") as yaml_file: LOG.debug("Loading state from yaml") content = await yaml_file.read() - state_yaml_payload: StateDict = yaml.safe_load(content) + state_yaml_payload: StateDict | None = yaml.safe_load(content) # Handle corrupted/empty YAML files if state_yaml_payload is None: @@ -141,7 +141,7 @@ async def get_state(state_yaml: str) -> StateDict: "State file %s is corrupted or empty, reinitializing with defaults", state_yaml, ) - defaults = _get_defaults(StateDict) # type: ignore + defaults = _get_defaults(StateDict) async with aiofiles.open(state_yaml, mode="w") as yaml_file_write: content = yaml.dump(defaults) await yaml_file_write.write(content) @@ -154,7 +154,7 @@ async def get_state(state_yaml: str) -> StateDict: state_yaml, e, ) - defaults = _get_defaults(StateDict) # type: ignore + defaults = _get_defaults(StateDict) async with aiofiles.open(state_yaml, mode="w") as yaml_file_write: content = yaml.dump(defaults) await yaml_file_write.write(content)