[AAASM-1696] 🐛 (agent_assembly): Lazy-load top-level exports so runtime probe works without httpx#51
Merged
Conversation
`agent_assembly/__init__.py` previously imported the full SDK surface eagerly: `from agent_assembly.core import …` → `agent_assembly.client.gateway` → `import httpx`. That defeated `agent_assembly/runtime`'s design intent of being stdlib-only and broke aa-integration-tests::e2e_sdk_runtime_lifecycle::python_binary_in_path_returns_resolved_path with `ModuleNotFoundError: No module named 'httpx'` whenever the SDK was used via PYTHONPATH without installing third-party deps (agent-assembly CI run 26211782822). Convert the package to lazy attribute resolution using PEP 562's `__getattr__` so accessing `agent_assembly.init_assembly` still works, but `from agent_assembly.runtime import …` no longer drags httpx/pydantic into sys.modules. `__all__` and `__version__` remain static; the optional native `_core` exports are still gated on availability (now via sys.modules + importlib.util.find_spec to preserve the existing test_init_exports.py behaviour). TYPE_CHECKING re-exports keep mypy and IDE completion identical to before.
Spawns a child interpreter with a sys.meta_path finder that raises ModuleNotFoundError for `httpx` and `pydantic`, then asserts: * `from agent_assembly.runtime import find_aasm_binary, init_assembly, is_running` succeeds in that environment. * `import agent_assembly` resolves to the package without dragging in the gateway client's third-party deps. * Eager attribute access (`agent_assembly.init_assembly`, etc.) still resolves through the PEP 562 `__getattr__` loader. * Unknown attributes raise AttributeError with the offending name. Guards against the eager-import regression that broke agent-assembly CI run 26211782822.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
`ruff format` flagged the single-line failure-message assert as non-canonical when run across the whole tree (vs. per-file). Switch to the trailing-tuple form to match the rest of the file. No behavioural change.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
agent_assembly/__init__.pyto PEP 562__getattr__lazy attribute resolution sofrom agent_assembly.runtime import …no longer dragshttpx/pydanticintosys.modules.httpxandpydanticfrom import and verifies bothagent_assembly.runtimeand the top-levelagent_assemblypackage import cleanly.Closes AAASM-1696.
Why
agent_assembly/runtime.pywas designed to be stdlib-only (its docstring is explicit: "intentionally NOT re-exported fromagent_assemblyat the top level"), so it could be reached viaPYTHONPATH=…/python-sdkwithout installing the SDK's third-party deps.That intent was undone by the eager imports in
__init__.py. Resolvingfrom agent_assembly.runtime import find_aasm_binaryfirst executesagent_assembly/__init__.py, which chained through:In agent-assembly's
aa-integration-testsCI,python3is set up byactions/setup-python@v6but the SDK's runtime deps (httpx,pydantic,typing-extensions) are never installed — onlyPYTHON_SDK_PATHis set. After theposix_spawnpfix in agent-assembly commit39f53be0unblocked the probe, the next layer of the bug surfaced asModuleNotFoundError: No module named 'httpx'in run 26211782822 (bothubuntu-latestandmacos-latest).How the fix works
_LAZY_EXPORTSmaps each public name to the submodule that owns it.__getattr__(name)(PEP 562) imports the owning submodule on first access and caches the attribute back intoglobals()so subsequent accesses are O(1).__all__is built statically from_ALWAYS_EXPORTED, plus the optional native_coreexports (RuntimeClient,GovernanceEvent,PolicyResult,PolicyTimeoutError) when the extension is available. Availability is probed viasys.modulesfirst thenimportlib.util.find_spec, preserving the semantics of the existingtest_init_exports.pyfixture which pre-populatessys.moduleswith a fake_core.TYPE_CHECKINGblock re-imports the same names statically so mypy / IDE completion are unchanged.Test plan
pytest test/unit/test_runtime_import_isolation.py— 4 new regression tests pass.pytest test/— 377 passed, 11 pre-existing skips (native_core, optional adapter deps).ruff check agent_assembly/__init__.py test/unit/test_runtime_import_isolation.py— clean.ruff format --check— clean.mypy agent_assembly— no new errors introduced (verified against pristine worktree: 58 → 58).aa-integration-tests::e2e_sdk_runtime_lifecycle::python_binary_in_path_returns_resolved_pathshould pass on Linux + macOS.Out of scope
The pre-existing mypy noise on master (proto
.pyi/.pyduplicates,gateway.pygenericdictwarnings, …) is untouched.🤖 Generated with Claude Code