Extend type checking
How to use register_type_namespace to make forward references from downstream packages resolvable at composition time, enabling third-party types in app pipelines.
The problem
When you compose apps with +, scinexus checks that the output type of the left app is compatible with the input type of the right app. Type hints are often written as forward references — strings like "Alignment" or "PhyloNode" — to avoid circular imports. At composition time scinexus must resolve these strings to actual classes, but it only knows about its own types by default. If your package defines custom types used in app hints, scinexus cannot resolve them without help.
The solution
register_type_namespace lets a downstream package register a lazy namespace provider — a zero-argument callable that returns a dict[str, type]. When scinexus encounters an unresolved forward reference, it queries each registered provider in order until it finds a match.
from scinexus.typing import register_type_namespace
register_type_namespace(my_provider)
The provider is called lazily each time a name needs resolving, so the package can defer heavy imports. Providers are responsible for their own caching. Registration is idempotent: re-registering the same callable is a no-op.
How cogent3 does it
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
cogent3defines many types (Alignment,PhyloNode,Table, etc.) that are used as forward references in app type hints.- In
cogent3/app/typing.py, a resolution namespace is built lazily and registered withscinexus - With this registration, any
scinexusapp that uses"PhyloNode"as a type hint will resolve correctly at composition time without the user importingPhyloNodeexplicitly.
Registering your own package's types
Follow the same pattern: define a lazy provider function that imports and caches your types, then register it at module level.
from scinexus.typing import register_type_namespace
_ns = None
def _get_my_types():
global _ns
if _ns is not None:
return _ns
from my_package.core import MyDataType, MyResultType
_ns = {
"MyDataType": MyDataType,
"MyResultType": MyResultType,
}
return _ns
register_type_namespace(_get_my_types)
Place this in a module that is imported early (e.g. your package's typing.py or __init__.py). Once registered, apps using "MyDataType" as a forward reference will resolve correctly when composed with other apps.