mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-11-13 17:58:18 +00:00
fix(types): mypy clean again over src; stub-less libraries and the benchmark imports handled in pyproject
66 errors had accumulated in src since the last green run (the hunt modules of groups 4-6, stats, candidates, runner). Codex typed them without behaviour change; the 17 inline import-untyped ignores it added are replaced by one override for dspy, pandas, statsmodels and scikit-learn, and the hunt package's lazy imports of benchmarks/ (never type-checked, not in files) are followed silently so src stays strict against their signatures. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
0d7d3f0dc9
commit
c8f7610313
@@ -190,7 +190,7 @@ def run(
|
||||
if table.digest() != manifest.table_digest:
|
||||
raise ValueError("table digest does not match registration")
|
||||
runner.refuse_pilot(Path(pool_manifest_path), pilot_report=False)
|
||||
folds: dict[str, tuple[str, int]] = {}
|
||||
folds: dict[str, tuple[str, int | None]] = {}
|
||||
for row in table.rows:
|
||||
key, value = row["change_id"], (row["repo"], row.get("fold"))
|
||||
if key in folds and folds[key] != value:
|
||||
|
||||
@@ -77,7 +77,7 @@ class Decision:
|
||||
artifact.configurations.append(record)
|
||||
|
||||
|
||||
def _record(value: Any) -> dict[str, Any]:
|
||||
def _record(value: Estimate | FoldResult | Mapping[str, Any]) -> dict[str, Any]:
|
||||
"""Convert dataclass estimates and ordinary mappings to JSON records."""
|
||||
return asdict(value) if is_dataclass(value) else dict(value)
|
||||
|
||||
@@ -124,7 +124,8 @@ def decide(
|
||||
instructions = [state.get("signature", {}).get("instructions", "") for state in candidate.state.values()]
|
||||
if any(not isinstance(text, str) or len(text) > rule.instruction_cap for text in instructions):
|
||||
reasons.append("instruction_cap")
|
||||
compiled, heldout = {}, {}
|
||||
compiled: dict[str, dict[str, Any]] = {}
|
||||
heldout: dict[str, dict[str, Any]] = {}
|
||||
for scope, source, target in (("compile", compile_results, compiled), ("holdout", holdout_results, heldout)):
|
||||
for family, result in source.items():
|
||||
record = _record(result)
|
||||
@@ -150,10 +151,10 @@ def decide(
|
||||
reasons.append("no_positive_recall_difference")
|
||||
if _valid_number(holdout_diff) and abs(holdout_diff) <= rule.tolerance:
|
||||
reasons.append("holdout_tie")
|
||||
for family, result in heldout.items():
|
||||
for family, heldout_record in heldout.items():
|
||||
if family == "pooled":
|
||||
continue
|
||||
diff = result["recall"].get("diff")
|
||||
diff = heldout_record["recall"].get("diff")
|
||||
floor = rule.regression_budget.get(family, rule.regression_budget.get("default", 0))
|
||||
if _valid_number(diff) and diff < floor:
|
||||
reasons.append(f"family_regression:{family}")
|
||||
|
||||
@@ -28,7 +28,7 @@ def _exhausted(usage: Mapping[str, float], budget: Mapping[str, float]) -> bool:
|
||||
class RunArtifact:
|
||||
program_id: str
|
||||
schema_version: int
|
||||
mask: tuple[str, ...]
|
||||
mask: tuple[str, ...] | list[str]
|
||||
data_digests: dict[str, str]
|
||||
configurations: list[dict[str, Any]]
|
||||
usage: dict[str, float]
|
||||
|
||||
@@ -4,13 +4,14 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import tomllib
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Callable, Iterable
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _eligibility():
|
||||
def _eligibility() -> tuple[re.Pattern[str], Callable[[str], str]]:
|
||||
"""The benchmark's name normaliser and GitHub URL pattern, imported late so the package imports without the benchmarks tree."""
|
||||
from benchmarks.unseen.eligibility import URL, normalize
|
||||
|
||||
|
||||
@@ -234,7 +234,7 @@ def _roles(function: Any, facts: Any) -> dict[str, str]:
|
||||
for call in function.calls:
|
||||
for arguments in call.arg_names:
|
||||
names.update(arguments)
|
||||
roles = {}
|
||||
roles: dict[str, str] = {}
|
||||
for role, entries, attribute in (
|
||||
("source", facts.sources, "patterns"),
|
||||
("sink", facts.sinks, "calls"),
|
||||
|
||||
@@ -67,7 +67,8 @@ def signature_for(mask: Iterable[str] = ()) -> type[dspy.Signature]:
|
||||
continue
|
||||
fields[name] = (str, dspy.InputField(desc=desc))
|
||||
fields["findings"] = (list[Finding], dspy.OutputField(desc="JSON list; empty when the change is ordinary"))
|
||||
return dspy.Signature(fields, BASELINE_INSTRUCTION)
|
||||
signature: type[dspy.Signature] = dspy.Signature(fields, BASELINE_INSTRUCTION)
|
||||
return signature
|
||||
|
||||
|
||||
def numbered(lines: Sequence[str], start: int, end: int) -> str:
|
||||
@@ -194,7 +195,9 @@ class _Loop(dspy.ReAct):
|
||||
|
||||
loop_parse_failed = False
|
||||
|
||||
def _call_with_potential_trajectory_truncation(self, module, trajectory, **input_args):
|
||||
def _call_with_potential_trajectory_truncation(
|
||||
self, module: dspy.Module, trajectory: dict[str, Any], **input_args: str
|
||||
) -> dspy.Prediction:
|
||||
try:
|
||||
return super()._call_with_potential_trajectory_truncation(module, trajectory, **input_args)
|
||||
except dspy.utils.exceptions.AdapterParseError as error:
|
||||
|
||||
@@ -20,7 +20,7 @@ from .metric import search_metric, search_outcome
|
||||
from .table import FEATURE_COLUMNS, canonical_json
|
||||
|
||||
|
||||
class _Optimisers(Mapping):
|
||||
class _Optimisers(Mapping[str, type]):
|
||||
"""Load a DSPy optimiser class only when its registry entry is requested."""
|
||||
|
||||
names = {"gepa": "GEPA", "miprov2": "MIPROv2", "bootstrap": "BootstrapFewShot"}
|
||||
@@ -28,7 +28,8 @@ class _Optimisers(Mapping):
|
||||
def __getitem__(self, name: str) -> type:
|
||||
import dspy
|
||||
|
||||
return getattr(dspy, self.names[name])
|
||||
optimiser: type = getattr(dspy, self.names[name])
|
||||
return optimiser
|
||||
|
||||
def __iter__(self) -> Iterator[str]:
|
||||
return iter(self.names)
|
||||
@@ -93,7 +94,8 @@ def compile_examples(
|
||||
|
||||
from .program import INPUTS
|
||||
|
||||
repo_folds, ids = {}, set()
|
||||
repo_folds: dict[str, int] = {}
|
||||
ids: set[str] = set()
|
||||
for change in changes:
|
||||
if change["id"] in ids:
|
||||
raise ValueError("change IDs must be unique")
|
||||
@@ -230,7 +232,13 @@ def _compile(round: Round, program: Any, examples: list, optimiser: Any, metric:
|
||||
if dspy.settings.lm is None:
|
||||
raise ValueError("GEPA needs a configured reflection model in dspy.context")
|
||||
|
||||
def feedback(example, prediction, trace=None, pred_name=None, pred_trace=None):
|
||||
def feedback(
|
||||
example: dspy.Example,
|
||||
prediction: dspy.Prediction,
|
||||
trace: Any = None,
|
||||
pred_name: str | None = None,
|
||||
pred_trace: Any = None,
|
||||
) -> dspy.Prediction:
|
||||
"""Give GEPA the same score and the metric's compile-only feedback."""
|
||||
import dspy
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ def _instrument(records: Sequence[Mapping]) -> dict:
|
||||
)
|
||||
|
||||
|
||||
def _clean(records: Sequence[Mapping]) -> list[dict]:
|
||||
def _clean(records: Sequence[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||
"""Remove stale findings on failures while preserving the scorer's coverage checks."""
|
||||
from benchmarks.unseen import score
|
||||
|
||||
@@ -109,7 +109,7 @@ def _clean(records: Sequence[Mapping]) -> list[dict]:
|
||||
return result
|
||||
|
||||
|
||||
def _rate(values: list[float], repos: list[str], *, binary: bool = False, scale: float = 1) -> dict:
|
||||
def _rate(values: Sequence[float], repos: list[str], *, binary: bool = False, scale: float = 1) -> dict:
|
||||
"""Report a mean with its count and a repository-clustered interval, plus Wilson for proportions."""
|
||||
from benchmarks.unseen import score
|
||||
|
||||
@@ -127,7 +127,7 @@ def _rate(values: list[float], repos: list[str], *, binary: bool = False, scale:
|
||||
return result
|
||||
|
||||
|
||||
def _family_records(records: Sequence[Mapping], family: str | None) -> list[dict]:
|
||||
def _family_records(records: Sequence[dict[str, Any]], family: str | None) -> list[dict[str, Any]]:
|
||||
"""Keep a family's positives and count only its findings over all ordinary pushes."""
|
||||
result = []
|
||||
for original in records:
|
||||
@@ -217,7 +217,7 @@ def _baseline_comparison(baselines: list[list[dict]], records: list[dict], famil
|
||||
from benchmarks.unseen import score
|
||||
from benchmarks.valid import metrics
|
||||
|
||||
units = [
|
||||
units: list[dict[str, Any]] = [
|
||||
dict(change=after, repeat=repeat, a=_outcome(before, before, 10), b=_outcome(after, after, 10))
|
||||
for repeat, baseline in enumerate(baselines)
|
||||
for before, after in zip(baseline, records, strict=True)
|
||||
@@ -232,7 +232,7 @@ def _baseline_comparison(baselines: list[list[dict]], records: list[dict], famil
|
||||
suspicions_per_push=asdict(suspicions),
|
||||
mcnemar=asdict(stats.mcnemar_exact([u["a"]["hit"] for u in positives], [u["b"]["hit"] for u in positives])),
|
||||
)
|
||||
rows = {"recall": [], "false_alarms_per_100_pushes": [], "precision": []}
|
||||
rows: dict[str, list[dict[str, Any]]] = {"recall": [], "false_alarms_per_100_pushes": [], "precision": []}
|
||||
for baseline in baselines:
|
||||
before = metrics.scoring_records(_family_records(baseline, family))
|
||||
after = metrics.scoring_records(_family_records(records, family))
|
||||
@@ -426,7 +426,7 @@ def pilot_gain(
|
||||
records = _records(directory / "records", changes)
|
||||
proof = _instrument(records)
|
||||
_write(directory / "instrument.json", proof)
|
||||
analysis = dict(
|
||||
analysis: dict[str, Any] = dict(
|
||||
program_id=candidate.program_id,
|
||||
comparison=decision.comparison,
|
||||
measurement_directory=directory.name,
|
||||
|
||||
@@ -21,7 +21,8 @@ def _fold_changes(pool_manifest: Path, table: FeatureTable, load_changes: Any) -
|
||||
from benchmarks.unseen.replay import load_slice
|
||||
|
||||
runner.refuse_pilot(pool_manifest, pilot_report=False)
|
||||
folds, repo_folds = {}, {}
|
||||
folds: dict[str, tuple[str, int]] = {}
|
||||
repo_folds: dict[str, int] = {}
|
||||
for row in table.rows:
|
||||
key, repo, fold = row["change_id"], row["repo"], row.get("fold")
|
||||
if type(fold) is not int or fold < 0:
|
||||
@@ -183,7 +184,8 @@ def fold_results(
|
||||
if len({c["id"] for c in changes}) != len(changes):
|
||||
raise ValueError("change IDs must be unique")
|
||||
directories = {"a": Path(current_dir), "b": Path(candidate_dir)}
|
||||
studies, repeats = {}, set()
|
||||
studies: dict[str, Any] = {}
|
||||
repeats: set[int] = set()
|
||||
for arm, directory in directories.items():
|
||||
path = directory / "study.json"
|
||||
if path.exists():
|
||||
@@ -291,7 +293,7 @@ def round_trip(
|
||||
)
|
||||
)
|
||||
results[scope] = fold_results(
|
||||
*paths, [c for c in changes if c["fold"] in folds], scope=scope, tolerance=tolerance, seed=seed, resamples=resamples
|
||||
paths[0], paths[1], [c for c in changes if c["fold"] in folds], scope=scope, tolerance=tolerance, seed=seed, resamples=resamples
|
||||
)
|
||||
decision = accept.decide(current_id, candidate, results["compile"], results["holdout"], rule)
|
||||
if not decision.accepted:
|
||||
|
||||
Reference in New Issue
Block a user