diff --git a/tests/test_lazy_imports.py b/tests/test_lazy_imports.py index cdafe6a8..ac4224d1 100644 --- a/tests/test_lazy_imports.py +++ b/tests/test_lazy_imports.py @@ -2,6 +2,9 @@ Regression tests for the cold package import surface. ''' +import json +import subprocess +import sys from typing import ( Any, get_type_hints, @@ -17,6 +20,54 @@ from tractor.ipc import ( ) +def run_cold_import(code: str) -> dict[str, object]: + result = subprocess.run( + [ + sys.executable, + '-c', + code, + ], + check=True, + capture_output=True, + text=True, + ) + return json.loads(result.stdout) + + +def test_lazy_to_asyncio_package_api(): + ''' + Keep the public lazy submodule discoverable without eagerly + importing it. + + Before the lazy conversion, package import side effects exposed + `to_asyncio` to `dir()` and wildcard imports. Exercise those APIs + in cold interpreters so this test proves normal `import tractor` + leaves `asyncio` unloaded, while discovery and wildcard access + still advertise and resolve the public submodule. + + ''' + cold = run_cold_import( + 'import json, sys, tractor; ' + 'print(json.dumps({' + '"advertised": "to_asyncio" in dir(tractor), ' + '"asyncio_loaded": "asyncio" in sys.modules}))' + ) + assert cold == { + 'advertised': True, + 'asyncio_loaded': False, + } + + wildcard = run_cold_import( + 'import json; ' + 'from tractor import *; ' + 'print(json.dumps({' + '"module": to_asyncio.__name__}))' + ) + assert wildcard == { + 'module': 'tractor.to_asyncio', + } + + def test_lazy_annotation_names_resolve(): ''' Resolve annotations without importing optional dependencies. diff --git a/tractor/__init__.py b/tractor/__init__.py index 42df61e8..13689c06 100644 --- a/tractor/__init__.py +++ b/tractor/__init__.py @@ -76,6 +76,19 @@ from .discovery._registry import ( # from . import hilevel as hilevel +__all__: tuple[str, ...] = tuple( + name + for name in globals() + if not name.startswith('_') +) + ( + 'to_asyncio', +) + + +def __dir__() -> list[str]: + return sorted(set(globals()) | set(__all__)) + + def __getattr__(name: str): ''' PEP 562 lazy sub-module loading, presently only for