Python · 3944 bytes Raw Blame History
1 """Integration test: dlm public surface compatibility (F06).
2
3 Asserts the contract sway's resolver depends on against a real
4 installed ``dlm`` — every entry in dlm's built-in base-model registry
5 must ``resolve()`` to an object carrying an ``hf_id`` attribute. Catches
6 the ``.hf_id`` → ``.repo_id`` rename (or any equivalent) before a user
7 hits it via ``sway autogen``.
8
9 Runs under ``slow + online + dlm-extra``. Skipped cleanly when the
10 ``dlm`` extra isn't installed (so `pytest tests/integration` on a
11 no-extras runner still works).
12 """
13
14 from __future__ import annotations
15
16 import pytest
17
18 pytestmark = [pytest.mark.slow, pytest.mark.online]
19
20
21 dlm_base_models = pytest.importorskip(
22 "dlm.base_models",
23 reason="dlm extra not installed (pip install 'dlm-sway[dlm]')",
24 )
25
26
27 def _iter_registry_keys() -> list[str]:
28 """Return every registry key dlm exposes.
29
30 dlm's API surface for enumerating the registry has moved around
31 (``list_bases``, ``registry.keys()``, ``iter_registered``). Try
32 the known shapes; if none work, yield the canonical keys hard-coded
33 in the sway CLAUDE.md so the test still runs against a stable
34 floor. Failure mode: zero keys → test is asserting nothing → fail
35 loudly in ``test_registry_nonempty``.
36 """
37 for accessor in ("list_bases", "registered_bases", "list_registered"):
38 fn = getattr(dlm_base_models, accessor, None)
39 if callable(fn):
40 return list(fn())
41 registry = getattr(dlm_base_models, "REGISTRY", None) or getattr(
42 dlm_base_models, "registry", None
43 )
44 if registry is not None and hasattr(registry, "keys"):
45 return list(registry.keys())
46 # Floor: keys the sway CLAUDE.md documents as shipped by dlm.
47 return [
48 "qwen2.5-0.5b",
49 "qwen2.5-1.5b",
50 "qwen2.5-3b",
51 "qwen2.5-coder-1.5b",
52 "llama-3.2-1b",
53 "llama-3.2-3b",
54 "smollm2-135m",
55 "smollm2-360m",
56 "smollm2-1.7b",
57 "phi-3.5-mini",
58 ]
59
60
61 def test_registry_nonempty() -> None:
62 """At least one registry key exists — tests below are trivial
63 otherwise."""
64 keys = _iter_registry_keys()
65 assert keys, "dlm base-model registry appears empty; accessor changed?"
66
67
68 @pytest.mark.parametrize("key", _iter_registry_keys())
69 def test_base_resolves_with_hf_id(key: str) -> None:
70 """Every registry entry must resolve to an object with ``hf_id``.
71
72 sway's resolver (``integrations/dlm/resolver.py``) calls
73 ``dlm.base_models.resolve(key).hf_id``. A rename of that attribute
74 would break every autogen run; this test catches the drift at
75 sway's CI.
76 """
77 spec = dlm_base_models.resolve(key)
78 assert hasattr(spec, "hf_id"), (
79 f"dlm.base_models.resolve({key!r}) returned {type(spec).__name__} "
80 f"without .hf_id — public-surface drift. Visible attrs: "
81 f"{sorted(a for a in dir(spec) if not a.startswith('_'))[:8]!r}"
82 )
83 assert isinstance(spec.hf_id, str), (
84 f"dlm.base_models.resolve({key!r}).hf_id = {spec.hf_id!r} — expected a string."
85 )
86 assert "/" in spec.hf_id, (
87 f"dlm.base_models.resolve({key!r}).hf_id = {spec.hf_id!r} — "
88 "not a plausible HuggingFace 'org/name' id."
89 )
90
91
92 def test_sway_resolver_does_not_wrap_valid_response(monkeypatch: pytest.MonkeyPatch) -> None:
93 """A well-formed dlm spec passes through sway's resolver without
94 raising — guards against an accidentally over-strict hasattr check.
95 """
96 from dlm_sway.integrations.dlm.resolver import _resolve_base_model_to_hf_id
97
98 # Pick any key; use the smallest to keep the test fast.
99 keys = _iter_registry_keys()
100 # Prefer SmolLM 135M — it's the smallest known base and is the
101 # integration fixture sway already uses.
102 key = next((k for k in keys if "135m" in k), keys[0])
103
104 hf_id = _resolve_base_model_to_hf_id(key)
105 assert "/" in hf_id, f"{key!r}{hf_id!r} (expected 'org/name')"