539b6f61e1
CI / Lint (ruff check) (push) Successful in 28s
CI / Format (ruff format) (push) Successful in 28s
CI / Sync project version with tag (push) Has been skipped
CI / Lint (ruff check) (pull_request) Successful in 40s
CI / Type check (ty) (push) Successful in 43s
CI / Format (ruff format) (pull_request) Successful in 39s
CI / Sync project version with tag (pull_request) Has been skipped
CI / Type check (ty) (pull_request) Successful in 41s
CI / Tests (push) Successful in 1m26s
CI / Tests (pull_request) Successful in 1m18s
Covers the default-config 0-sentinel inheritance path (the exact bug
fixed by 969c5c6, previously untested since every router test in
test_router.py passes expert_hidden_dim/expert_n_blocks explicitly),
plus missing-key inheritance, full override, and partial override.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
from giant import config as gconfig
|
|
|
|
|
|
def _write_config(path, git_hash):
|
|
path.write_text(
|
|
f"""
|
|
[train]
|
|
epochs = 5
|
|
|
|
[model]
|
|
hidden_dim = 64
|
|
|
|
[meta]
|
|
git_hash = "{git_hash}"
|
|
"""
|
|
)
|
|
|
|
|
|
def test_merge_cli_overrides_applies_file_then_cli(tmp_path, monkeypatch):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "abc123")
|
|
path = tmp_path / "config.toml"
|
|
_write_config(path, "abc123")
|
|
|
|
cfg = gconfig.merge_cli_overrides(
|
|
gconfig.DEFAULT_CONFIG,
|
|
path,
|
|
train_overrides={},
|
|
model_overrides={"hidden_dim": 128},
|
|
)
|
|
assert cfg["train"]["epochs"] == 5 # from file
|
|
assert cfg["model"]["hidden_dim"] == 128 # CLI override wins over file
|
|
|
|
|
|
def test_merge_cli_overrides_warns_on_git_hash_mismatch(tmp_path, monkeypatch, capsys):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "current999")
|
|
path = tmp_path / "config.toml"
|
|
_write_config(path, "old111")
|
|
|
|
cfg = gconfig.merge_cli_overrides(gconfig.DEFAULT_CONFIG, path, {}, {})
|
|
|
|
assert cfg["train"]["epochs"] == 5 # does not fail, config still applied
|
|
captured = capsys.readouterr()
|
|
assert "warning" in captured.err
|
|
assert "old111" in captured.err
|
|
assert "current999" in captured.err
|
|
|
|
|
|
def test_merge_cli_overrides_no_warning_on_matching_git_hash(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "same123")
|
|
path = tmp_path / "config.toml"
|
|
_write_config(path, "same123")
|
|
|
|
gconfig.merge_cli_overrides(gconfig.DEFAULT_CONFIG, path, {}, {})
|
|
assert capsys.readouterr().err == ""
|
|
|
|
|
|
def test_merge_cli_overrides_no_warning_when_git_hash_unknown(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "unknown")
|
|
path = tmp_path / "config.toml"
|
|
_write_config(path, "abc123")
|
|
|
|
gconfig.merge_cli_overrides(gconfig.DEFAULT_CONFIG, path, {}, {})
|
|
assert capsys.readouterr().err == ""
|
|
|
|
|
|
def test_merge_cli_overrides_no_warning_when_meta_section_absent(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "current999")
|
|
path = tmp_path / "config.toml"
|
|
path.write_text("[train]\nepochs = 5\n")
|
|
|
|
gconfig.merge_cli_overrides(gconfig.DEFAULT_CONFIG, path, {}, {})
|
|
assert capsys.readouterr().err == ""
|
|
|
|
|
|
def test_warn_if_checkpoint_config_mismatch_finds_sibling_toml(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "current999")
|
|
ckpt_path = tmp_path / "best.pt"
|
|
ckpt_path.write_bytes(b"") # contents irrelevant, only its directory is used
|
|
_write_config(tmp_path / "config.toml", "old111")
|
|
|
|
gconfig.warn_if_checkpoint_config_mismatch(ckpt_path)
|
|
|
|
captured = capsys.readouterr()
|
|
assert "warning" in captured.err
|
|
assert "old111" in captured.err
|
|
assert "current999" in captured.err
|
|
|
|
|
|
def test_warn_if_checkpoint_config_mismatch_no_warning_when_toml_absent(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "current999")
|
|
ckpt_path = tmp_path / "best.pt"
|
|
ckpt_path.write_bytes(b"")
|
|
|
|
gconfig.warn_if_checkpoint_config_mismatch(ckpt_path)
|
|
assert capsys.readouterr().err == ""
|
|
|
|
|
|
def test_warn_if_checkpoint_config_mismatch_no_warning_when_hashes_match(
|
|
tmp_path, monkeypatch, capsys
|
|
):
|
|
monkeypatch.setattr(gconfig, "git_hash", lambda: "same123")
|
|
ckpt_path = tmp_path / "best.pt"
|
|
ckpt_path.write_bytes(b"")
|
|
_write_config(tmp_path / "config.toml", "same123")
|
|
|
|
gconfig.warn_if_checkpoint_config_mismatch(ckpt_path)
|
|
assert capsys.readouterr().err == ""
|
|
|
|
|
|
def test_resolve_expert_dims_default_config_inherits_hidden_dim_and_n_blocks():
|
|
# The unset sentinel (expert_hidden_dim/n_blocks == 0 in DEFAULT_CONFIG)
|
|
# is exactly the bug fixed by resolve_expert_dims: it must not silently
|
|
# fall back to some other hardcoded default, only to the monolith's own
|
|
# hidden_dim/n_blocks, so --hidden-dim/--n-blocks reach the experts too.
|
|
router_cfg = dict(gconfig.DEFAULT_CONFIG["model"]["router"])
|
|
assert router_cfg["expert_hidden_dim"] == 0
|
|
assert router_cfg["expert_n_blocks"] == 0
|
|
|
|
hidden_dim, n_blocks = gconfig.resolve_expert_dims(router_cfg, 512, 6)
|
|
assert (hidden_dim, n_blocks) == (512, 6)
|
|
|
|
|
|
def test_resolve_expert_dims_missing_keys_also_inherit():
|
|
hidden_dim, n_blocks = gconfig.resolve_expert_dims({}, 512, 6)
|
|
assert (hidden_dim, n_blocks) == (512, 6)
|
|
|
|
|
|
def test_resolve_expert_dims_explicit_override_wins():
|
|
router_cfg = {"expert_hidden_dim": 128, "expert_n_blocks": 3}
|
|
hidden_dim, n_blocks = gconfig.resolve_expert_dims(router_cfg, 512, 6)
|
|
assert (hidden_dim, n_blocks) == (128, 3)
|
|
|
|
|
|
def test_resolve_expert_dims_partial_override_mixes_explicit_and_inherited():
|
|
router_cfg = {"expert_hidden_dim": 128, "expert_n_blocks": 0}
|
|
hidden_dim, n_blocks = gconfig.resolve_expert_dims(router_cfg, 512, 6)
|
|
assert (hidden_dim, n_blocks) == (128, 6) # n_blocks inherited, hidden_dim not
|