Registered Operators
Python does not manufacture a parallel operator hierarchy. It discovers C++
operator registrations already loaded into the process and presents each one
as an immutable OperatorType proxy with reflected ports, parameters, and
documentation.
Prefer importable proxies in application code. Fully qualified registry-name lookup remains available for data-driven graph builders and diagnostics.
- How to import and inspect operator proxies
- How proxies differ from graph-owned operator handles
- When to use a fully qualified registry name
- How provider imports and generated stubs affect discovery
Import a proxy
CounterSource is a callable registry proxy, not an instance of the C++
operator. Calling it uses its stable registry identity to author the
graph-owned operator declaration and validates keyword arguments against the
registered parameter schema.
custom_holoscan is an illustrative independently installed provider package.
Import the package that ships your operators; Core does not copy provider
classes into holoscan.operators.
The returned source is an OperatorHandle. It exposes the ports of that
specific graph instance:
Operator and port handles are weak. They do not keep their Graph alive; a
later use after graph retirement fails with a stable authoring error.
Inspect the registry
hs.registry is the process-local registration discovery module:
The registry iteration order is stable and lexical. Reflected parameter records include type spelling, description, units, optionality, nested status, ranges, named choices, and sensitivity metadata. Sensitive values are never rendered by operator-handle representations.
Use names only for dynamic composition
Both forms below identify the same registered operator type:
Use the imported proxy for ordinary source code: editors can complete the
operator name, help() is useful, and a misspelling fails at import or
attribute access. Use the fully qualified string when the operator identity
comes from an external graph description.
holoscan.operators owns Core’s generic OperatorHandle; it never publishes
provider leaf names. This prevents two providers with the same class name from
changing one another’s Python API. Look up dynamic types by fully qualified
registry identity.
Import the provider first
The registry is process-local. Core types are available after import holoscan; separately shipped operator modules register their rows when their
provider package is imported. A distribution can advertise a lazy public alias
through the holoscan.modules entry-point group:
An unknown-name error suggests close registered matches and reminds you to
import the provider. Core indexes entry-point metadata but does not import
provider Python packages or native libraries until their alias is requested.
SDK registrations use holoscan.*; downstream providers allocate names under
holoscan.<provider>.*, choosing a provider name that does not collide with SDK
areas or other providers. NVIDIA modules follow the same convention whether
shipped in or outside the SDK repository.
Typing and generated documentation
Each provider package ships its generated proxy definitions and a py.typed
marker. Each proxy has a generated Params TypedDict and a generated
Handle type. The callable signature expands that parameter dictionary, so
editors and type checkers know the exact keyword names and value types, while
the handle exposes only the operator’s declared ports. For example,
CounterSource.Params contains limit: int, and the return type exposes
out.
Those precise nested types are PEP 561 views: at runtime Handle is the erased
OperatorHandle class and Params is dict. Use the generated views for
static analysis and editor completion, not for isinstance() checks or
typing.get_type_hints() introspection.
Fern’s generated Python reference turns those same parameter records into the parameter table on each proxy page. Scalar, sequence, optional, named-enum, nested-aggregate, and duration annotations therefore come from the same schema metadata that drives runtime validation rather than from a second handwritten description.
Recap
- Calling an
OperatorTypeproxy authors one graph-owned instance and returns its precisely typed weak handle. - Prefer importable proxies in application source and fully qualified strings
through
graph.op()for data-driven composition. - Core discovers provider metadata lazily; importing an operator package or
requesting its
holoscan.<module>alias populates the process-local registry. - Registry metadata drives validation, help text, and generated typing stubs.