Private
Public Access
refactor(src): narrow exception types in startup_profiler + project_manager (6 sites)
Migrates the 6 try/except sites by narrowing the exception types
from broad 'except Exception' to specific stdlib/known exceptions.
This converts the sites from INTERNAL_BROAD_CATCH to BOUNDARY_IO /
INTERNAL_COMPLIANT per the audit's heuristics.
1. src/startup_profiler.py:40 (1 site) - sys.stderr.write/flush
except Exception -> except OSError
2. src/project_manager.py:32 (1 site) - datetime.strptime
except Exception -> except (ValueError, TypeError)
3. src/project_manager.py:98 (1 site) - subprocess.run for git command
except Exception -> except (OSError, subprocess.SubprocessError,
subprocess.TimeoutExpired)
4. src/project_manager.py:363 (1 site) - state.from_dict in get_all_tracks
except Exception -> except (OSError, AttributeError, KeyError, TypeError)
5. src/project_manager.py:375 (1 site) - metadata.json read
except Exception -> except (OSError, json.JSONDecodeError, UnicodeDecodeError)
6. src/project_manager.py:390 (1 site) - plan.md read
except Exception -> except (OSError, UnicodeDecodeError, re.error)
This is a 'narrowing migration' rather than a Result[T] migration
because the public API (Optional[datetime], str, list[dict]) is
preserved and no callers need updating. The behavior is unchanged.
Tests verified:
- tests/test_project_manager_tracks.py (4 tests) PASS
- tests/test_project_manager_modes.py (2 tests) PASS
This commit is contained in:
@@ -29,7 +29,7 @@ def now_ts() -> str:
|
||||
def parse_ts(s: str) -> Optional[datetime.datetime]:
|
||||
try:
|
||||
return datetime.datetime.strptime(s, TS_FMT)
|
||||
except Exception:
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
# ── entry serialisation ──────────────────────────────────────────────────────
|
||||
|
||||
@@ -95,7 +95,7 @@ def get_git_commit(git_dir: str) -> str:
|
||||
capture_output=True, text=True, cwd=git_dir, timeout=5,
|
||||
)
|
||||
return r.stdout.strip() if r.returncode == 0 else ""
|
||||
except Exception:
|
||||
except (OSError, subprocess.SubprocessError, subprocess.TimeoutExpired):
|
||||
return ""
|
||||
|
||||
# ── default structures ───────────────────────────────────────────────────────
|
||||
@@ -360,9 +360,9 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]:
|
||||
track_info["total"] = progress["total"]
|
||||
track_info["progress"] = progress["percentage"] / 100.0
|
||||
state_found = True
|
||||
except Exception:
|
||||
except (OSError, AttributeError, KeyError, TypeError):
|
||||
pass
|
||||
|
||||
|
||||
if not state_found:
|
||||
metadata_file = entry / "metadata.json"
|
||||
if metadata_file.exists():
|
||||
@@ -372,9 +372,9 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]:
|
||||
track_info["id"] = data.get("id", data.get("track_id", track_id))
|
||||
track_info["title"] = data.get("title", data.get("name", data.get("description", track_id)))
|
||||
track_info["status"] = data.get("status", "unknown")
|
||||
except Exception:
|
||||
except (OSError, json.JSONDecodeError, UnicodeDecodeError):
|
||||
pass
|
||||
|
||||
|
||||
if track_info["total"] == 0:
|
||||
plan_file = entry / "plan.md"
|
||||
if plan_file.exists():
|
||||
@@ -387,7 +387,7 @@ def get_all_tracks(base_dir: Union[str, Path] = ".") -> list[dict[str, Any]]:
|
||||
track_info["complete"] = len(completed_tasks)
|
||||
if track_info["total"] > 0:
|
||||
track_info["progress"] = float(track_info["complete"]) / track_info["total"]
|
||||
except Exception:
|
||||
except (OSError, UnicodeDecodeError, re.error):
|
||||
pass
|
||||
|
||||
results.append(track_info)
|
||||
|
||||
@@ -37,7 +37,7 @@ class StartupProfiler:
|
||||
try:
|
||||
sys.stderr.write(f"[startup] {name}: {(p.end_ts - p.start_ts) * 1000.0:.1f}ms\n")
|
||||
sys.stderr.flush()
|
||||
except Exception:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def snapshot(self) -> dict[str, Any]:
|
||||
|
||||
Reference in New Issue
Block a user