Skip to content

Commit d56d088

Browse files
test(types): pin back-compat shim contract for agentex.lib.types.{acp,json_rpc}
Codifies the invariants Greptile flagged in PR review (and that the previous commit fixed): 1. Every symbol the original modules exported must be importable from the shim path — including the two module-level constants (RPC_SYNC_METHODS, PARAMS_MODEL_BY_METHOD) that an earlier shim iteration dropped. 2. The shim re-exports must be the *same* class objects as the canonical path (identity check, not just type equality). Different objects would silently break isinstance/match-case for any consumer that mixes import styles. 3. The pydantic ConfigDict (from_attributes=True, populate_by_name=True) that JSONRPCRequest/Response/Error inherited from model_utils.BaseModel before the refactor stays preserved on the canonical agentex.protocol.json_rpc classes. Verified locally: - All 5 tests pass against the current shim. - Simulated regression (removing RPC_SYNC_METHODS from the shim re-exports): 2 tests fail with the exact ImportError + AttributeError a downstream consumer would hit. Catches the contract violation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 348f608 commit d56d088

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

tests/test_protocol_shims.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Tests that pin the back-compat contract for protocol-type shims.
2+
3+
The canonical location for wire-protocol shapes is :mod:`agentex.protocol`
4+
(see PR scaleapi/scale-agentex-python#371). The historical locations
5+
:mod:`agentex.lib.types.acp` and :mod:`agentex.lib.types.json_rpc` are
6+
preserved as re-export shims so external consumers' existing imports
7+
continue to work.
8+
9+
These tests enforce two invariants:
10+
11+
1. **Symbol parity** — every public name the original modules exported
12+
is still importable from the old path. Greptile flagged
13+
``RPC_SYNC_METHODS`` and ``PARAMS_MODEL_BY_METHOD`` as missing in an
14+
earlier pass; this test prevents that regression.
15+
2. **Identity** — the class objects at the shim path are the *same*
16+
objects as the canonical path. Without this, type-narrowing via
17+
``isinstance`` or pattern matching would silently misbehave for code
18+
that mixes import styles.
19+
20+
Also asserts the :class:`pydantic.ConfigDict` settings on the JSON-RPC
21+
classes survived the move from :mod:`agentex.lib.utils.model_utils` to
22+
plain :mod:`pydantic` — Greptile flagged the silent loss of
23+
``from_attributes=True`` / ``populate_by_name=True``.
24+
"""
25+
26+
from __future__ import annotations
27+
28+
29+
def test_acp_shim_re_exports_all_original_symbols() -> None:
30+
"""Every name historically exported from agentex.lib.types.acp must
31+
still be importable from that path via the back-compat shim."""
32+
# Importing each symbol; ImportError here means the shim regressed.
33+
from agentex.lib.types.acp import ( # noqa: F401
34+
PARAMS_MODEL_BY_METHOD,
35+
RPC_SYNC_METHODS,
36+
CancelTaskParams,
37+
CreateTaskParams,
38+
RPCMethod,
39+
SendEventParams,
40+
SendMessageParams,
41+
)
42+
43+
44+
def test_json_rpc_shim_re_exports_all_original_symbols() -> None:
45+
"""Every name historically exported from agentex.lib.types.json_rpc
46+
must still be importable from that path via the back-compat shim."""
47+
from agentex.lib.types.json_rpc import ( # noqa: F401
48+
JSONRPCError,
49+
JSONRPCRequest,
50+
JSONRPCResponse,
51+
)
52+
53+
54+
def test_acp_shim_classes_are_identical_to_canonical() -> None:
55+
"""Shim re-exports must be the *same* class objects as the canonical
56+
path. Different objects would break ``isinstance`` for code that
57+
mixes import styles."""
58+
from agentex.lib.types import acp as shim
59+
from agentex.protocol import acp as canon
60+
61+
assert shim.RPCMethod is canon.RPCMethod
62+
assert shim.CreateTaskParams is canon.CreateTaskParams
63+
assert shim.SendMessageParams is canon.SendMessageParams
64+
assert shim.SendEventParams is canon.SendEventParams
65+
assert shim.CancelTaskParams is canon.CancelTaskParams
66+
assert shim.RPC_SYNC_METHODS is canon.RPC_SYNC_METHODS
67+
assert shim.PARAMS_MODEL_BY_METHOD is canon.PARAMS_MODEL_BY_METHOD
68+
69+
70+
def test_json_rpc_shim_classes_are_identical_to_canonical() -> None:
71+
"""Same identity check for the JSON-RPC envelope types."""
72+
from agentex.lib.types import json_rpc as shim
73+
from agentex.protocol import json_rpc as canon
74+
75+
assert shim.JSONRPCError is canon.JSONRPCError
76+
assert shim.JSONRPCRequest is canon.JSONRPCRequest
77+
assert shim.JSONRPCResponse is canon.JSONRPCResponse
78+
79+
80+
def test_json_rpc_classes_preserve_legacy_model_config() -> None:
81+
"""Pre-refactor, JSON-RPC classes inherited
82+
``from_attributes=True`` / ``populate_by_name=True`` from
83+
``agentex.lib.utils.model_utils.BaseModel``. The refactor swapped
84+
to plain ``pydantic.BaseModel`` and set ``model_config`` explicitly
85+
to preserve both flags. Catch any future drop."""
86+
from agentex.protocol.json_rpc import (
87+
JSONRPCError,
88+
JSONRPCRequest,
89+
JSONRPCResponse,
90+
)
91+
92+
for cls in (JSONRPCError, JSONRPCRequest, JSONRPCResponse):
93+
assert cls.model_config.get("from_attributes") is True, (
94+
f"{cls.__name__}.model_config dropped from_attributes=True"
95+
)
96+
assert cls.model_config.get("populate_by_name") is True, (
97+
f"{cls.__name__}.model_config dropped populate_by_name=True"
98+
)

0 commit comments

Comments
 (0)