holoscan 2.9.0__cp310-cp310-manylinux_2_35_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- holoscan-2.9.0.data/purelib/holoscan/__init__.py +133 -0
- holoscan-2.9.0.data/purelib/holoscan/cli/__main__.py +26 -0
- holoscan-2.9.0.data/purelib/holoscan/conditions/__init__.py +69 -0
- holoscan-2.9.0.data/purelib/holoscan/conditions/_conditions.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/core/__init__.py +574 -0
- holoscan-2.9.0.data/purelib/holoscan/core/_core.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/decorator.py +594 -0
- holoscan-2.9.0.data/purelib/holoscan/executors/__init__.py +26 -0
- holoscan-2.9.0.data/purelib/holoscan/executors/_executors.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/graphs/__init__.py +32 -0
- holoscan-2.9.0.data/purelib/holoscan/graphs/_graphs.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/gxf/__init__.py +60 -0
- holoscan-2.9.0.data/purelib/holoscan/gxf/_gxf.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper_lib.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan_lib.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_app.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_core.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_cuda.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_logger.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_multimedia.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_rmm.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_sample.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_serialization.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_std.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libgxf_ucx.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_core.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_infer.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_infer_onnx_runtime.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_infer_torch.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_infer_utils.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_logger.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_aja.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_rx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_tx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_bayer_demosaic.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_format_converter.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_gxf_codelet.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_holoviz.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_inference.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_inference_processor.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_ping_rx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_rx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_tx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_ping_tx.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_segmentation_postprocessor.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_v4l2.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_recorder.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_replayer.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_profiler.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_spdlog_logger.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libholoscan_viz.so.2.9.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libucm.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libucp.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libucs.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libucs_signal.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libuct.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/libyaml-cpp.so.0.7.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libucm_cuda.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libucs_fuse.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_cma.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_cuda.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_cuda_gdrcopy.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_ib.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_rdmacm.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libuct_xpmem.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/lib/ucx/libucx_perftest_cuda.so.0.0.0 +0 -0
- holoscan-2.9.0.data/purelib/holoscan/logger/__init__.py +37 -0
- holoscan-2.9.0.data/purelib/holoscan/logger/_logger.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/network_contexts/__init__.py +28 -0
- holoscan-2.9.0.data/purelib/holoscan/network_contexts/_network_contexts.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/__init__.py +97 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/aja_source/__init__.py +22 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/aja_source/_aja_source.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/bayer_demosaic/__init__.py +24 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/bayer_demosaic/_bayer_demosaic.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/format_converter/__init__.py +23 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/format_converter/_format_converter.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/gxf_codelet/__init__.py +67 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/gxf_codelet/_gxf_codelet.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/holoviz/__init__.py +420 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/holoviz/_holoviz.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/inference/__init__.py +23 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/inference/_inference.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/inference_processor/__init__.py +23 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/inference_processor/_inference_processor.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_rx/__init__.py +45 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_tensor_rx/__init__.py +22 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_tensor_rx/_ping_tensor_rx.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_tensor_tx/__init__.py +22 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_tensor_tx/_ping_tensor_tx.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/ping_tx/__init__.py +46 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/segmentation_postprocessor/__init__.py +23 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/segmentation_postprocessor/_segmentation_postprocessor.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/v4l2_video_capture/__init__.py +23 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/v4l2_video_capture/_v4l2_video_capture.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/video_stream_recorder/__init__.py +22 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/video_stream_recorder/_video_stream_recorder.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/video_stream_replayer/__init__.py +22 -0
- holoscan-2.9.0.data/purelib/holoscan/operators/video_stream_replayer/_video_stream_replayer.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/resources/__init__.py +150 -0
- holoscan-2.9.0.data/purelib/holoscan/resources/_resources.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan/schedulers/__init__.py +32 -0
- holoscan-2.9.0.data/purelib/holoscan/schedulers/_schedulers.cpython-310-x86_64-linux-gnu.so +0 -0
- holoscan-2.9.0.data/purelib/holoscan-2.9.0.pth +1 -0
- holoscan-2.9.0.dist-info/LICENSE.txt +202 -0
- holoscan-2.9.0.dist-info/METADATA +142 -0
- holoscan-2.9.0.dist-info/NOTICE.txt +174 -0
- holoscan-2.9.0.dist-info/NVIDIA-AI-PRODUCT-EULA.txt +243 -0
- holoscan-2.9.0.dist-info/README.md +35 -0
- holoscan-2.9.0.dist-info/RECORD +117 -0
- holoscan-2.9.0.dist-info/WHEEL +5 -0
- holoscan-2.9.0.dist-info/axle.lck +0 -0
- holoscan-2.9.0.dist-info/entry_points.txt +3 -0
- holoscan-2.9.0.dist-info/symlinks.txt +82 -0
- holoscan-2.9.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
"""This module provides a Python API for the core C++ API classes.
|
|
16
|
+
|
|
17
|
+
The `Application` class is the primary class that should be derived from to
|
|
18
|
+
create a custom application.
|
|
19
|
+
|
|
20
|
+
.. autosummary::
|
|
21
|
+
|
|
22
|
+
holoscan.core.Application
|
|
23
|
+
holoscan.core.Arg
|
|
24
|
+
holoscan.core.ArgContainerType
|
|
25
|
+
holoscan.core.ArgElementType
|
|
26
|
+
holoscan.core.ArgList
|
|
27
|
+
holoscan.core.ArgType
|
|
28
|
+
holoscan.core.CLIOptions
|
|
29
|
+
holoscan.core.Component
|
|
30
|
+
holoscan.core.ComponentSpec
|
|
31
|
+
holoscan.core.ConditionType
|
|
32
|
+
holoscan.core.Condition
|
|
33
|
+
holoscan.core.Config
|
|
34
|
+
holoscan.core.DataFlowMetric
|
|
35
|
+
holoscan.core.DataFlowTracker
|
|
36
|
+
holoscan.core.DLDevice
|
|
37
|
+
holoscan.core.DLDeviceType
|
|
38
|
+
holoscan.core.ExecutionContext
|
|
39
|
+
holoscan.core.Executor
|
|
40
|
+
holoscan.core.Fragment
|
|
41
|
+
holoscan.core.Graph
|
|
42
|
+
holoscan.core.InputContext
|
|
43
|
+
holoscan.core.IOSpec
|
|
44
|
+
holoscan.core.Message
|
|
45
|
+
holoscan.core.MetadataDictionary
|
|
46
|
+
holoscan.core.MultiMessageConditionInfo
|
|
47
|
+
holoscan.core.MetadataPolicy
|
|
48
|
+
holoscan.core.NetworkContext
|
|
49
|
+
holoscan.core.Operator
|
|
50
|
+
holoscan.core.OperatorSpec
|
|
51
|
+
holoscan.core.OutputContext
|
|
52
|
+
holoscan.core.ParameterFlag
|
|
53
|
+
holoscan.core.Resource
|
|
54
|
+
holoscan.core.SchedulingStatusType
|
|
55
|
+
holoscan.core.Tensor
|
|
56
|
+
holoscan.core.Tracker
|
|
57
|
+
holoscan.core.arg_to_py_object
|
|
58
|
+
holoscan.core.arglist_to_kwargs
|
|
59
|
+
holoscan.core.kwargs_to_arglist
|
|
60
|
+
holoscan.core.py_object_to_arg
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
import os
|
|
64
|
+
import sys
|
|
65
|
+
|
|
66
|
+
# Note: Python 3.7+ expects the threading module to be initialized (imported) before additional
|
|
67
|
+
# threads are created (by C++ modules using pybind11).
|
|
68
|
+
# Otherwise you will get an assert tlock.locked() error on exit.
|
|
69
|
+
# (CLARAHOLOS-765)
|
|
70
|
+
import threading as _threading # noqa: F401, I001
|
|
71
|
+
from typing import Optional
|
|
72
|
+
|
|
73
|
+
# Temporarily set RTLD_GLOBAL to ensure that global symbols in the Holoscan C++ API
|
|
74
|
+
# (including logging-related symbols like nvidia::LoggingFunction) are shared
|
|
75
|
+
# across bindings. This is necessary because the Python interpreter loads the
|
|
76
|
+
# Pybind11 module with RTLD_LOCAL by default, which can duplicate symbols and
|
|
77
|
+
# lead to symbol resolution issues when the C++ API and global symbols are loaded
|
|
78
|
+
# as shared libraries by the Python interpreter.
|
|
79
|
+
original_flags = sys.getdlopenflags() # Save the current dlopen flags
|
|
80
|
+
try:
|
|
81
|
+
sys.setdlopenflags(os.RTLD_GLOBAL | os.RTLD_LAZY)
|
|
82
|
+
|
|
83
|
+
# Import statements for the C++ API classes
|
|
84
|
+
from ..graphs._graphs import FragmentGraph, OperatorGraph
|
|
85
|
+
from ._core import Application as _Application
|
|
86
|
+
from ._core import (
|
|
87
|
+
Arg,
|
|
88
|
+
ArgContainerType,
|
|
89
|
+
ArgElementType,
|
|
90
|
+
ArgList,
|
|
91
|
+
ArgType,
|
|
92
|
+
CLIOptions,
|
|
93
|
+
Component,
|
|
94
|
+
ConditionType,
|
|
95
|
+
Config,
|
|
96
|
+
DataFlowMetric,
|
|
97
|
+
DataFlowTracker,
|
|
98
|
+
DLDevice,
|
|
99
|
+
DLDeviceType,
|
|
100
|
+
Executor,
|
|
101
|
+
IOSpec,
|
|
102
|
+
Message,
|
|
103
|
+
MetadataDictionary,
|
|
104
|
+
MetadataPolicy,
|
|
105
|
+
MultiMessageConditionInfo,
|
|
106
|
+
NetworkContext,
|
|
107
|
+
ParameterFlag,
|
|
108
|
+
Scheduler,
|
|
109
|
+
SchedulingStatusType,
|
|
110
|
+
arg_to_py_object,
|
|
111
|
+
arglist_to_kwargs,
|
|
112
|
+
kwargs_to_arglist,
|
|
113
|
+
py_object_to_arg,
|
|
114
|
+
)
|
|
115
|
+
from ._core import Condition as _Condition
|
|
116
|
+
from ._core import Fragment as _Fragment
|
|
117
|
+
from ._core import Operator as _Operator
|
|
118
|
+
from ._core import PyComponentSpec as ComponentSpec
|
|
119
|
+
from ._core import PyExecutionContext as ExecutionContext
|
|
120
|
+
from ._core import PyInputContext as InputContext
|
|
121
|
+
from ._core import PyOperatorSpec as OperatorSpec
|
|
122
|
+
from ._core import PyOutputContext as OutputContext
|
|
123
|
+
from ._core import PyRegistryContext as _RegistryContext
|
|
124
|
+
from ._core import PyTensor as Tensor
|
|
125
|
+
from ._core import Resource as _Resource
|
|
126
|
+
from ._core import register_types as _register_types
|
|
127
|
+
finally:
|
|
128
|
+
# Restore the original dlopen flags immediately after the imports
|
|
129
|
+
sys.setdlopenflags(original_flags)
|
|
130
|
+
del original_flags
|
|
131
|
+
|
|
132
|
+
# need these imports for ThreadPool return type of Fragment.make_thread_pool to work
|
|
133
|
+
from ..gxf._gxf import GXFResource as _GXFResource # noqa: E402, F401, I001
|
|
134
|
+
from ..resources import ThreadPool as _ThreadPool # noqa: E402, F401, I001
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
Graph = OperatorGraph # define alias for backward compatibility
|
|
138
|
+
|
|
139
|
+
__all__ = [
|
|
140
|
+
"Application",
|
|
141
|
+
"Arg",
|
|
142
|
+
"ArgContainerType",
|
|
143
|
+
"ArgElementType",
|
|
144
|
+
"ArgList",
|
|
145
|
+
"ArgType",
|
|
146
|
+
"CLIOptions",
|
|
147
|
+
"Component",
|
|
148
|
+
"ComponentSpec",
|
|
149
|
+
"ConditionType",
|
|
150
|
+
"Condition",
|
|
151
|
+
"Config",
|
|
152
|
+
"DataFlowMetric",
|
|
153
|
+
"DataFlowTracker",
|
|
154
|
+
"DLDevice",
|
|
155
|
+
"DLDeviceType",
|
|
156
|
+
"ExecutionContext",
|
|
157
|
+
"Executor",
|
|
158
|
+
"Fragment",
|
|
159
|
+
"FragmentGraph",
|
|
160
|
+
"Graph",
|
|
161
|
+
"InputContext",
|
|
162
|
+
"IOSpec",
|
|
163
|
+
"Message",
|
|
164
|
+
"MetadataDictionary",
|
|
165
|
+
"MetadataPolicy",
|
|
166
|
+
"MultiMessageConditionInfo",
|
|
167
|
+
"NetworkContext",
|
|
168
|
+
"Operator",
|
|
169
|
+
"OperatorSpec",
|
|
170
|
+
"OperatorGraph",
|
|
171
|
+
"OutputContext",
|
|
172
|
+
"ParameterFlag",
|
|
173
|
+
"Resource",
|
|
174
|
+
"Scheduler",
|
|
175
|
+
"SchedulingStatusType",
|
|
176
|
+
"Tensor",
|
|
177
|
+
"Tracker",
|
|
178
|
+
"arg_to_py_object",
|
|
179
|
+
"arglist_to_kwargs",
|
|
180
|
+
"io_type_registry",
|
|
181
|
+
"kwargs_to_arglist",
|
|
182
|
+
"py_object_to_arg",
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# Define custom __repr__ method for MetadataDictionary
|
|
187
|
+
def metadata_repr(self):
|
|
188
|
+
items = {k: v for k, v in self.items()}
|
|
189
|
+
return f"{items}"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
MetadataDictionary.__repr__ = metadata_repr
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class Application(_Application):
|
|
196
|
+
def __init__(self, argv=None, *args, **kwargs):
|
|
197
|
+
# If no arguments are provided, instead of letting the C++ API initialize the application
|
|
198
|
+
# from the command line (through '/proc/self/cmdline'), we initialize the application
|
|
199
|
+
# with the command line arguments retrieved from the Python interpreter.
|
|
200
|
+
# This is because the C++ API will not be able to discard arguments that are not meant for
|
|
201
|
+
# the Python application.
|
|
202
|
+
# For example, if the user runs the application with the following
|
|
203
|
+
# command line arguments:
|
|
204
|
+
# /usr/bin/python3 -m pytest -v -k test_init /workspace/holoscan-sdk/public/python/tests
|
|
205
|
+
# then the C++ API will get the following arguments:
|
|
206
|
+
# ['/usr/bin/python3', '-m', 'pytest', '-v', '-k', 'test_init',
|
|
207
|
+
# '/workspace/holoscan-sdk/public/python/tests']
|
|
208
|
+
# whereas the Python interpreter (sys.argv) will get the following arguments:
|
|
209
|
+
# ['/usr/lib/python3/dist-packages/pytest.py', '-v', '-k', 'test_init',
|
|
210
|
+
# '/workspace/holoscan-sdk/public/python/tests']
|
|
211
|
+
# For the reason above, we initialize the application with the arguments:
|
|
212
|
+
# [sys.executable, *sys.argv]
|
|
213
|
+
# which will be equivalent to the following command line arguments:
|
|
214
|
+
# ['/usr/bin/python3', '/usr/lib/python3/dist-packages/pytest.py', '-v', '-k',
|
|
215
|
+
# 'test_init', '/workspace/holoscan-sdk/public/python/tests']
|
|
216
|
+
# and ``Application().argv`` will return the same arguments as ``sys.argv``.
|
|
217
|
+
|
|
218
|
+
if not argv:
|
|
219
|
+
import sys
|
|
220
|
+
|
|
221
|
+
argv = [sys.executable, *sys.argv]
|
|
222
|
+
|
|
223
|
+
# It is recommended to not use super()
|
|
224
|
+
# (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
|
|
225
|
+
_Application.__init__(self, argv, *args, **kwargs)
|
|
226
|
+
|
|
227
|
+
def run_async(self):
|
|
228
|
+
"""Run the application asynchronously.
|
|
229
|
+
|
|
230
|
+
This method is a convenience method that creates a thread pool with
|
|
231
|
+
one thread and runs the application in that thread. The thread pool
|
|
232
|
+
is created using `concurrent.futures.ThreadPoolExecutor`.
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
future : ``concurrent.futures.Future`` object
|
|
237
|
+
"""
|
|
238
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
239
|
+
|
|
240
|
+
executor = ThreadPoolExecutor(max_workers=1)
|
|
241
|
+
return executor.submit(self.run)
|
|
242
|
+
|
|
243
|
+
# If we created a context via `gxf.context_create` then we would need to
|
|
244
|
+
# call `gxf.context_destroy` in a destructor. However, in the __init__
|
|
245
|
+
# here, the C++ API creates the GXFExecutor and its context and the
|
|
246
|
+
# C++ object will also take care of the context deletion.
|
|
247
|
+
|
|
248
|
+
# def __del__(self):
|
|
249
|
+
# context_destroy(self._context)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
# copy docstrings defined in core_pydoc.hpp
|
|
253
|
+
Application.__doc__ = _Application.__doc__
|
|
254
|
+
Application.__init__.__doc__ = _Application.__init__.__doc__
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Fragment(_Fragment):
|
|
258
|
+
def __init__(self, app=None, name="", *args, **kwargs):
|
|
259
|
+
if app is not None and not isinstance(app, _Application):
|
|
260
|
+
raise ValueError(
|
|
261
|
+
"The first argument to a Fragment's constructor must be the Application "
|
|
262
|
+
"to which it belongs."
|
|
263
|
+
)
|
|
264
|
+
# It is recommended to not use super()
|
|
265
|
+
# (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
|
|
266
|
+
_Fragment.__init__(self, self, *args, **kwargs)
|
|
267
|
+
|
|
268
|
+
self.name = name
|
|
269
|
+
self.application = app
|
|
270
|
+
# Set the fragment config to the application config.
|
|
271
|
+
if app:
|
|
272
|
+
self.config(app.config())
|
|
273
|
+
|
|
274
|
+
def compose(self):
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
def run_async(self):
|
|
278
|
+
"""Run the fragment asynchronously.
|
|
279
|
+
|
|
280
|
+
This method is a convenience method that creates a thread pool with
|
|
281
|
+
one thread and runs the fragment in that thread. The thread pool
|
|
282
|
+
is created using `concurrent.futures.ThreadPoolExecutor`.
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
future : ``concurrent.futures.Future`` object
|
|
287
|
+
"""
|
|
288
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
289
|
+
|
|
290
|
+
executor = ThreadPoolExecutor(max_workers=1)
|
|
291
|
+
return executor.submit(self.run)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# copy docstrings defined in core_pydoc.hpp
|
|
295
|
+
Fragment.__doc__ = _Fragment.__doc__
|
|
296
|
+
Fragment.__init__.__doc__ = _Fragment.__init__.__doc__
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class Operator(_Operator):
|
|
300
|
+
_readonly_attributes = [
|
|
301
|
+
"fragment",
|
|
302
|
+
"conditions",
|
|
303
|
+
"resources",
|
|
304
|
+
"operator_type",
|
|
305
|
+
"description",
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
def __setattr__(self, name, value):
|
|
309
|
+
if name in self._readonly_attributes:
|
|
310
|
+
raise AttributeError(f'cannot override read-only property "{name}"')
|
|
311
|
+
super().__setattr__(name, value)
|
|
312
|
+
|
|
313
|
+
def __init__(self, fragment, *args, **kwargs):
|
|
314
|
+
if not isinstance(fragment, _Fragment):
|
|
315
|
+
raise ValueError(
|
|
316
|
+
"The first argument to an Operator's constructor must be the Fragment "
|
|
317
|
+
"(Application) to which it belongs."
|
|
318
|
+
)
|
|
319
|
+
# It is recommended to not use super()
|
|
320
|
+
# (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
|
|
321
|
+
_Operator.__init__(self, self, fragment, *args, **kwargs)
|
|
322
|
+
# Create a PyOperatorSpec object and pass it to the C++ API
|
|
323
|
+
spec = OperatorSpec(fragment=self.fragment, op=self)
|
|
324
|
+
self.spec = spec
|
|
325
|
+
# Call setup method in PyOperator class
|
|
326
|
+
self.setup(spec)
|
|
327
|
+
|
|
328
|
+
def setup(self, spec: OperatorSpec):
|
|
329
|
+
"""Default implementation of setup method."""
|
|
330
|
+
pass
|
|
331
|
+
|
|
332
|
+
def initialize(self):
|
|
333
|
+
"""Default implementation of initialize"""
|
|
334
|
+
pass
|
|
335
|
+
|
|
336
|
+
def start(self):
|
|
337
|
+
"""Default implementation of start"""
|
|
338
|
+
pass
|
|
339
|
+
|
|
340
|
+
def compute(self, op_input, op_output, context):
|
|
341
|
+
"""Default implementation of compute"""
|
|
342
|
+
pass
|
|
343
|
+
|
|
344
|
+
def stop(self):
|
|
345
|
+
"""Default implementation of stop"""
|
|
346
|
+
pass
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
# copy docstrings defined in core_pydoc.hpp
|
|
350
|
+
Operator.__doc__ = _Operator.__doc__
|
|
351
|
+
Operator.__init__.__doc__ = _Operator.__init__.__doc__
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class Condition(_Condition):
|
|
355
|
+
_readonly_attributes = [
|
|
356
|
+
"fragment",
|
|
357
|
+
"condition_type",
|
|
358
|
+
"description",
|
|
359
|
+
]
|
|
360
|
+
|
|
361
|
+
def __setattr__(self, name, value):
|
|
362
|
+
if name in self._readonly_attributes:
|
|
363
|
+
raise AttributeError(f'cannot override read-only property "{name}"')
|
|
364
|
+
super().__setattr__(name, value)
|
|
365
|
+
|
|
366
|
+
def __init__(self, fragment, *args, **kwargs):
|
|
367
|
+
if not isinstance(fragment, _Fragment):
|
|
368
|
+
raise ValueError(
|
|
369
|
+
"The first argument to an Condition's constructor must be the Fragment "
|
|
370
|
+
"(Application) to which it belongs."
|
|
371
|
+
)
|
|
372
|
+
# It is recommended to not use super()
|
|
373
|
+
# (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
|
|
374
|
+
_Condition.__init__(self, self, fragment, *args, **kwargs)
|
|
375
|
+
# Create a PyComponentSpec object and pass it to the C++ API
|
|
376
|
+
spec = ComponentSpec(fragment=self.fragment, component=self)
|
|
377
|
+
self.spec = spec
|
|
378
|
+
# Call setup method in PyCondition class
|
|
379
|
+
self.setup(spec)
|
|
380
|
+
|
|
381
|
+
def setup(self, spec: ComponentSpec):
|
|
382
|
+
"""Default implementation of setup method."""
|
|
383
|
+
pass
|
|
384
|
+
|
|
385
|
+
def initialize(self):
|
|
386
|
+
"""Default implementation of initialize"""
|
|
387
|
+
pass
|
|
388
|
+
|
|
389
|
+
def update_state(self, timestamp):
|
|
390
|
+
"""Default implementation of update_state
|
|
391
|
+
|
|
392
|
+
Parameters
|
|
393
|
+
----------
|
|
394
|
+
timestamp : int
|
|
395
|
+
The timestamp at which the update_state method was called.
|
|
396
|
+
|
|
397
|
+
Notes
|
|
398
|
+
-----
|
|
399
|
+
This method is always called by the underlying GXF framework immediately before the
|
|
400
|
+
`Condition.check` method. In some cases, the `Condition.on_execute` method may also wish
|
|
401
|
+
to call this method.
|
|
402
|
+
"""
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
def check(self, timestamp: int) -> tuple[SchedulingStatusType, Optional[int]]:
|
|
406
|
+
"""Default implementation of check.
|
|
407
|
+
|
|
408
|
+
Parameters
|
|
409
|
+
----------
|
|
410
|
+
timestamp : int
|
|
411
|
+
The timestamp at which the check method is called. This method is called by the
|
|
412
|
+
underlying GXF framework to determine whether an operator is ready to execute.
|
|
413
|
+
|
|
414
|
+
Returns
|
|
415
|
+
-------
|
|
416
|
+
status_type: SchedulingStatusType
|
|
417
|
+
The current status of the operator. See the documentation on native condition
|
|
418
|
+
creation for explanations of the various status types.
|
|
419
|
+
target_timestamp: int or None
|
|
420
|
+
Specifies a specific target timestamp at which the operator is expected to be ready.
|
|
421
|
+
This should only be provided if relevant (it helps the underlying framework avoid
|
|
422
|
+
overhead of repeated checks before the target time).
|
|
423
|
+
|
|
424
|
+
Notes
|
|
425
|
+
-----
|
|
426
|
+
The method should return SchedulingStatusType.READY when the desired condition has been met.
|
|
427
|
+
|
|
428
|
+
The operator will always execute with this default implementation that always execute with
|
|
429
|
+
this default implementation.
|
|
430
|
+
"""
|
|
431
|
+
return SchedulingStatusType.READY, None
|
|
432
|
+
|
|
433
|
+
def on_execute(self, timestamp):
|
|
434
|
+
"""Default implementation of on_execute
|
|
435
|
+
|
|
436
|
+
Parameters
|
|
437
|
+
----------
|
|
438
|
+
timestamp : int
|
|
439
|
+
The timestamp at which the on_execute method was called.
|
|
440
|
+
|
|
441
|
+
Notes
|
|
442
|
+
-----
|
|
443
|
+
This method is called by the underlying GXF framework immediately after the
|
|
444
|
+
`Operator.compute` call for the operator to which the condition has been assigned.
|
|
445
|
+
"""
|
|
446
|
+
pass
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
# copy docstrings defined in core_pydoc.hpp
|
|
450
|
+
Condition.__doc__ = _Condition.__doc__
|
|
451
|
+
Condition.__init__.__doc__ = _Condition.__init__.__doc__
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
class Resource(_Resource):
|
|
455
|
+
_readonly_attributes = [
|
|
456
|
+
"fragment",
|
|
457
|
+
"resource_type",
|
|
458
|
+
"description",
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
def __setattr__(self, name, value):
|
|
462
|
+
if name in self._readonly_attributes:
|
|
463
|
+
raise AttributeError(f'cannot override read-only property "{name}"')
|
|
464
|
+
super().__setattr__(name, value)
|
|
465
|
+
|
|
466
|
+
def __init__(self, fragment, *args, **kwargs):
|
|
467
|
+
if not isinstance(fragment, _Fragment):
|
|
468
|
+
raise ValueError(
|
|
469
|
+
"The first argument to an Resource's constructor must be the Fragment "
|
|
470
|
+
"(Application) to which it belongs."
|
|
471
|
+
)
|
|
472
|
+
# It is recommended to not use super()
|
|
473
|
+
# (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
|
|
474
|
+
_Resource.__init__(self, self, fragment, *args, **kwargs)
|
|
475
|
+
# Create a PyComponentSpec object and pass it to the C++ API
|
|
476
|
+
spec = ComponentSpec(fragment=self.fragment, component=self)
|
|
477
|
+
self.spec = spec
|
|
478
|
+
# Call setup method in PyResource class
|
|
479
|
+
self.setup(spec)
|
|
480
|
+
|
|
481
|
+
def setup(self, spec: ComponentSpec):
|
|
482
|
+
"""Default implementation of setup method."""
|
|
483
|
+
pass
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
# copy docstrings defined in core_pydoc.hpp
|
|
487
|
+
Resource.__doc__ = _Resource.__doc__
|
|
488
|
+
Resource.__init__.__doc__ = _Resource.__init__.__doc__
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
class Tracker:
|
|
492
|
+
"""Context manager to add data flow tracking to an application."""
|
|
493
|
+
|
|
494
|
+
def __init__(
|
|
495
|
+
self,
|
|
496
|
+
app,
|
|
497
|
+
*,
|
|
498
|
+
filename=None,
|
|
499
|
+
num_buffered_messages=100,
|
|
500
|
+
num_start_messages_to_skip=10,
|
|
501
|
+
num_last_messages_to_discard=10,
|
|
502
|
+
latency_threshold=0,
|
|
503
|
+
is_limited_tracking=False,
|
|
504
|
+
):
|
|
505
|
+
"""
|
|
506
|
+
Parameters
|
|
507
|
+
----------
|
|
508
|
+
app : holoscan.core.Application
|
|
509
|
+
on which flow tracking should be applied.
|
|
510
|
+
filename : str or None, optional
|
|
511
|
+
If none, logging to file will be disabled. Otherwise, logging will
|
|
512
|
+
write to the specified file.
|
|
513
|
+
num_buffered_messages : int, optional
|
|
514
|
+
Controls the number of messages buffered between file writing when
|
|
515
|
+
`filename` is not ``None``.
|
|
516
|
+
num_start_messages_to_skip : int, optional
|
|
517
|
+
The number of messages to skip at the beginning of the execution. This does not affect
|
|
518
|
+
the log file or the number of source messages metric.
|
|
519
|
+
num_last_messages_to_discard : int, optional
|
|
520
|
+
The number of messages to discard at the end of the execution. This does not affect
|
|
521
|
+
the log file or the number of source messages metric.
|
|
522
|
+
latency_threshold : int, optional
|
|
523
|
+
The minimum end-to-end latency in milliseconds to account for in the end-to-end
|
|
524
|
+
latency metric calculations.
|
|
525
|
+
is_limited_tracking : bool, optional
|
|
526
|
+
If true, the tracking is limited to root and leaf nodes, minimizing the timestamps by
|
|
527
|
+
avoiding intermediate operators.
|
|
528
|
+
"""
|
|
529
|
+
self.app = app
|
|
530
|
+
|
|
531
|
+
# Check the number of fragment nodes to see if it is a distributed app.
|
|
532
|
+
# Use compose_graph(), not compose() to protect against repeated compose() calls.
|
|
533
|
+
self.app.compose_graph()
|
|
534
|
+
self.is_distributed_app = len(app.fragment_graph.get_nodes()) > 0
|
|
535
|
+
|
|
536
|
+
self.enable_logging = filename is not None
|
|
537
|
+
if self.enable_logging:
|
|
538
|
+
self.logging_kwargs = dict(
|
|
539
|
+
filename=filename,
|
|
540
|
+
num_buffered_messages=num_buffered_messages,
|
|
541
|
+
)
|
|
542
|
+
self.tracker_kwargs = dict(
|
|
543
|
+
num_start_messages_to_skip=num_start_messages_to_skip,
|
|
544
|
+
num_last_messages_to_discard=num_last_messages_to_discard,
|
|
545
|
+
latency_threshold=latency_threshold,
|
|
546
|
+
is_limited_tracking=False,
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
def __enter__(self):
|
|
550
|
+
if self.is_distributed_app:
|
|
551
|
+
self.trackers = self.app.track_distributed(**self.tracker_kwargs)
|
|
552
|
+
for tracker in self.trackers.values():
|
|
553
|
+
if self.enable_logging:
|
|
554
|
+
tracker.enable_logging(**self.logging_kwargs)
|
|
555
|
+
return self.trackers
|
|
556
|
+
else:
|
|
557
|
+
self.tracker = self.app.track(**self.tracker_kwargs)
|
|
558
|
+
if self.enable_logging:
|
|
559
|
+
self.tracker.enable_logging(**self.logging_kwargs)
|
|
560
|
+
return self.tracker
|
|
561
|
+
|
|
562
|
+
def __exit__(self, exc_type, exc_value, exc_tb):
|
|
563
|
+
if self.enable_logging:
|
|
564
|
+
if self.is_distributed_app:
|
|
565
|
+
for tracker in self.trackers.values():
|
|
566
|
+
tracker.end_logging()
|
|
567
|
+
else:
|
|
568
|
+
self.tracker.end_logging()
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
_registry_context = _RegistryContext()
|
|
572
|
+
io_type_registry = _registry_context.registry()
|
|
573
|
+
|
|
574
|
+
_register_types(io_type_registry)
|