mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +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
@@ -90,6 +90,17 @@ ignore_missing_imports = true
|
|||||||
module = "yaml"
|
module = "yaml"
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
# dspy, pandas, statsmodels and scikit-learn ship no py.typed marker and no stub packages are dev dependencies.
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = ["dspy", "dspy.*", "pandas", "pandas.*", "statsmodels.*", "sklearn.*"]
|
||||||
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
# The hunt package reaches the benchmark scorers and manifests lazily. benchmarks/ is not in `files` and has never
|
||||||
|
# been type-checked; src stays strict against its signatures while errors inside benchmarks/ are not reported.
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = "benchmarks.*"
|
||||||
|
follow_imports = "silent"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"dagger-io>=0.21.7",
|
"dagger-io>=0.21.7",
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ def run(
|
|||||||
if table.digest() != manifest.table_digest:
|
if table.digest() != manifest.table_digest:
|
||||||
raise ValueError("table digest does not match registration")
|
raise ValueError("table digest does not match registration")
|
||||||
runner.refuse_pilot(Path(pool_manifest_path), pilot_report=False)
|
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:
|
for row in table.rows:
|
||||||
key, value = row["change_id"], (row["repo"], row.get("fold"))
|
key, value = row["change_id"], (row["repo"], row.get("fold"))
|
||||||
if key in folds and folds[key] != value:
|
if key in folds and folds[key] != value:
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class Decision:
|
|||||||
artifact.configurations.append(record)
|
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."""
|
"""Convert dataclass estimates and ordinary mappings to JSON records."""
|
||||||
return asdict(value) if is_dataclass(value) else dict(value)
|
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()]
|
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):
|
if any(not isinstance(text, str) or len(text) > rule.instruction_cap for text in instructions):
|
||||||
reasons.append("instruction_cap")
|
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 scope, source, target in (("compile", compile_results, compiled), ("holdout", holdout_results, heldout)):
|
||||||
for family, result in source.items():
|
for family, result in source.items():
|
||||||
record = _record(result)
|
record = _record(result)
|
||||||
@@ -150,10 +151,10 @@ def decide(
|
|||||||
reasons.append("no_positive_recall_difference")
|
reasons.append("no_positive_recall_difference")
|
||||||
if _valid_number(holdout_diff) and abs(holdout_diff) <= rule.tolerance:
|
if _valid_number(holdout_diff) and abs(holdout_diff) <= rule.tolerance:
|
||||||
reasons.append("holdout_tie")
|
reasons.append("holdout_tie")
|
||||||
for family, result in heldout.items():
|
for family, heldout_record in heldout.items():
|
||||||
if family == "pooled":
|
if family == "pooled":
|
||||||
continue
|
continue
|
||||||
diff = result["recall"].get("diff")
|
diff = heldout_record["recall"].get("diff")
|
||||||
floor = rule.regression_budget.get(family, rule.regression_budget.get("default", 0))
|
floor = rule.regression_budget.get(family, rule.regression_budget.get("default", 0))
|
||||||
if _valid_number(diff) and diff < floor:
|
if _valid_number(diff) and diff < floor:
|
||||||
reasons.append(f"family_regression:{family}")
|
reasons.append(f"family_regression:{family}")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def _exhausted(usage: Mapping[str, float], budget: Mapping[str, float]) -> bool:
|
|||||||
class RunArtifact:
|
class RunArtifact:
|
||||||
program_id: str
|
program_id: str
|
||||||
schema_version: int
|
schema_version: int
|
||||||
mask: tuple[str, ...]
|
mask: tuple[str, ...] | list[str]
|
||||||
data_digests: dict[str, str]
|
data_digests: dict[str, str]
|
||||||
configurations: list[dict[str, Any]]
|
configurations: list[dict[str, Any]]
|
||||||
usage: dict[str, float]
|
usage: dict[str, float]
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
import tomllib
|
import tomllib
|
||||||
from collections.abc import Iterable
|
from collections.abc import Callable, Iterable
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from pathlib import Path
|
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."""
|
"""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
|
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 call in function.calls:
|
||||||
for arguments in call.arg_names:
|
for arguments in call.arg_names:
|
||||||
names.update(arguments)
|
names.update(arguments)
|
||||||
roles = {}
|
roles: dict[str, str] = {}
|
||||||
for role, entries, attribute in (
|
for role, entries, attribute in (
|
||||||
("source", facts.sources, "patterns"),
|
("source", facts.sources, "patterns"),
|
||||||
("sink", facts.sinks, "calls"),
|
("sink", facts.sinks, "calls"),
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ def signature_for(mask: Iterable[str] = ()) -> type[dspy.Signature]:
|
|||||||
continue
|
continue
|
||||||
fields[name] = (str, dspy.InputField(desc=desc))
|
fields[name] = (str, dspy.InputField(desc=desc))
|
||||||
fields["findings"] = (list[Finding], dspy.OutputField(desc="JSON list; empty when the change is ordinary"))
|
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:
|
def numbered(lines: Sequence[str], start: int, end: int) -> str:
|
||||||
@@ -194,7 +195,9 @@ class _Loop(dspy.ReAct):
|
|||||||
|
|
||||||
loop_parse_failed = False
|
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:
|
try:
|
||||||
return super()._call_with_potential_trajectory_truncation(module, trajectory, **input_args)
|
return super()._call_with_potential_trajectory_truncation(module, trajectory, **input_args)
|
||||||
except dspy.utils.exceptions.AdapterParseError as error:
|
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
|
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."""
|
"""Load a DSPy optimiser class only when its registry entry is requested."""
|
||||||
|
|
||||||
names = {"gepa": "GEPA", "miprov2": "MIPROv2", "bootstrap": "BootstrapFewShot"}
|
names = {"gepa": "GEPA", "miprov2": "MIPROv2", "bootstrap": "BootstrapFewShot"}
|
||||||
@@ -28,7 +28,8 @@ class _Optimisers(Mapping):
|
|||||||
def __getitem__(self, name: str) -> type:
|
def __getitem__(self, name: str) -> type:
|
||||||
import dspy
|
import dspy
|
||||||
|
|
||||||
return getattr(dspy, self.names[name])
|
optimiser: type = getattr(dspy, self.names[name])
|
||||||
|
return optimiser
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[str]:
|
def __iter__(self) -> Iterator[str]:
|
||||||
return iter(self.names)
|
return iter(self.names)
|
||||||
@@ -93,7 +94,8 @@ def compile_examples(
|
|||||||
|
|
||||||
from .program import INPUTS
|
from .program import INPUTS
|
||||||
|
|
||||||
repo_folds, ids = {}, set()
|
repo_folds: dict[str, int] = {}
|
||||||
|
ids: set[str] = set()
|
||||||
for change in changes:
|
for change in changes:
|
||||||
if change["id"] in ids:
|
if change["id"] in ids:
|
||||||
raise ValueError("change IDs must be unique")
|
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:
|
if dspy.settings.lm is None:
|
||||||
raise ValueError("GEPA needs a configured reflection model in dspy.context")
|
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."""
|
"""Give GEPA the same score and the metric's compile-only feedback."""
|
||||||
import dspy
|
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."""
|
"""Remove stale findings on failures while preserving the scorer's coverage checks."""
|
||||||
from benchmarks.unseen import score
|
from benchmarks.unseen import score
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ def _clean(records: Sequence[Mapping]) -> list[dict]:
|
|||||||
return result
|
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."""
|
"""Report a mean with its count and a repository-clustered interval, plus Wilson for proportions."""
|
||||||
from benchmarks.unseen import score
|
from benchmarks.unseen import score
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ def _rate(values: list[float], repos: list[str], *, binary: bool = False, scale:
|
|||||||
return result
|
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."""
|
"""Keep a family's positives and count only its findings over all ordinary pushes."""
|
||||||
result = []
|
result = []
|
||||||
for original in records:
|
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.unseen import score
|
||||||
from benchmarks.valid import metrics
|
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))
|
dict(change=after, repeat=repeat, a=_outcome(before, before, 10), b=_outcome(after, after, 10))
|
||||||
for repeat, baseline in enumerate(baselines)
|
for repeat, baseline in enumerate(baselines)
|
||||||
for before, after in zip(baseline, records, strict=True)
|
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),
|
suspicions_per_push=asdict(suspicions),
|
||||||
mcnemar=asdict(stats.mcnemar_exact([u["a"]["hit"] for u in positives], [u["b"]["hit"] for u in positives])),
|
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:
|
for baseline in baselines:
|
||||||
before = metrics.scoring_records(_family_records(baseline, family))
|
before = metrics.scoring_records(_family_records(baseline, family))
|
||||||
after = metrics.scoring_records(_family_records(records, family))
|
after = metrics.scoring_records(_family_records(records, family))
|
||||||
@@ -426,7 +426,7 @@ def pilot_gain(
|
|||||||
records = _records(directory / "records", changes)
|
records = _records(directory / "records", changes)
|
||||||
proof = _instrument(records)
|
proof = _instrument(records)
|
||||||
_write(directory / "instrument.json", proof)
|
_write(directory / "instrument.json", proof)
|
||||||
analysis = dict(
|
analysis: dict[str, Any] = dict(
|
||||||
program_id=candidate.program_id,
|
program_id=candidate.program_id,
|
||||||
comparison=decision.comparison,
|
comparison=decision.comparison,
|
||||||
measurement_directory=directory.name,
|
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
|
from benchmarks.unseen.replay import load_slice
|
||||||
|
|
||||||
runner.refuse_pilot(pool_manifest, pilot_report=False)
|
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:
|
for row in table.rows:
|
||||||
key, repo, fold = row["change_id"], row["repo"], row.get("fold")
|
key, repo, fold = row["change_id"], row["repo"], row.get("fold")
|
||||||
if type(fold) is not int or fold < 0:
|
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):
|
if len({c["id"] for c in changes}) != len(changes):
|
||||||
raise ValueError("change IDs must be unique")
|
raise ValueError("change IDs must be unique")
|
||||||
directories = {"a": Path(current_dir), "b": Path(candidate_dir)}
|
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():
|
for arm, directory in directories.items():
|
||||||
path = directory / "study.json"
|
path = directory / "study.json"
|
||||||
if path.exists():
|
if path.exists():
|
||||||
@@ -291,7 +293,7 @@ def round_trip(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
results[scope] = fold_results(
|
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)
|
decision = accept.decide(current_id, candidate, results["compile"], results["holdout"], rule)
|
||||||
if not decision.accepted:
|
if not decision.accepted:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import os
|
|||||||
import re
|
import re
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import NotRequired, TypedDict
|
||||||
|
|
||||||
from .preprocess import enumerate_source_files
|
from .preprocess import enumerate_source_files
|
||||||
from .source import callers_of, product_files
|
from .source import callers_of, product_files
|
||||||
@@ -67,11 +68,19 @@ def _mtime(path: Path) -> int:
|
|||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
|
||||||
def grep_repo(root: Path, pattern: str, *, max_matches: int) -> list[dict[str, object]]:
|
class ToolMatch(TypedDict):
|
||||||
|
path: str
|
||||||
|
line: int
|
||||||
|
text: str
|
||||||
|
name: NotRequired[str]
|
||||||
|
source: NotRequired[str]
|
||||||
|
|
||||||
|
|
||||||
|
def grep_repo(root: Path, pattern: str, *, max_matches: int) -> list[ToolMatch]:
|
||||||
if max_matches <= 0:
|
if max_matches <= 0:
|
||||||
return []
|
return []
|
||||||
compiled = re.compile(pattern)
|
compiled = re.compile(pattern)
|
||||||
matches: list[dict[str, object]] = []
|
matches: list[ToolMatch] = []
|
||||||
for relative, lines in _source_lines(root):
|
for relative, lines in _source_lines(root):
|
||||||
for line_no, line in enumerate(lines, start=1):
|
for line_no, line in enumerate(lines, start=1):
|
||||||
if compiled.search(line):
|
if compiled.search(line):
|
||||||
@@ -81,7 +90,7 @@ def grep_repo(root: Path, pattern: str, *, max_matches: int) -> list[dict[str, o
|
|||||||
return matches
|
return matches
|
||||||
|
|
||||||
|
|
||||||
def find_refs(root: Path, symbol: str) -> list[dict[str, object]]:
|
def find_refs(root: Path, symbol: str) -> list[ToolMatch]:
|
||||||
if not symbol:
|
if not symbol:
|
||||||
return []
|
return []
|
||||||
lines = dict(_source_lines(root))
|
lines = dict(_source_lines(root))
|
||||||
|
|||||||
@@ -752,8 +752,11 @@ class LabelBuilder:
|
|||||||
if not function:
|
if not function:
|
||||||
lines = self._clone(population, str(case["id"])).lines(str(case["vulnerable"]), site_path)
|
lines = self._clone(population, str(case["id"])).lines(str(case["vulnerable"]), site_path)
|
||||||
language = detect_language(Path(site_path))
|
language = detect_language(Path(site_path))
|
||||||
covered = lines and language in DECLARATION and line <= len(lines)
|
function = (
|
||||||
function = enclosing(lines, line - 1, language) if covered else MODULE_FUNCTION
|
enclosing(lines, line - 1, language)
|
||||||
|
if lines and language in DECLARATION and line <= len(lines)
|
||||||
|
else MODULE_FUNCTION
|
||||||
|
)
|
||||||
self._row(
|
self._row(
|
||||||
candidate=f"{site_path}::{function}", family=str(row.get("family") or case["family"]), label=label, source=source.id,
|
candidate=f"{site_path}::{function}", family=str(row.get("family") or case["family"]), label=label, source=source.id,
|
||||||
source_ref=f"{Path(path).name}#{key}[{index}]", unit="pin", weight=1.0, split=population.id,
|
source_ref=f"{Path(path).name}#{key}[{index}]", unit="pin", weight=1.0, split=population.id,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from dataclasses import dataclass, field
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING, Literal
|
from typing import TYPE_CHECKING, Literal
|
||||||
|
|
||||||
from ..source import canonical_language
|
from ..source import FunctionRange, canonical_language
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .taxonomy import FamilyTaxonomy
|
from .taxonomy import FamilyTaxonomy
|
||||||
@@ -368,7 +368,7 @@ def labeled_family(case: object, taxonomy: FamilyTaxonomy | None = None) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def labeled_spans(
|
def labeled_spans(
|
||||||
case: object, ranges: Mapping[str, Sequence[tuple[str, int, int]]], *, function: str = ""
|
case: object, ranges: Mapping[str, Sequence[tuple[str, int, int] | FunctionRange]], *, function: str = ""
|
||||||
) -> tuple[tuple[str, int, int], ...]:
|
) -> tuple[tuple[str, int, int], ...]:
|
||||||
"""The (path, start, end) spans of the labeled functions; ``function`` overrides the label for the fixed side.
|
"""The (path, start, end) spans of the labeled functions; ``function`` overrides the label for the fixed side.
|
||||||
|
|
||||||
@@ -378,6 +378,7 @@ def labeled_spans(
|
|||||||
wanted = {function} if function else {str(getattr(row, "function", "") or "") for row in getattr(case, "expected", ()) or ()}
|
wanted = {function} if function else {str(getattr(row, "function", "") or "") for row in getattr(case, "expected", ()) or ()}
|
||||||
wanted.discard("")
|
wanted.discard("")
|
||||||
found: list[tuple[str, int, int]] = []
|
found: list[tuple[str, int, int]] = []
|
||||||
|
_kind: list[str]
|
||||||
for path, entries in ranges.items():
|
for path, entries in ranges.items():
|
||||||
for name, start, end, *_kind in entries:
|
for name, start, end, *_kind in entries:
|
||||||
if name in wanted:
|
if name in wanted:
|
||||||
|
|||||||
@@ -704,7 +704,7 @@ def safe_url(url: str) -> str:
|
|||||||
def deliver(
|
def deliver(
|
||||||
url: str,
|
url: str,
|
||||||
payload: bytes,
|
payload: bytes,
|
||||||
headers: Mapping[str, str],
|
headers: MutableMapping[str, str],
|
||||||
*,
|
*,
|
||||||
attempts: int = DELIVERY_ATTEMPTS,
|
attempts: int = DELIVERY_ATTEMPTS,
|
||||||
backoff: float = 1.0,
|
backoff: float = 1.0,
|
||||||
@@ -732,7 +732,7 @@ def deliver(
|
|||||||
raise DeliveryError(f"{last} after {attempts} attempts to {safe_url(url)}")
|
raise DeliveryError(f"{last} after {attempts} attempts to {safe_url(url)}")
|
||||||
|
|
||||||
|
|
||||||
def fetch(url: str, headers: Mapping[str, str], dest: Path, *, attempts: int = DELIVERY_ATTEMPTS, backoff: float = 1.0) -> int:
|
def fetch(url: str, headers: MutableMapping[str, str], dest: Path, *, attempts: int = DELIVERY_ATTEMPTS, backoff: float = 1.0) -> int:
|
||||||
"""GET ``url`` into ``dest`` (streamed to a sibling temp file, then renamed); retried like :func:`deliver`.
|
"""GET ``url`` into ``dest`` (streamed to a sibling temp file, then renamed); retried like :func:`deliver`.
|
||||||
|
|
||||||
Returns the byte count; :class:`DeliveryError` names the last cause when every attempt failed."""
|
Returns the byte count; :class:`DeliveryError` names the last cause when every attempt failed."""
|
||||||
|
|||||||
@@ -409,9 +409,11 @@ def _side(side: Side, demo: Path, family: str, timeout: int, browser: BrowserExe
|
|||||||
if task_boundary:
|
if task_boundary:
|
||||||
# Files are app data, so resolve their paths before writing;
|
# Files are app data, so resolve their paths before writing;
|
||||||
# the task runner only translates argv and environment.
|
# the task runner only translates argv and environment.
|
||||||
|
def fixture_path(_: re.Match[str], path: str = str(canary.root)) -> str:
|
||||||
|
return path
|
||||||
|
|
||||||
file_bindings = {
|
file_bindings = {
|
||||||
key: re.sub(r"/(?:fixture|scratch)(?=/|$)", lambda _, path=str(canary.root): path, value)
|
key: re.sub(r"/(?:fixture|scratch)(?=/|$)", fixture_path, value) for key, value in bindings.items()
|
||||||
for key, value in bindings.items()
|
|
||||||
}
|
}
|
||||||
private_values.extend((*bindings.values(), *file_bindings.values()))
|
private_values.extend((*bindings.values(), *file_bindings.values()))
|
||||||
write_start_files(checkout, start_spec, file_bindings)
|
write_start_files(checkout, start_spec, file_bindings)
|
||||||
|
|||||||
@@ -307,6 +307,7 @@ _HEAD = re.compile(
|
|||||||
def _regex_ranges(text: str, language: str) -> tuple[FunctionRange, ...]:
|
def _regex_ranges(text: str, language: str) -> tuple[FunctionRange, ...]:
|
||||||
lines, code = text.splitlines(), _code_lines(text)
|
lines, code = text.splitlines(), _code_lines(text)
|
||||||
result = []
|
result = []
|
||||||
|
end: int | None
|
||||||
for index, line in enumerate(code):
|
for index, line in enumerate(code):
|
||||||
name = declarator_name(line, language)
|
name = declarator_name(line, language)
|
||||||
if language == "python":
|
if language == "python":
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ def separation(frame: Any, label: str, columns: Iterable[str]) -> Any:
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from sklearn.metrics import roc_auc_score
|
from sklearn.metrics import roc_auc_score
|
||||||
|
|
||||||
rows = []
|
rows: list[dict[str, str | float | None]] = []
|
||||||
labelled = frame[frame[label].isin([0, 1])]
|
labelled = frame[frame[label].isin([0, 1])]
|
||||||
for column in columns:
|
for column in columns:
|
||||||
series = pd.to_numeric(labelled[column], errors="coerce") if column in labelled else None
|
series = pd.to_numeric(labelled[column], errors="coerce") if column in labelled else None
|
||||||
|
|||||||
Reference in New Issue
Block a user