chore: bump uv.lock and fix ruff 0.16 default-rule lint findings
CI / Sync project version with tag (hand-pushed tags only) (pull_request) Has been skipped
CI / Publish package to Gitea package registry (pull_request) Has been skipped
CI / Format (ruff format) (pull_request) Successful in 53s
CI / Type check (ty) (pull_request) Successful in 57s
CI / Lint (ruff check) (pull_request) Successful in 41s
CI / Tests (pull_request) Successful in 8m20s
CI / Release (bump, changelog, badges, tag) on merge to master (pull_request) Has been skipped

uv.lock was stale (ty 0.0.50 -> 0.0.78, ruff 0.15 -> 0.16, polars, numpy,
typer, wandb, pytest, and others), all within existing pyproject.toml
bounds. ruff 0.16 widened its default rule selection, taking this repo
from 0 to 274 lint errors under the same config; --fix handled most of
it (import sorting, Optional[X] -> X | None, ...), and the remainder
(unused unpacked variables, dict()-as-literal, subprocess.run without
explicit check=, a couple of intentional broad excepts/naive datetimes)
were fixed or annotated by hand. Also fixes a real type-narrowing gap
ty 0.0.78 caught in test_config_consumed_keys.py's `or`-combined
isinstance check.

torch stays pinned to 2.3.x (deliberate, see CLAUDE.md); pyarrow's <25
ceiling is left as a separate decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TMdZFqXXig7i3XkirSUxef
This commit is contained in:
2026-09-04 14:09:29 +02:00
parent 600e04f46a
commit c984d0a19d
60 changed files with 1686 additions and 1427 deletions
+11 -11
View File
@@ -17,8 +17,8 @@ import re
from collections.abc import Sequence
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch import nn
from giant.constants import (
COND_DIM,
@@ -949,7 +949,7 @@ def _check_router_conditioning_compat(router_types: list[str], conditioning: str
def _build_router_from_cfg(router_cfg: dict, pdg_vocab: int, mat_vocab: int, conditioning: str = "embedding") -> Router:
shared_vocab = dict(pdg_vocab=pdg_vocab, mat_vocab=mat_vocab)
shared_vocab = {"pdg_vocab": pdg_vocab, "mat_vocab": mat_vocab}
if router_cfg["type"] == "composed":
axes = _parse_composed_axes(router_cfg)
_check_router_conditioning_compat([a["type"] for a in axes], conditioning)
@@ -977,15 +977,15 @@ def build_models(model_config: dict) -> tuple[nn.Module, nn.Module]:
if router_cfg and router_cfg.get("enabled"):
pdg_vocab = model_config["pdg_vocab"]
mat_vocab = model_config["mat_vocab"]
shared = dict(
pdg_vocab=pdg_vocab,
mat_vocab=mat_vocab,
expert_hidden_dim=model_config.get("expert_hidden_dim") or model_config.get("hidden_dim", 128),
expert_n_blocks=model_config.get("expert_n_blocks") or model_config.get("n_blocks", 3),
emb_dim=model_config.get("emb_dim", EMB_DIM),
dropout=model_config.get("dropout", 0.1),
conditioning=model_config.get("conditioning", "embedding"),
)
shared = {
"pdg_vocab": pdg_vocab,
"mat_vocab": mat_vocab,
"expert_hidden_dim": model_config.get("expert_hidden_dim") or model_config.get("hidden_dim", 128),
"expert_n_blocks": model_config.get("expert_n_blocks") or model_config.get("n_blocks", 3),
"emb_dim": model_config.get("emb_dim", EMB_DIM),
"dropout": model_config.get("dropout", 0.1),
"conditioning": model_config.get("conditioning", "embedding"),
}
conditioning = shared["conditioning"]
stage1 = RoutedDenoisingMLP(
router=_build_router_from_cfg(router_cfg, pdg_vocab, mat_vocab, conditioning),
+1 -1
View File
@@ -5,12 +5,12 @@ from pathlib import Path
import pytest
import torch
from test_train import _base_cfg, _run_train
from giant.model.routers import EnergyRouter
from giant.model.wgan import gradient_penalty
from giant.training.amp import resolve_autocast
from giant.training.stage2_inputs import _remaining_energy_fraction
from test_train import _base_cfg, _run_train
# ---------------------------------------------------------------------------
# resolve_autocast
+1 -1
View File
@@ -184,7 +184,7 @@ def test_weighted_profile_matches_manual_bincount():
ea = R.entry_axis(lf)
lf2 = R.attach_entry_axis(lf, ea)
edges = np.linspace(0.0, 3.0, 4) # depth bins along +z
mean, std = R.weighted_profile(lf2, R.depth_expr(), edges, pl.col("edep"))
mean, _ = R.weighted_profile(lf2, R.depth_expr(), edges, pl.col("edep"))
assert mean.shape == (3,)
# totals conserved: sum over bins == mean total edep per event
assert np.isclose(mean.sum() * 1, (90.0 + 30.0) / 2) # 2 events
+2 -2
View File
@@ -197,7 +197,7 @@ def test_update_manifest_reports_missing_targets(tmp_path):
# schema2 dir exists but the parquet file does not
(tmp_path / "processed" / "steps" / "gen1" / "schema2").mkdir(parents=True)
lines, missing = plan_update_manifest(manifest, "schema2")
_, missing = plan_update_manifest(manifest, "schema2")
assert len(missing) == 1
assert "schema2" in str(missing[0])
@@ -313,7 +313,7 @@ def test_create_manifest_writes_relative_paths(tmp_path):
def test_create_manifest_reports_missing_files(tmp_path):
ghost = tmp_path / "processed" / "gen1" / "schema2" / "shard-000.parquet"
output = tmp_path / "pools" / "full.manifest"
lines, missing, _ = plan_create_manifest(output, [ghost])
_, missing, _ = plan_create_manifest(output, [ghost])
assert len(missing) == 1
assert missing[0] == ghost.resolve()
+1 -1
View File
@@ -9,7 +9,7 @@ from pathlib import Path
from typer.testing import CliRunner
import giant.cli as cli
from giant import cli
runner = CliRunner()
+1
View File
@@ -1,4 +1,5 @@
import pytest
from giant.cond_layout import AXIS_TYPES, CondLayout
from giant.constants import COND_DIM, COND_DIM_BASE, MATERIAL_PHYS_DIM, PARTICLE_PHYS_DIM
+1 -1
View File
@@ -576,7 +576,7 @@ def test_save_config_round_trips_three_level_nesting(tmp_path):
# default_out_dir_name
# ---------------------------------------------------------------------------
_NOW = datetime(2026, 7, 29, 14, 30)
_NOW = datetime(2026, 7, 29, 14, 30) # noqa: DTZ001 - naive, matching default_out_dir_name's naive datetime.now()
def _cfg_with(**dotted_overrides):
+1 -1
View File
@@ -90,7 +90,7 @@ def _collect_names(source: str, filename: str) -> set[str]:
names.add(node.attr)
elif isinstance(node, ast.Constant) and isinstance(node.value, str) and id(node) not in docstring_ids:
names.add(node.value)
elif isinstance(node, ast.arg):
elif isinstance(node, ast.arg): # noqa: SIM114 - kept separate so ty narrows node.arg to str, not str | None
names.add(node.arg)
elif isinstance(node, ast.keyword) and node.arg is not None:
names.add(node.arg)
+1 -1
View File
@@ -1,3 +1,4 @@
from test_pipeline import _make_synthetic_steps
from typer.testing import CliRunner
from giant import cli as giant_cli
@@ -5,7 +6,6 @@ from giant.config import Conditioning
from giant.data import setup_cache
from giant.tools import dwarf
from giant.tools.dwarf import app
from test_pipeline import _make_synthetic_steps
runner = CliRunner()
+2 -1
View File
@@ -1,9 +1,10 @@
import torch
from giant.config import ConditioningAxisConfig
from giant.constants import COND_DIM
from giant.model.network import Stage1Model
from giant.model.schedule import CosineSchedule, flow_matching_loss
from giant.sample import sample_flow, sample_ddim
from giant.sample import sample_ddim, sample_flow
PARTICLE_CFG = ConditioningAxisConfig(type="physical", emb_dim=8, n_layers=1)
MATERIAL_CFG = ConditioningAxisConfig(type="physical", emb_dim=8, n_layers=1)
+14 -13
View File
@@ -2,8 +2,9 @@ import copy
import pytest
import torch
from giant import config as gconfig
from giant.constants import CONT_SLOT_DIM, COND_DIM, PARTICLE_PHYS_DIM, SEC_SLOT_DIM
from giant.constants import COND_DIM, CONT_SLOT_DIM, PARTICLE_PHYS_DIM, SEC_SLOT_DIM
from giant.model.network import (
HISTORY_REGISTRY,
AttentionHistory,
@@ -1217,18 +1218,18 @@ def test_stage_classes_are_stagemodel_subclasses(cls):
@pytest.mark.parametrize("cls", [Stage1Model, Stage2OneShot, Stage2Autoregressive])
@pytest.mark.parametrize("generator", ["flow", "ddpm", "wgan"])
def test_stagemodel_time_emb_matches_objective_needs_time(cls, generator):
kwargs = dict(
pdg_vocab=5,
mat_vocab=3,
particle_cfg=PARTICLE_CFG,
material_cfg=MATERIAL_CFG,
hidden_dim=_STAGE_HIDDEN_DIM,
n_res_blocks=_STAGE_N_BLOCKS,
cond_out_dim=_STAGE_COND_OUT_DIM,
generator=generator,
time_dim=8,
noise_dim=8,
)
kwargs = {
"pdg_vocab": 5,
"mat_vocab": 3,
"particle_cfg": PARTICLE_CFG,
"material_cfg": MATERIAL_CFG,
"hidden_dim": _STAGE_HIDDEN_DIM,
"n_res_blocks": _STAGE_N_BLOCKS,
"cond_out_dim": _STAGE_COND_OUT_DIM,
"generator": generator,
"time_dim": 8,
"noise_dim": 8,
}
if cls is Stage1Model:
kwargs["n_sec_head_k_max"] = 15
else:
+3 -4
View File
@@ -20,7 +20,6 @@ from giant.model.schedule import (
)
from giant.sample import sample_secondaries
# ── helpers ──────────────────────────────────────────────────────────────────
@@ -341,7 +340,7 @@ def test_encode_secondaries_energy_conservation():
def test_encode_secondaries_stick_logits_match_naive_reference():
"""Cumsum-based remaining-budget computation must match a naive
per-row, per-slot Python reference (no cumsum) within float tolerance."""
from giant.data.transforms import encode_secondaries, _EPS, _STICK_LOGIT_CLIP
from giant.data.transforms import _EPS, _STICK_LOGIT_CLIP, encode_secondaries
rng = np.random.default_rng(11)
N = 25
@@ -569,7 +568,7 @@ def test_decode_secondaries_degenerate_row_falls_back_to_even_split():
e_sec = np.array([0.0, 4.0, 9.0, 30.0], dtype=np.float32)
pre_dir = np.tile([0.0, 0.0, 1.0], (N, 1)).astype(np.float32)
sec_E, _sec_dir, _mass, _charge, sec_valid = decode_secondaries(sec_cont, n_sec, e_sec, pre_dir)
sec_E, _sec_dir, _mass, _charge, _ = decode_secondaries(sec_cont, n_sec, e_sec, pre_dir)
for i, k in enumerate(n_sec):
if k == 0:
@@ -593,7 +592,7 @@ def test_decode_secondaries_rescale_preserves_relative_shares():
n_sec = np.array([4])
pre_dir = np.array([[0.0, 0.0, 1.0]], dtype=np.float32)
sec_E_small, _, _, _, sec_valid = decode_secondaries(sec_cont, n_sec, np.array([5.0], dtype=np.float32), pre_dir)
sec_E_small, _, _, _, _ = decode_secondaries(sec_cont, n_sec, np.array([5.0], dtype=np.float32), pre_dir)
sec_E_large, _, _, _, _ = decode_secondaries(sec_cont, n_sec, np.array([50.0], dtype=np.float32), pre_dir)
ratio_small = sec_E_small[0, :4] / sec_E_small[0, 0]
+2 -2
View File
@@ -9,8 +9,8 @@ import pytest
pytest.importorskip("plotstyle")
from giant.analysis import render as render_mod # noqa: E402
from giant.analysis.reduced import Reduced # noqa: E402
from giant.analysis import render as render_mod
from giant.analysis.reduced import Reduced
def _try_render(reduced: list[Reduced], out: Path):
+2 -2
View File
@@ -9,7 +9,7 @@ import pytest
import torch
from giant.config import ConditioningAxisConfig, ParticleTypeConfig
from giant.constants import TERM_ESCAPED, TERM_MAX_STEPS, TERM_UNKNOWN_PDG, K_MAX
from giant.constants import K_MAX, TERM_ESCAPED, TERM_MAX_STEPS, TERM_UNKNOWN_PDG
from giant.data.loader import TopNMap
from giant.data.transforms import Normalizer
from giant.model.network import (
@@ -21,7 +21,7 @@ from giant.model.network import (
from giant.rollout import L1DistCollector, make_seed_frontier, rollout
pytest.importorskip("sklearn")
from giant import geometry as g # noqa: E402
from giant import geometry as g
PDG_MAP = {22: 0, 11: 1, -11: 2}
MAT_MAP = {"G4_AIR": 0, "G4_PbWO4": 1}
+6 -8
View File
@@ -1,5 +1,7 @@
"""Tests for the mixture-of-experts routing prototype (giant/model/network.py)."""
import itertools
import pytest
import torch
@@ -7,6 +9,7 @@ from giant.config import ConditioningAxisConfig
from giant.constants import COND_DIM, K_MAX, SEC_DIM, X_DIM
from giant.model.network import (
BLOCK_REGISTRY,
ROUTER_REGISTRY,
TRUNK_REGISTRY,
AdaLNResBlock,
ComposedRouter,
@@ -17,7 +20,6 @@ from giant.model.network import (
NoneRouter,
PdgRouter,
ProcessRouter,
ROUTER_REGISTRY,
ResBlock,
RoutedTrunk,
Stage1Model,
@@ -397,7 +399,7 @@ def test_energy_router_own_width_controls_own_coverage_independent_of_others():
router.raw_width[0] = raw
shares.append(router.gate(cond_cont, cond_cat)[0, 0].item())
assert all(a <= b + 1e-6 for a, b in zip(shares, shares[1:]))
assert all(a <= b + 1e-6 for a, b in itertools.pairwise(shares))
def test_build_router_threads_learn_width_kwargs_through():
@@ -1010,9 +1012,7 @@ def test_build_models_routed_pair_composed_router_is_drop_in_for_sample_flow():
n_sec_pred = stage2.predict_n_sec(cond_cont, cond_cat, stage1_norm).argmax(dim=-1)
assert n_sec_pred.shape == (B,)
sec_cont, sec_type_emb, sec_valid = sample_secondaries(
stage2, cond_cont, cond_cat, stage1_norm, n_sec_pred, steps=2
)
sec_cont, _, sec_valid = sample_secondaries(stage2, cond_cont, cond_cat, stage1_norm, n_sec_pred, steps=2)
assert sec_cont.shape == (B, K_MAX, 4)
assert sec_valid.shape == (B, K_MAX)
@@ -1261,9 +1261,7 @@ def test_build_models_routed_pair_is_drop_in_for_sample_flow():
n_sec_pred = stage2.predict_n_sec(cond_cont, cond_cat, stage1_norm).argmax(dim=-1)
assert n_sec_pred.shape == (B,)
sec_cont, sec_type_emb, sec_valid = sample_secondaries(
stage2, cond_cont, cond_cat, stage1_norm, n_sec_pred, steps=2
)
sec_cont, _, sec_valid = sample_secondaries(stage2, cond_cont, cond_cat, stage1_norm, n_sec_pred, steps=2)
assert sec_cont.shape == (B, K_MAX, 4)
assert sec_valid.shape == (B, K_MAX)
+4 -4
View File
@@ -262,7 +262,7 @@ def test_sample_secondaries_ar_first_slot_has_no_history():
cond_cont, cond_cat = _cond(B)
stage1_out = torch.randn(B, X_DIM)
n_sec_pred = torch.tensor([0, 1, 1])
sec_cont, sec_type, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, n_sec_pred, steps=2)
sec_cont, _, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, n_sec_pred, steps=2)
assert sec_cont.shape == (B, 1, CONT_SLOT_DIM)
assert sec_valid.tolist() == [[False], [True], [True]]
@@ -281,7 +281,7 @@ def test_sample_secondaries_ar_stop_token_forced_stop_gives_zero_secondaries(n_s
_force_stop_head_logit(decoder, 50.0)
cond_cont, cond_cat = _cond(B)
stage1_out = torch.randn(B, X_DIM)
sec_cont, sec_type, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, None, steps=2)
_, _, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, None, steps=2)
assert sec_valid.shape == (B, k_max)
assert not sec_valid.any()
@@ -296,7 +296,7 @@ def test_sample_secondaries_ar_stop_token_forced_never_stop_runs_to_k_max(n_sec_
_force_stop_head_logit(decoder, -50.0)
cond_cont, cond_cat = _cond(B)
stage1_out = torch.randn(B, X_DIM)
sec_cont, sec_type, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, None, steps=2)
_, _, sec_valid = sample_secondaries_ar(decoder, cond_cont, cond_cat, stage1_out, None, steps=2)
assert sec_valid.all()
@@ -412,7 +412,7 @@ def test_sample_secondaries_ar_full_length_ignores_n_sec_pred_zero_rows():
cond_cont, cond_cat = _cond(B)
stage1_out = torch.randn(B, X_DIM)
n_sec_pred = torch.tensor([0, 0, 0])
sec_cont, sec_type, sec_valid = sample_secondaries_ar(
sec_cont, _, sec_valid = sample_secondaries_ar(
decoder, cond_cont, cond_cat, stage1_out, n_sec_pred, steps=2, full_length=True
)
assert not sec_valid.any()
+14 -15
View File
@@ -12,6 +12,7 @@ import pytest
import torch
import torch.nn.functional as F
from giant.checkpoint_io import load_for_inference
from giant.config import ParticleTypeConfig
from giant.constants import (
COND_DIM,
@@ -21,7 +22,6 @@ from giant.constants import (
SEC_SLOT_DIM,
X_DIM,
)
from giant.checkpoint_io import load_for_inference
from giant.data.dataset import StepBatch
from giant.data.transforms import Normalizer
from giant.model.network import Stage2Autoregressive, build_critics, build_models
@@ -36,7 +36,6 @@ from giant.training import (
train,
)
from giant.training.metrics import _wandb_run_config
from giant.training.trainers import _type_class_weight_vector
from giant.training.stage2_inputs import (
_ar_has_prev,
_assemble_stage2_ar_inputs,
@@ -51,6 +50,7 @@ from giant.training.stage2_inputs import (
_stop_target_and_mask,
_type_repr,
)
from giant.training.trainers import _type_class_weight_vector
PDG_VOCAB = 6
MAT_VOCAB = 3
@@ -543,19 +543,18 @@ def test_train_raises_when_no_active_stage():
model_config = _model_config(cfg)
models = build_models(model_config)
critics = build_critics(model_config)
with tempfile.TemporaryDirectory() as tmp:
with pytest.raises(ValueError, match="no active stage"):
train(
cfg=cfg,
models=models,
critics=critics,
train_loader=_fake_batches(1, 8),
val_loader=_fake_batches(1, 8),
device=torch.device("cpu"),
out_dir=Path(tmp) / "run",
model_config=model_config,
total_train_batches=1,
)
with tempfile.TemporaryDirectory() as tmp, pytest.raises(ValueError, match="no active stage"):
train(
cfg=cfg,
models=models,
critics=critics,
train_loader=_fake_batches(1, 8),
val_loader=_fake_batches(1, 8),
device=torch.device("cpu"),
out_dir=Path(tmp) / "run",
model_config=model_config,
total_train_batches=1,
)
def test_metrics_csv_columns_are_stage_prefixed():
+2 -2
View File
@@ -11,8 +11,8 @@ import pytest
pytest.importorskip("plotstyle")
from giant.training import plots as plots_mod # noqa: E402
from giant.training.plots import MetricsTable, derive_metrics_dir, render_metrics # noqa: E402
from giant.training import plots as plots_mod
from giant.training.plots import MetricsTable, derive_metrics_dir, render_metrics
# --- fixtures ----------------------------------------------------------
+4 -3
View File
@@ -2,9 +2,13 @@ import warnings
import numpy as np
import pytest
from giant.cond_layout import AXIS_TYPES, CondLayout
from giant.constants import COND_DIM, COND_DIM_BASE, K_MAX
from giant.data.transforms import (
Normalizer,
_vectorized_map_lookup,
_WelfordAccumulator,
build_cond_features,
build_features,
encode_secondaries,
@@ -14,12 +18,9 @@ from giant.data.transforms import (
inv_log_transform,
local_frame_rotation,
log_transform,
Normalizer,
reconstruct_post_pos,
sorted_membership,
travel_direction,
_vectorized_map_lookup,
_WelfordAccumulator,
)