!!! abstract “”
Why types are checked at composition time rather than call time, how `check_type_compatibility` works, handling of Union types and forward references, the role of `register_type_namespace`, and the relationship to `typeguard` for runtime checking.
There are rules around app composition, starting with app types. Loaders and writers are special cases. If included, a loader must always be first, e.g.
python { notest } app = a_loader + a_generic
If included, a writer must always be last, e.g.
python { notest } app = a_generic + a_writer
Changing the order for either of the above will result in a
TypeError.
The next constraint on app composition are the input and output types
of the apps involved. Specifically, apps define the type of input they
work on and the type of output they produce. For two apps to be
composed, the output (or return) type of app on the left
(e.g. a_loader) must overlap with the input type of the app
on the right (e.g. a_generic). If they don’t match, a
TypeError is raised.
SciNexus defines two type-level constructs used across the framework:
SerialisableType – a Protocol that any
object with a to_rich_dict() method satisfies. Database
writer apps rely on this to serialise results before storing them in a
data store.IdentifierType – a type alias
(str | Path | DataMemberABC) representing the accepted ways
to identify a member of a data store. Loader apps accept this as
input.See the API reference for details.
In addition to checking type compatibility when apps are composed,
scinexus validates input data at runtime before each call to
main(). This uses typeguard.check_type to
verify that the data matches the app’s declared input type. On a
mismatch, a NotCompleted is returned with a message naming
the received and expected types.
!!! important “Why this matters”
Without runtime type checking, passing the wrong data type to an app still fails — but the error occurs inside the users `main()` and can be confusing. For example, a message like `'NoneType' object has no attribute 'blah'` gives little indication that the real problem is a type mismatch from an upstream app. With runtime checking enabled, scinexus catches this before entering `main()` and reports the mismatch clearly.
check_data_typeRuntime type checking is enabled by default. For mature pipelines
where type correctness has been established, you can disable it to
remove the small overhead of the typeguard check:
python { notest } app = read_json() + validate(required_field="name") app.check_data_type = False
Setting check_data_type on the outermost app propagates
the setting to all apps in the pipeline.