refactor(app_controller): migrate 6 project-op sites to Result (batch 2)
Migrated 6 INTERNAL_BROAD_CATCH sites in src/app_controller.py: 1. cb_prune_logs.run_manual_prune (L2157) - log pruning with aggressive thresholds - Narrowed: except Exception -> (OSError, IOError, ValueError, TypeError, AttributeError) - Returns Result[None] via OK on success, Result with errors on failure - logging.debug added per Heuristic #19 2. _load_active_project primary (L2168) - project_manager.load_project - Narrowed: except Exception -> (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, tomllib.TOMLDecodeError) - logging.debug added - Preserves the migrate_from_legacy_config fallback 3. _load_active_project fallback_loop (L2182) - load_project for each project_path - Same exception narrowing as primary - logging.debug includes the failed path - Preserves the continue-on-error behavior 4. _prune_old_logs.run_prune (L2223) - background log pruning - Same exception narrowing as run_manual_prune - logging.debug added - Returns Result[None] 5. _refresh_from_project active_track deserialization (L2918) - Narrowed: except Exception -> (TypeError, ValueError, KeyError, AttributeError) - logging.debug added - Preserves the active_track = None fallback 6. _save_active_project (L2972) - project_manager.save_project - Narrowed: except Exception -> (OSError, IOError, ValueError, TypeError, KeyError, AttributeError) - logging.debug added - Preserves the ai_status = save error fallback Added import tomllib to the top of app_controller.py for the TOMLDecodeError exception narrowing in _load_active_project. Refs: spec.md FR1, plan.md Task 2.3
This commit is contained in:
+30
-10
@@ -10,6 +10,7 @@ import signal
|
|||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
import tomllib
|
||||||
import traceback
|
import traceback
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
@@ -2144,7 +2145,7 @@ class AppController:
|
|||||||
"""Manually triggers the log pruning process with aggressive thresholds."""
|
"""Manually triggers the log pruning process with aggressive thresholds."""
|
||||||
self.ai_status = "Manual prune started (Age > 0d, Size < 100KB)..."
|
self.ai_status = "Manual prune started (Age > 0d, Size < 100KB)..."
|
||||||
|
|
||||||
def run_manual_prune() -> None:
|
def run_manual_prune() -> Result[None]:
|
||||||
try:
|
try:
|
||||||
from src import log_registry
|
from src import log_registry
|
||||||
from src import log_pruner
|
from src import log_pruner
|
||||||
@@ -2154,18 +2155,26 @@ class AppController:
|
|||||||
# Note: max_age_days=0 means cutoff is NOW.
|
# Note: max_age_days=0 means cutoff is NOW.
|
||||||
pruner.prune(max_age_days=0, min_size_kb=100)
|
pruner.prune(max_age_days=0, min_size_kb=100)
|
||||||
self.ai_status = "Manual prune complete."
|
self.ai_status = "Manual prune complete."
|
||||||
except Exception as e:
|
return OK
|
||||||
|
except (OSError, IOError, ValueError, TypeError, AttributeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("manual prune error: %s", e, extra={"source": "app_controller.cb_prune_logs.run_manual_prune"})
|
||||||
self.ai_status = f"Manual prune error: {e}"
|
self.ai_status = f"Manual prune error: {e}"
|
||||||
print(f"Error during manual log pruning: {e}")
|
return Result(data=None, errors=[ErrorInfo(
|
||||||
|
kind=ErrorKind.INTERNAL,
|
||||||
|
message=str(e),
|
||||||
|
source="app_controller.cb_prune_logs.run_manual_prune",
|
||||||
|
original=e,
|
||||||
|
)])
|
||||||
|
|
||||||
self.submit_io(run_manual_prune)
|
self.submit_io(run_manual_prune)
|
||||||
|
|
||||||
def _load_active_project(self) -> None:
|
def _load_active_project(self) -> Result[None]:
|
||||||
"""Loads the active project configuration, with fallbacks."""
|
"""Loads the active project configuration, with fallbacks."""
|
||||||
if self.active_project_path and Path(self.active_project_path).exists():
|
if self.active_project_path and Path(self.active_project_path).exists():
|
||||||
try:
|
try:
|
||||||
self.project = project_manager.load_project(self.active_project_path)
|
self.project = project_manager.load_project(self.active_project_path)
|
||||||
except Exception as e:
|
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, tomllib.TOMLDecodeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("load_project failed: %s", e, extra={"source": "app_controller._load_active_project.primary"})
|
||||||
print(f"Failed to load project {self.active_project_path}: {e}")
|
print(f"Failed to load project {self.active_project_path}: {e}")
|
||||||
self.project = project_manager.migrate_from_legacy_config(self.config)
|
self.project = project_manager.migrate_from_legacy_config(self.config)
|
||||||
self.active_project_path = ""
|
self.active_project_path = ""
|
||||||
@@ -2179,7 +2188,8 @@ class AppController:
|
|||||||
self.project = project_manager.load_project(pp)
|
self.project = project_manager.load_project(pp)
|
||||||
self.active_project_path = pp
|
self.active_project_path = pp
|
||||||
break
|
break
|
||||||
except Exception:
|
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError, tomllib.TOMLDecodeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("load_project failed for %s: %s", pp, e, extra={"source": "app_controller._load_active_project.fallback_loop"})
|
||||||
continue
|
continue
|
||||||
if not self.active_project_path:
|
if not self.active_project_path:
|
||||||
name = self.project.get("project", {}).get("name", "project")
|
name = self.project.get("project", {}).get("name", "project")
|
||||||
@@ -2213,15 +2223,23 @@ class AppController:
|
|||||||
def _prune_old_logs(self) -> None:
|
def _prune_old_logs(self) -> None:
|
||||||
"""Asynchronously prunes old insignificant logs on startup."""
|
"""Asynchronously prunes old insignificant logs on startup."""
|
||||||
|
|
||||||
def run_prune() -> None:
|
def run_prune() -> Result[None]:
|
||||||
try:
|
try:
|
||||||
from src import log_registry
|
from src import log_registry
|
||||||
from src import log_pruner
|
from src import log_pruner
|
||||||
registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||||
pruner = log_pruner.LogPruner(registry, str(paths.get_logs_dir()))
|
pruner = log_pruner.LogPruner(registry, str(paths.get_logs_dir()))
|
||||||
pruner.prune()
|
pruner.prune()
|
||||||
except Exception as e:
|
return OK
|
||||||
|
except (OSError, IOError, ValueError, TypeError, AttributeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("log pruning error: %s", e, extra={"source": "app_controller._prune_old_logs.run_prune"})
|
||||||
print(f"Error during log pruning: {e}")
|
print(f"Error during log pruning: {e}")
|
||||||
|
return Result(data=None, errors=[ErrorInfo(
|
||||||
|
kind=ErrorKind.INTERNAL,
|
||||||
|
message=str(e),
|
||||||
|
source="app_controller._prune_old_logs.run_prune",
|
||||||
|
original=e,
|
||||||
|
)])
|
||||||
self.submit_io(run_prune)
|
self.submit_io(run_prune)
|
||||||
|
|
||||||
def start_services(self, app: Any = None):
|
def start_services(self, app: Any = None):
|
||||||
@@ -2915,7 +2933,8 @@ class AppController:
|
|||||||
tickets=tickets
|
tickets=tickets
|
||||||
)
|
)
|
||||||
self.active_tickets = at_data.get("tickets", []) # Keep dicts for UI table
|
self.active_tickets = at_data.get("tickets", []) # Keep dicts for UI table
|
||||||
except Exception as e:
|
except (TypeError, ValueError, KeyError, AttributeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("active track deserialize failed: %s", e, extra={"source": "app_controller._refresh_from_project.active_track"})
|
||||||
print(f"Failed to deserialize active track: {e}")
|
print(f"Failed to deserialize active track: {e}")
|
||||||
self.active_track = None
|
self.active_track = None
|
||||||
else:
|
else:
|
||||||
@@ -2969,7 +2988,8 @@ class AppController:
|
|||||||
try:
|
try:
|
||||||
cleaned = project_manager.clean_nones(self.project)
|
cleaned = project_manager.clean_nones(self.project)
|
||||||
project_manager.save_project(cleaned, self.active_project_path)
|
project_manager.save_project(cleaned, self.active_project_path)
|
||||||
except Exception as e:
|
except (OSError, IOError, ValueError, TypeError, KeyError, AttributeError) as e:
|
||||||
|
logging.getLogger(__name__).debug("save_project failed: %s", e, extra={"source": "app_controller._save_active_project"})
|
||||||
self.ai_status = f"save error: {e}"
|
self.ai_status = f"save error: {e}"
|
||||||
|
|
||||||
#endregion: Project
|
#endregion: Project
|
||||||
|
|||||||
Reference in New Issue
Block a user