mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-11 13:27:41 +01:00
Six new modules, all composed or re-exported so no caller changes:
_shutdown.py (384) -> _shutdown_sick_state.py SickDayStateMixin
_wake_alarm.py WakeAlarmMixin
_phone_verification.py (380)-> _adb_transport.py AdbTransportMixin
_http_workout_fetch.py HttpWorkoutFetchMixin
_status_data.py (370) -> _status_types.py the 7 dataclasses
_status_projection.py shutdown projection
+ format_summary_line
Moving a name means moving where it is *read*, so 30-odd mock patch targets
move with it. Most importantly conftest.py's autouse _block_real_network
fixture: ruff correctly dropped the now-unused `socket` import from
_phone_verification, which silently removed the guard's target and would have
let subnet probes reach the real network. It now blocks socket in both modules
that actually own the probes, and both targets are asserted to exist.
976 tests pass at 100% branch coverage; pylint 8.70 -> 8.71; `screen_lock
--status` renders the real week unchanged. File-length gate: 41 -> 35.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EveB813BQ8abAP68VSqZ5Y
120 lines
4.0 KiB
Python
120 lines
4.0 KiB
Python
"""Sick-day shutdown state: persistence and next-day restoration.
|
|
|
|
Split out of :mod:`screen_locker._shutdown` to keep every file under the
|
|
250-line cap. Composed back into ``ShutdownMixin`` there, so callers see no
|
|
change.
|
|
|
|
Tracks the shutdown hours that were in force before a sick day moved them
|
|
earlier, so the following day can put them back.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
import json
|
|
import logging
|
|
|
|
from screen_locker._constants import SICK_DAY_STATE_FILE
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SickDayStateMixin:
|
|
"""Persists and restores the pre-sick-day shutdown configuration."""
|
|
|
|
def _sick_mode_used_today(self) -> bool:
|
|
"""Check if sick mode was already used today."""
|
|
if not SICK_DAY_STATE_FILE.exists():
|
|
return False
|
|
|
|
try:
|
|
with SICK_DAY_STATE_FILE.open() as f:
|
|
state = json.load(f)
|
|
today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d")
|
|
return state.get("date") == today
|
|
except (OSError, json.JSONDecodeError) as exc:
|
|
_logger.warning(
|
|
"Could not read sick-day state from %s: %s — treating sick mode "
|
|
"as UNUSED today, which may allow a second sick day",
|
|
SICK_DAY_STATE_FILE,
|
|
exc,
|
|
)
|
|
return False
|
|
|
|
def _save_sick_day_state(
|
|
self,
|
|
date: str,
|
|
orig_mon_wed: int,
|
|
orig_thu_sun: int,
|
|
) -> bool:
|
|
"""Save sick day state with original config values.
|
|
|
|
Returns True if saved successfully, False otherwise.
|
|
"""
|
|
state = {
|
|
"date": date,
|
|
"original_mon_wed_hour": orig_mon_wed,
|
|
"original_thu_sun_hour": orig_thu_sun,
|
|
}
|
|
try:
|
|
with SICK_DAY_STATE_FILE.open("w") as f:
|
|
json.dump(state, f, indent=2)
|
|
except OSError as e:
|
|
_logger.warning("Failed to save sick day state: %s", e)
|
|
return False
|
|
|
|
_logger.info("Saved sick day state for %s", date)
|
|
return True
|
|
|
|
def _load_sick_day_state(self) -> tuple[str, int, int] | None:
|
|
"""Load sick day state file.
|
|
|
|
Returns (date, orig_mon_wed_hour, orig_thu_sun_hour) or None.
|
|
"""
|
|
with SICK_DAY_STATE_FILE.open() as f:
|
|
state = json.load(f)
|
|
date = state.get("date")
|
|
orig_mw = state.get("original_mon_wed_hour")
|
|
orig_ts = state.get("original_thu_sun_hour")
|
|
if date is None or orig_mw is None or orig_ts is None:
|
|
return None
|
|
return (str(date), int(orig_mw), int(orig_ts))
|
|
|
|
def _write_restored_config(
|
|
self,
|
|
orig_mw: int,
|
|
orig_ts: int,
|
|
state_date: str,
|
|
) -> None:
|
|
"""Write restored config values and clean up state file."""
|
|
config_values = self._read_shutdown_config()
|
|
if config_values:
|
|
_, _, morning_end = config_values
|
|
_logger.info(
|
|
"Restoring original shutdown config from %s",
|
|
state_date,
|
|
)
|
|
self._write_shutdown_config(
|
|
orig_mw,
|
|
orig_ts,
|
|
morning_end,
|
|
restore=True,
|
|
)
|
|
SICK_DAY_STATE_FILE.unlink()
|
|
_logger.info("Removed stale sick day state from %s", state_date)
|
|
|
|
def _restore_original_config_if_needed(self) -> None:
|
|
"""Restore original config if sick day state is from a previous day."""
|
|
if not SICK_DAY_STATE_FILE.exists():
|
|
return
|
|
try:
|
|
loaded = self._load_sick_day_state()
|
|
if loaded is None:
|
|
return
|
|
state_date, orig_mw, orig_ts = loaded
|
|
today = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d")
|
|
if state_date != today:
|
|
self._write_restored_config(orig_mw, orig_ts, state_date)
|
|
except (OSError, json.JSONDecodeError) as e:
|
|
_logger.warning("Error checking sick day state: %s", e)
|