holoscan-cu13 3.7.0__cp310-cp310-manylinux_2_35_aarch64.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.
Files changed (124) hide show
  1. holoscan_cu13-3.7.0.data/purelib/holoscan/__init__.py +135 -0
  2. holoscan_cu13-3.7.0.data/purelib/holoscan/cli/__main__.py +26 -0
  3. holoscan_cu13-3.7.0.data/purelib/holoscan/conditions/__init__.py +75 -0
  4. holoscan_cu13-3.7.0.data/purelib/holoscan/conditions/_conditions.cpython-310-aarch64-linux-gnu.so +0 -0
  5. holoscan_cu13-3.7.0.data/purelib/holoscan/core/__init__.py +799 -0
  6. holoscan_cu13-3.7.0.data/purelib/holoscan/core/_core.cpython-310-aarch64-linux-gnu.so +0 -0
  7. holoscan_cu13-3.7.0.data/purelib/holoscan/data_loggers/__init__.py +79 -0
  8. holoscan_cu13-3.7.0.data/purelib/holoscan/data_loggers/async_console_logger/__init__.py +22 -0
  9. holoscan_cu13-3.7.0.data/purelib/holoscan/data_loggers/async_console_logger/_async_console_logger.cpython-310-aarch64-linux-gnu.so +0 -0
  10. holoscan_cu13-3.7.0.data/purelib/holoscan/data_loggers/basic_console_logger/__init__.py +22 -0
  11. holoscan_cu13-3.7.0.data/purelib/holoscan/data_loggers/basic_console_logger/_basic_console_logger.cpython-310-aarch64-linux-gnu.so +0 -0
  12. holoscan_cu13-3.7.0.data/purelib/holoscan/decorator.py +662 -0
  13. holoscan_cu13-3.7.0.data/purelib/holoscan/executors/__init__.py +26 -0
  14. holoscan_cu13-3.7.0.data/purelib/holoscan/executors/_executors.cpython-310-aarch64-linux-gnu.so +0 -0
  15. holoscan_cu13-3.7.0.data/purelib/holoscan/graphs/__init__.py +32 -0
  16. holoscan_cu13-3.7.0.data/purelib/holoscan/graphs/_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  17. holoscan_cu13-3.7.0.data/purelib/holoscan/gxf/__init__.py +60 -0
  18. holoscan_cu13-3.7.0.data/purelib/holoscan/gxf/_gxf.cpython-310-aarch64-linux-gnu.so +0 -0
  19. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper.so +0 -0
  20. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_holoscan_wrapper_lib.so +0 -0
  21. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan.so +0 -0
  22. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/gxf_extensions/libgxf_ucx_holoscan_lib.so +0 -0
  23. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_app.so +0 -0
  24. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_core.so +0 -0
  25. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_cuda.so +0 -0
  26. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_http.so +0 -0
  27. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_logger.so +0 -0
  28. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_multimedia.so +0 -0
  29. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_rmm.so +0 -0
  30. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_sample.so +0 -0
  31. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_serialization.so +0 -0
  32. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_std.so +0 -0
  33. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libgxf_ucx.so +0 -0
  34. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoinfer_utils.so.3.7.0 +0 -0
  35. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_core.so.3.7.0 +0 -0
  36. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_data_loggers_async_console_logger.so.3.7.0 +0 -0
  37. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_data_loggers_basic_console_logger.so.3.7.0 +0 -0
  38. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_infer.so.3.7.0 +0 -0
  39. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_infer_onnx_runtime.so.3.7.0 +0 -0
  40. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_infer_torch.so.3.7.0 +0 -0
  41. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_infer_utils.so.3.7.0 +0 -0
  42. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_logger.so.3.7.0 +0 -0
  43. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_rx.so.3.7.0 +0 -0
  44. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_async_ping_tx.so.3.7.0 +0 -0
  45. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_bayer_demosaic.so.3.7.0 +0 -0
  46. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_format_converter.so.3.7.0 +0 -0
  47. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_gxf_codelet.so.3.7.0 +0 -0
  48. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_holoviz.so.3.7.0 +0 -0
  49. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_inference.so.3.7.0 +0 -0
  50. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_inference_processor.so.3.7.0 +0 -0
  51. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_ping_rx.so.3.7.0 +0 -0
  52. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_rx.so.3.7.0 +0 -0
  53. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_ping_tensor_tx.so.3.7.0 +0 -0
  54. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_ping_tx.so.3.7.0 +0 -0
  55. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_segmentation_postprocessor.so.3.7.0 +0 -0
  56. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_test_ops.so.3.7.0 +0 -0
  57. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_v4l2.so.3.7.0 +0 -0
  58. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_recorder.so.3.7.0 +0 -0
  59. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_op_video_stream_replayer.so.3.7.0 +0 -0
  60. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_pose_tree.so.3.7.0 +0 -0
  61. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_profiler.so.3.7.0 +0 -0
  62. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_spdlog_logger.so.3.7.0 +0 -0
  63. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libholoscan_viz.so.3.7.0 +0 -0
  64. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libucm.so.0.0.0 +0 -0
  65. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libucp.so.0.0.0 +0 -0
  66. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libucs.so.0.0.0 +0 -0
  67. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libucs_signal.so.0.0.0 +0 -0
  68. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libuct.so.0.0.0 +0 -0
  69. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/libucxx.so +0 -0
  70. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/ucx/libucm_cuda.so.0.0.0 +0 -0
  71. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/ucx/libuct_cma.so.0.0.0 +0 -0
  72. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/ucx/libuct_cuda.so.0.0.0 +0 -0
  73. holoscan_cu13-3.7.0.data/purelib/holoscan/lib/ucx/libucx_perftest_cuda.so.0.0.0 +0 -0
  74. holoscan_cu13-3.7.0.data/purelib/holoscan/logger/__init__.py +37 -0
  75. holoscan_cu13-3.7.0.data/purelib/holoscan/logger/_logger.cpython-310-aarch64-linux-gnu.so +0 -0
  76. holoscan_cu13-3.7.0.data/purelib/holoscan/network_contexts/__init__.py +28 -0
  77. holoscan_cu13-3.7.0.data/purelib/holoscan/network_contexts/_network_contexts.cpython-310-aarch64-linux-gnu.so +0 -0
  78. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/__init__.py +99 -0
  79. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/bayer_demosaic/__init__.py +24 -0
  80. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/bayer_demosaic/_bayer_demosaic.cpython-310-aarch64-linux-gnu.so +0 -0
  81. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/format_converter/__init__.py +23 -0
  82. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/format_converter/_format_converter.cpython-310-aarch64-linux-gnu.so +0 -0
  83. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/gxf_codelet/__init__.py +67 -0
  84. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/gxf_codelet/_gxf_codelet.cpython-310-aarch64-linux-gnu.so +0 -0
  85. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/holoviz/__init__.py +423 -0
  86. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/holoviz/_holoviz.cpython-310-aarch64-linux-gnu.so +0 -0
  87. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/inference/__init__.py +28 -0
  88. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/inference/_inference.cpython-310-aarch64-linux-gnu.so +0 -0
  89. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/inference_processor/__init__.py +23 -0
  90. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/inference_processor/_inference_processor.cpython-310-aarch64-linux-gnu.so +0 -0
  91. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_rx/__init__.py +45 -0
  92. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_tensor_rx/__init__.py +22 -0
  93. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_tensor_rx/_ping_tensor_rx.cpython-310-aarch64-linux-gnu.so +0 -0
  94. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_tensor_tx/__init__.py +22 -0
  95. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_tensor_tx/_ping_tensor_tx.cpython-310-aarch64-linux-gnu.so +0 -0
  96. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/ping_tx/__init__.py +46 -0
  97. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/segmentation_postprocessor/__init__.py +23 -0
  98. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/segmentation_postprocessor/_segmentation_postprocessor.cpython-310-aarch64-linux-gnu.so +0 -0
  99. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/test_ops/__init__.py +22 -0
  100. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/test_ops/_test_ops.cpython-310-aarch64-linux-gnu.so +0 -0
  101. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/v4l2_video_capture/__init__.py +23 -0
  102. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/v4l2_video_capture/_v4l2_video_capture.cpython-310-aarch64-linux-gnu.so +0 -0
  103. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/video_stream_recorder/__init__.py +22 -0
  104. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/video_stream_recorder/_video_stream_recorder.cpython-310-aarch64-linux-gnu.so +0 -0
  105. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/video_stream_replayer/__init__.py +22 -0
  106. holoscan_cu13-3.7.0.data/purelib/holoscan/operators/video_stream_replayer/_video_stream_replayer.cpython-310-aarch64-linux-gnu.so +0 -0
  107. holoscan_cu13-3.7.0.data/purelib/holoscan/pose_tree/__init__.py +271 -0
  108. holoscan_cu13-3.7.0.data/purelib/holoscan/pose_tree/_pose_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  109. holoscan_cu13-3.7.0.data/purelib/holoscan/resources/__init__.py +171 -0
  110. holoscan_cu13-3.7.0.data/purelib/holoscan/resources/_resources.cpython-310-aarch64-linux-gnu.so +0 -0
  111. holoscan_cu13-3.7.0.data/purelib/holoscan/schedulers/__init__.py +32 -0
  112. holoscan_cu13-3.7.0.data/purelib/holoscan/schedulers/_schedulers.cpython-310-aarch64-linux-gnu.so +0 -0
  113. holoscan_cu13-3.7.0.data/purelib/holoscan_cu13-3.7.0.pth +1 -0
  114. holoscan_cu13-3.7.0.dist-info/LICENSE.txt +202 -0
  115. holoscan_cu13-3.7.0.dist-info/METADATA +148 -0
  116. holoscan_cu13-3.7.0.dist-info/NOTICE.txt +191 -0
  117. holoscan_cu13-3.7.0.dist-info/NVIDIA-AI-PRODUCT-EULA.txt +243 -0
  118. holoscan_cu13-3.7.0.dist-info/README.md +35 -0
  119. holoscan_cu13-3.7.0.dist-info/RECORD +124 -0
  120. holoscan_cu13-3.7.0.dist-info/WHEEL +5 -0
  121. holoscan_cu13-3.7.0.dist-info/axle.lck +0 -0
  122. holoscan_cu13-3.7.0.dist-info/entry_points.txt +3 -0
  123. holoscan_cu13-3.7.0.dist-info/symlinks.txt +78 -0
  124. holoscan_cu13-3.7.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,799 @@
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.AsyncDataLoggerResource
29
+ holoscan.core.AsyncQueuePolicy
30
+ holoscan.core.CLIOptions
31
+ holoscan.core.Clock
32
+ holoscan.core.ClockInterface
33
+ holoscan.core.Component
34
+ holoscan.core.ComponentSpec
35
+ holoscan.core.Condition
36
+ holoscan.core.ConditionType
37
+ holoscan.core.Config
38
+ holoscan.core.DataFlowMetric
39
+ holoscan.core.DataFlowTracker
40
+ holoscan.core.DataLogger
41
+ holoscan.core.DataLoggerResource
42
+ holoscan.core.DefaultFragmentService
43
+ holoscan.core.DLDevice
44
+ holoscan.core.DLDeviceType
45
+ holoscan.core.ExecutionContext
46
+ holoscan.core.Executor
47
+ holoscan.core.Fragment
48
+ holoscan.core.FlowInfo
49
+ holoscan.core.Fragment
50
+ holoscan.core.Graph
51
+ holoscan.core.FragmentService
52
+ holoscan.core.InputContext
53
+ holoscan.core.IOSpec
54
+ holoscan.core.Message
55
+ holoscan.core.MetadataDictionary
56
+ holoscan.core.MetadataPolicy
57
+ holoscan.core.MultiMessageConditionInfo
58
+ holoscan.core.NetworkContext
59
+ holoscan.core.Operator
60
+ holoscan.core.OperatorSpec
61
+ holoscan.core.OperatorStatus
62
+ holoscan.core.OutputContext
63
+ holoscan.core.ParameterFlag
64
+ holoscan.core.arg_to_py_object
65
+ holoscan.core.arglist_to_kwargs
66
+ holoscan.core.Resource
67
+ holoscan.core.SchedulingStatusType
68
+ holoscan.core.ServiceDriverEndpoint
69
+ holoscan.core.ServiceWorkerEndpoint
70
+ holoscan.core.Tensor
71
+ holoscan.core.Tracker
72
+ holoscan.core.kwargs_to_arglist
73
+ holoscan.core.py_object_to_arg
74
+ """
75
+
76
+ import logging
77
+ import sys
78
+
79
+ # Note: Python 3.7+ expects the threading module to be initialized (imported) before additional
80
+ # threads are created (by C++ modules using pybind11).
81
+ # Otherwise you will get an assert tlock.locked() error on exit.
82
+ # (CLARAHOLOS-765)
83
+ import threading as _threading # noqa: F401, I001
84
+
85
+ # Add ThreadPoolExecutor to imports if not already there
86
+ from concurrent.futures import ThreadPoolExecutor
87
+
88
+ # Import statements for the C++ API classes
89
+ from ..graphs._graphs import FragmentGraph, OperatorGraph
90
+ from ._core import Application as _Application
91
+ from ._core import (
92
+ Arg,
93
+ ArgContainerType,
94
+ ArgElementType,
95
+ ArgList,
96
+ ArgType,
97
+ AsyncDataLoggerResource,
98
+ AsyncQueuePolicy,
99
+ CLIOptions,
100
+ Clock,
101
+ ClockInterface,
102
+ Component,
103
+ ConditionType,
104
+ Config,
105
+ DataFlowMetric,
106
+ DataFlowTracker,
107
+ DataLogger,
108
+ DataLoggerResource,
109
+ DistributedAppService,
110
+ DLDevice,
111
+ DLDeviceType,
112
+ Executor,
113
+ FlowInfo,
114
+ FragmentService,
115
+ IOSpec,
116
+ Message,
117
+ MetadataDictionary,
118
+ MetadataPolicy,
119
+ MultiMessageConditionInfo,
120
+ NetworkContext,
121
+ OperatorStatus,
122
+ ParameterFlag,
123
+ Scheduler,
124
+ SchedulingStatusType,
125
+ ServiceDriverEndpoint,
126
+ ServiceWorkerEndpoint,
127
+ arg_to_py_object,
128
+ arglist_to_kwargs,
129
+ kwargs_to_arglist,
130
+ py_object_to_arg,
131
+ )
132
+ from ._core import Condition as _Condition
133
+ from ._core import DefaultFragmentService as _DefaultFragmentService
134
+ from ._core import Fragment as _Fragment
135
+ from ._core import Operator as _Operator
136
+ from ._core import PyComponentSpec as ComponentSpec
137
+ from ._core import PyExecutionContext as ExecutionContext
138
+ from ._core import PyInputContext as InputContext
139
+ from ._core import PyOperatorSpec as OperatorSpec
140
+ from ._core import PyOutputContext as OutputContext
141
+ from ._core import PyRegistryContext as _RegistryContext
142
+ from ._core import PyTensor as Tensor
143
+ from ._core import Resource as _Resource
144
+ from ._core import register_types as _register_types
145
+
146
+ # Get a logger instance for this module
147
+ logger = logging.getLogger(__name__)
148
+
149
+ Graph = OperatorGraph # define alias for backward compatibility
150
+
151
+ __all__ = [
152
+ "Application",
153
+ "Arg",
154
+ "ArgContainerType",
155
+ "ArgElementType",
156
+ "ArgList",
157
+ "ArgType",
158
+ "AsyncDataLoggerResource",
159
+ "AsyncQueuePolicy",
160
+ "CLIOptions",
161
+ "Clock",
162
+ "ClockInterface",
163
+ "Component",
164
+ "ComponentSpec",
165
+ "ConditionType",
166
+ "Condition",
167
+ "Config",
168
+ "DataFlowMetric",
169
+ "DataFlowTracker",
170
+ "DataLogger",
171
+ "DataLoggerResource",
172
+ "DefaultFragmentService",
173
+ "DistributedAppService",
174
+ "DLDevice",
175
+ "DLDeviceType",
176
+ "ExecutionContext",
177
+ "Executor",
178
+ "FlowInfo",
179
+ "Fragment",
180
+ "FragmentGraph",
181
+ "FragmentService",
182
+ "Graph",
183
+ "InputContext",
184
+ "IOSpec",
185
+ "Message",
186
+ "MetadataDictionary",
187
+ "MetadataPolicy",
188
+ "MultiMessageConditionInfo",
189
+ "NetworkContext",
190
+ "Operator",
191
+ "OperatorSpec",
192
+ "OperatorStatus",
193
+ "OperatorGraph",
194
+ "OutputContext",
195
+ "ParameterFlag",
196
+ "Resource",
197
+ "Scheduler",
198
+ "SchedulingStatusType",
199
+ "ServiceDriverEndpoint",
200
+ "ServiceWorkerEndpoint",
201
+ "START_OPERATOR_NAME",
202
+ "Tensor",
203
+ "Tracker",
204
+ "arg_to_py_object",
205
+ "arglist_to_kwargs",
206
+ "io_type_registry",
207
+ "kwargs_to_arglist",
208
+ "py_object_to_arg",
209
+ ]
210
+
211
+
212
+ # Define custom __repr__ method for MetadataDictionary
213
+ def metadata_repr(self):
214
+ items = {k: v for k, v in self.items()}
215
+ return f"{items}"
216
+
217
+
218
+ # need these imports for ThreadPool return type of Fragment.make_thread_pool to work
219
+ from ..gxf._gxf import GXFResource as _GXFResource # noqa: E402, F401, I001
220
+ from ..resources import ThreadPool as _ThreadPool # noqa: E402, F401, I001
221
+
222
+ MetadataDictionary.__repr__ = metadata_repr
223
+
224
+ # Defines the special operator name used to initiate application execution.
225
+ # The GXF framework requires entity names to not begin with double underscores,
226
+ # so this distinctive name pattern is chosen to prevent naming collisions.
227
+ # This constant mirrors the C++ definition of `holoscan::kStartOperatorName`
228
+ # found in holoscan/core/fragment.hpp
229
+ START_OPERATOR_NAME = "<|start|>"
230
+
231
+
232
+ class Application(_Application):
233
+ def __init__(self, argv=None, *args, **kwargs):
234
+ # If no arguments are provided, instead of letting the C++ API initialize the application
235
+ # from the command line (through '/proc/self/cmdline'), we initialize the application
236
+ # with the command line arguments retrieved from the Python interpreter.
237
+ # This is because the C++ API will not be able to discard arguments that are not meant for
238
+ # the Python application.
239
+ # For example, if the user runs the application with the following
240
+ # command line arguments:
241
+ # /usr/bin/python3 -m pytest -v -k test_init /workspace/holoscan-sdk/public/python/tests
242
+ # then the C++ API will get the following arguments:
243
+ # ['/usr/bin/python3', '-m', 'pytest', '-v', '-k', 'test_init',
244
+ # '/workspace/holoscan-sdk/public/python/tests']
245
+ # whereas the Python interpreter (sys.argv) will get the following arguments:
246
+ # ['/usr/lib/python3/dist-packages/pytest.py', '-v', '-k', 'test_init',
247
+ # '/workspace/holoscan-sdk/public/python/tests']
248
+ # For the reason above, we initialize the application with the arguments:
249
+ # [sys.executable, *sys.argv]
250
+ # which will be equivalent to the following command line arguments:
251
+ # ['/usr/bin/python3', '/usr/lib/python3/dist-packages/pytest.py', '-v', '-k',
252
+ # 'test_init', '/workspace/holoscan-sdk/public/python/tests']
253
+ # and ``Application().argv`` will return the same arguments as ``sys.argv``.
254
+
255
+ if not argv:
256
+ argv = [sys.executable, *sys.argv]
257
+
258
+ # It is recommended to not use super()
259
+ # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
260
+ _Application.__init__(self, argv, *args, **kwargs)
261
+ self._async_executor = None
262
+ self._async_executor_lock = _threading.Lock()
263
+ self._start_op = None
264
+
265
+ def run_async(self):
266
+ """Run the application asynchronously using a shared executor.
267
+
268
+ This method uses a shared ThreadPoolExecutor associated with this
269
+ Application instance. The executor is created on the first call.
270
+ Call `shutdown_async_executor()` when done with async runs
271
+ to clean up resources.
272
+
273
+ Returns
274
+ -------
275
+ future : ``concurrent.futures.Future`` object
276
+ """
277
+ # Ensure only one thread creates the executor
278
+ with self._async_executor_lock:
279
+ if self._async_executor is None:
280
+ # Create the executor ONCE
281
+ self._async_executor = ThreadPoolExecutor(
282
+ max_workers=1, thread_name_prefix=f"HoloscanApp_{self.name}_Async"
283
+ )
284
+
285
+ # Submit the job to the shared executor
286
+ return self._async_executor.submit(self.run)
287
+
288
+ def shutdown_async_executor(self, wait=True):
289
+ """Shuts down the shared asynchronous executor.
290
+
291
+ Call this method when the application instance is no longer needed
292
+ and asynchronous runs initiated by `run_async` should terminate.
293
+
294
+ Parameters
295
+ ----------
296
+ wait : bool
297
+ If True (default), wait for running tasks to complete before shutting down.
298
+ If False, shut down immediately.
299
+ """
300
+ # Use the lock to prevent race conditions with run_async
301
+ with self._async_executor_lock:
302
+ if self._async_executor is not None:
303
+ # Shutting down async executor
304
+ self._async_executor.shutdown(wait=wait)
305
+ self._async_executor = None
306
+
307
+ def start_op(self):
308
+ """Get or create the start operator for this application.
309
+
310
+ This operator is nothing but the first operator that was added to the application.
311
+ It has the name of `<|start|>` and has a condition of `CountCondition(1)`.
312
+ This Operator is used to start the execution of the application.
313
+ Entry operators who want to start the execution of the application should connect to this
314
+ operator.
315
+
316
+ If this method is not called, no start operator is created.
317
+ Otherwise, the start operator is created if it does not exist, and the start operator is
318
+ returned.
319
+
320
+ Returns
321
+ -------
322
+ Operator
323
+ The start operator instance. If it doesn't exist, it will be created with
324
+ a CountCondition(1).
325
+ """
326
+ from ..conditions import CountCondition # noqa: PLC0415
327
+
328
+ if not self._start_op:
329
+ self._start_op = Operator(self, CountCondition(self, 1), name=START_OPERATOR_NAME)
330
+ self.add_operator(self._start_op)
331
+ return self._start_op
332
+
333
+ # If we created a context via `gxf.context_create` then we would need to
334
+ # call `gxf.context_destroy` in a destructor. However, in the __init__
335
+ # here, the C++ API creates the GXFExecutor and its context and the
336
+ # C++ object will also take care of the context deletion.
337
+
338
+ # def __del__(self):
339
+ # context_destroy(self._context)
340
+
341
+ def __del__(self):
342
+ # This is best-effort cleanup, not guaranteed to be called reliably.
343
+ # Avoid potentially blocking calls or complex logic here.
344
+ if self._async_executor is not None:
345
+ # Non-blocking shutdown is safer in __del__ if possible,
346
+ # but might leave work unfinished or resources dangling longer.
347
+ # Using wait=False might be preferable here, but check implications.
348
+ try:
349
+ self._async_executor.shutdown(wait=False) # Try non-blocking first
350
+ except Exception as e:
351
+ logger.error(
352
+ f"Error during __del__ executor shutdown for Application {self.name}: {e}",
353
+ exc_info=True,
354
+ )
355
+ finally:
356
+ self._async_executor = None
357
+
358
+
359
+ # copy docstrings defined in core_pydoc.hpp
360
+ Application.__doc__ = _Application.__doc__
361
+ Application.__init__.__doc__ = _Application.__init__.__doc__
362
+
363
+
364
+ class Fragment(_Fragment):
365
+ def __init__(self, app=None, name="", *args, **kwargs):
366
+ if app is not None and not isinstance(app, _Application):
367
+ raise ValueError(
368
+ "The first argument to a Fragment's constructor must be the Application "
369
+ "to which it belongs."
370
+ )
371
+ # It is recommended to not use super()
372
+ # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
373
+ _Fragment.__init__(self, self, *args, **kwargs)
374
+
375
+ self.name = name
376
+ self.application = app
377
+ # Set the fragment config to the application config.
378
+ if app:
379
+ self.config(app.config())
380
+ self._async_executor = None
381
+ self._async_executor_lock = _threading.Lock()
382
+ self._start_op = None
383
+ # Initialize the Python service registry for PyFragment
384
+ self._python_service_registry = {}
385
+
386
+ def compose(self):
387
+ pass
388
+
389
+ def run_async(self):
390
+ """Run the fragment asynchronously using a shared executor.
391
+
392
+ This method uses a shared ThreadPoolExecutor associated with this
393
+ Application instance. The executor is created on the first call.
394
+ Call `shutdown_async_executor()` when done with async runs
395
+ to clean up resources.
396
+
397
+ Returns
398
+ -------
399
+ future : ``concurrent.futures.Future`` object
400
+ """
401
+ # Ensure only one thread creates the executor
402
+ with self._async_executor_lock:
403
+ if self._async_executor is None:
404
+ # Create the executor ONCE
405
+ self._async_executor = ThreadPoolExecutor(
406
+ max_workers=1, thread_name_prefix=f"HoloscanFragment_{self.name}_Async"
407
+ )
408
+
409
+ # Submit the job to the shared executor
410
+ return self._async_executor.submit(self.run)
411
+
412
+ def shutdown_async_executor(self, wait=True):
413
+ """Shuts down the shared asynchronous executor.
414
+
415
+ Call this method when the application instance is no longer needed
416
+ and asynchronous runs initiated by `run_async` should terminate.
417
+
418
+ Parameters
419
+ ----------
420
+ wait : bool
421
+ If True (default), wait for running tasks to complete before shutting down.
422
+ If False, shut down immediately.
423
+ """
424
+ # Use the lock to prevent race conditions with run_async
425
+ with self._async_executor_lock:
426
+ if self._async_executor is not None:
427
+ # Shutting down async executor
428
+ self._async_executor.shutdown(wait=wait)
429
+ self._async_executor = None
430
+
431
+ def start_op(self):
432
+ """Get or create the start operator for this fragment.
433
+
434
+ This operator is nothing but the first operator that was added to the fragment.
435
+ It has the name of `<|start|>` and has a condition of `CountCondition(1)`.
436
+ This Operator is used to start the execution of the fragment.
437
+ Entry operators who want to start the execution of the fragment should connect to this
438
+ operator.
439
+
440
+ If this method is not called, no start operator is created.
441
+ Otherwise, the start operator is created if it does not exist, and the start operator is
442
+ returned.
443
+
444
+ Returns
445
+ -------
446
+ Operator
447
+ The start operator instance. If it doesn't exist, it will be created with
448
+ a CountCondition(1).
449
+ """
450
+ from ..conditions import CountCondition # noqa: PLC0415
451
+
452
+ if not self._start_op:
453
+ self._start_op = Operator(self, CountCondition(self, 1), name=START_OPERATOR_NAME)
454
+ self.add_operator(self._start_op)
455
+ return self._start_op
456
+
457
+ def __del__(self):
458
+ # This is best-effort cleanup, not guaranteed to be called reliably.
459
+ # Avoid potentially blocking calls or complex logic here.
460
+ if getattr(self, "_async_executor", None):
461
+ # Non-blocking shutdown is safer in __del__ if possible,
462
+ # but might leave work unfinished or resources dangling longer.
463
+ # Using wait=False might be preferable here, but check implications.
464
+ try:
465
+ self._async_executor.shutdown(wait=False) # Try non-blocking first
466
+ except Exception as e:
467
+ logger.error(
468
+ f"Error during __del__ executor shutdown for Fragment {self.name}: {e}",
469
+ exc_info=True,
470
+ )
471
+ finally:
472
+ self._async_executor = None
473
+
474
+
475
+ # copy docstrings defined in core_pydoc.hpp
476
+ Fragment.__doc__ = _Fragment.__doc__
477
+ Fragment.__init__.__doc__ = _Fragment.__init__.__doc__
478
+
479
+
480
+ class Operator(_Operator):
481
+ _readonly_attributes = [
482
+ "fragment",
483
+ "conditions",
484
+ "resources",
485
+ "operator_type",
486
+ "description",
487
+ ]
488
+
489
+ def __setattr__(self, name, value):
490
+ if name in self._readonly_attributes:
491
+ raise AttributeError(f'cannot override read-only property "{name}"')
492
+ super().__setattr__(name, value)
493
+
494
+ def __init__(self, fragment, *args, **kwargs):
495
+ if not isinstance(fragment, _Fragment):
496
+ raise ValueError(
497
+ "The first argument to an Operator's constructor must be the Fragment "
498
+ "(Application) to which it belongs."
499
+ )
500
+ # It is recommended to not use super()
501
+ # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
502
+ _Operator.__init__(self, self, fragment, *args, **kwargs)
503
+ # Create a PyOperatorSpec object and pass it to the C++ API
504
+ spec = OperatorSpec(fragment=self.fragment, op=self)
505
+ self.spec = spec
506
+ # Call setup method in PyOperator class
507
+ self.setup(spec)
508
+
509
+ def setup(self, spec: OperatorSpec):
510
+ """Default implementation of setup method."""
511
+ pass
512
+
513
+ def initialize(self):
514
+ """Default implementation of initialize"""
515
+ pass
516
+
517
+ def start(self):
518
+ """Default implementation of start"""
519
+ pass
520
+
521
+ def compute(self, op_input, op_output, context):
522
+ """Default implementation of compute"""
523
+ pass
524
+
525
+ def stop(self):
526
+ """Default implementation of stop"""
527
+ pass
528
+
529
+
530
+ # copy docstrings defined in core_pydoc.hpp
531
+ Operator.__doc__ = _Operator.__doc__
532
+ Operator.__init__.__doc__ = _Operator.__init__.__doc__
533
+
534
+
535
+ class Condition(_Condition):
536
+ _readonly_attributes = [
537
+ "fragment",
538
+ "condition_type",
539
+ "description",
540
+ ]
541
+
542
+ def __setattr__(self, name, value):
543
+ if name in self._readonly_attributes:
544
+ raise AttributeError(f'cannot override read-only property "{name}"')
545
+ super().__setattr__(name, value)
546
+
547
+ def __init__(self, fragment, *args, **kwargs):
548
+ if not isinstance(fragment, _Fragment):
549
+ raise ValueError(
550
+ "The first argument to an Condition's constructor must be the Fragment "
551
+ "(Application) to which it belongs."
552
+ )
553
+ # It is recommended to not use super()
554
+ # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
555
+ _Condition.__init__(self, self, fragment, *args, **kwargs)
556
+ # Create a PyComponentSpec object and pass it to the C++ API
557
+ spec = ComponentSpec(fragment=self.fragment, component=self)
558
+ self.spec = spec
559
+ # Call setup method in PyCondition class
560
+ self.setup(spec)
561
+
562
+ def setup(self, spec: ComponentSpec):
563
+ """Default implementation of setup method."""
564
+ pass
565
+
566
+ def initialize(self):
567
+ """Default implementation of initialize"""
568
+ pass
569
+
570
+ def update_state(self, timestamp):
571
+ """Default implementation of update_state
572
+
573
+ Parameters
574
+ ----------
575
+ timestamp : int
576
+ The timestamp at which the update_state method was called.
577
+
578
+ Notes
579
+ -----
580
+ This method is always called by the underlying GXF framework immediately before the
581
+ `Condition.check` method. In some cases, the `Condition.on_execute` method may also wish
582
+ to call this method.
583
+ """
584
+ pass
585
+
586
+ def check(self, timestamp: int) -> tuple[SchedulingStatusType, int | None]:
587
+ """Default implementation of check.
588
+
589
+ Parameters
590
+ ----------
591
+ timestamp : int
592
+ The timestamp at which the check method is called. This method is called by the
593
+ underlying GXF framework to determine whether an operator is ready to execute.
594
+
595
+ Returns
596
+ -------
597
+ status_type: SchedulingStatusType
598
+ The current status of the operator. See the documentation on native condition
599
+ creation for explanations of the various status types.
600
+ target_timestamp: int or None
601
+ Specifies a specific target timestamp at which the operator is expected to be ready.
602
+ This should only be provided if relevant (it helps the underlying framework avoid
603
+ overhead of repeated checks before the target time).
604
+
605
+ Notes
606
+ -----
607
+ The method should return SchedulingStatusType.READY when the desired condition has been met.
608
+
609
+ The operator will always execute with this default implementation that always execute with
610
+ this default implementation.
611
+ """
612
+ return SchedulingStatusType.READY, None
613
+
614
+ def on_execute(self, timestamp):
615
+ """Default implementation of on_execute
616
+
617
+ Parameters
618
+ ----------
619
+ timestamp : int
620
+ The timestamp at which the on_execute method was called.
621
+
622
+ Notes
623
+ -----
624
+ This method is called by the underlying GXF framework immediately after the
625
+ `Operator.compute` call for the operator to which the condition has been assigned.
626
+ """
627
+ pass
628
+
629
+
630
+ # copy docstrings defined in core_pydoc.hpp
631
+ Condition.__doc__ = _Condition.__doc__
632
+ Condition.__init__.__doc__ = _Condition.__init__.__doc__
633
+
634
+
635
+ class Resource(_Resource):
636
+ _readonly_attributes = [
637
+ "fragment",
638
+ "resource_type",
639
+ "description",
640
+ ]
641
+
642
+ def __setattr__(self, name, value):
643
+ if name in self._readonly_attributes:
644
+ raise AttributeError(f'cannot override read-only property "{name}"')
645
+ super().__setattr__(name, value)
646
+
647
+ def __init__(self, fragment, *args, **kwargs):
648
+ if not isinstance(fragment, _Fragment):
649
+ raise ValueError(
650
+ "The first argument to an Resource's constructor must be the Fragment "
651
+ "(Application) to which it belongs."
652
+ )
653
+ # It is recommended to not use super()
654
+ # (https://pybind11.readthedocs.io/en/stable/advanced/classes.html#overriding-virtual-functions-in-python)
655
+ _Resource.__init__(self, self, fragment, *args, **kwargs)
656
+ # Create a PyComponentSpec object and pass it to the C++ API
657
+ spec = ComponentSpec(fragment=self.fragment, component=self)
658
+ self.spec = spec
659
+ # Call setup method in PyResource class
660
+ self.setup(spec)
661
+
662
+ def setup(self, spec: ComponentSpec):
663
+ """Default implementation of setup method."""
664
+ pass
665
+
666
+
667
+ # copy docstrings defined in core_pydoc.hpp
668
+ Resource.__doc__ = _Resource.__doc__
669
+ Resource.__init__.__doc__ = _Resource.__init__.__doc__
670
+
671
+
672
+ class DefaultFragmentService(_DefaultFragmentService):
673
+ """Base class for fragment services in Python.
674
+
675
+ Provides default implementations of virtual methods to avoid
676
+ infinite recursion issues with pybind11 trampolines.
677
+ """
678
+
679
+ def __init__(self, resource=None, *args, **kwargs):
680
+ """Initialize the fragment service.
681
+
682
+ Parameters
683
+ ----------
684
+ resource : Resource, optional
685
+ The underlying resource for this service.
686
+ """
687
+ # Call the C++ base class constructor
688
+ if resource is not None:
689
+ _DefaultFragmentService.__init__(self, resource, *args, **kwargs)
690
+ else:
691
+ _DefaultFragmentService.__init__(self, *args, **kwargs)
692
+ self._resource_ref = resource
693
+
694
+ def resource(self, new_resource=None):
695
+ """Get or set the underlying Resource associated with this service.
696
+
697
+ This method is called by the C++ backend.
698
+
699
+ Parameters
700
+ ----------
701
+ new_resource : Resource or None
702
+ If provided, sets the resource. If None, acts as getter.
703
+
704
+ Returns
705
+ -------
706
+ Resource or None
707
+ The associated resource when called as a getter.
708
+ """
709
+ if new_resource is not None:
710
+ self._resource_ref = new_resource
711
+ # We also need to call the C++ base class's resource setter
712
+ super().resource(new_resource)
713
+ return self._resource_ref
714
+
715
+
716
+ class Tracker:
717
+ """Context manager to add data flow tracking to an application."""
718
+
719
+ def __init__(
720
+ self,
721
+ app,
722
+ *,
723
+ filename=None,
724
+ num_buffered_messages=100,
725
+ num_start_messages_to_skip=10,
726
+ num_last_messages_to_discard=10,
727
+ latency_threshold=0,
728
+ is_limited_tracking=False,
729
+ ):
730
+ """
731
+ Parameters
732
+ ----------
733
+ app : holoscan.core.Application
734
+ on which flow tracking should be applied.
735
+ filename : str or None, optional
736
+ If none, logging to file will be disabled. Otherwise, logging will
737
+ write to the specified file.
738
+ num_buffered_messages : int, optional
739
+ Controls the number of messages buffered between file writing when
740
+ `filename` is not ``None``.
741
+ num_start_messages_to_skip : int, optional
742
+ The number of messages to skip at the beginning of the execution. This does not affect
743
+ the log file or the number of source messages metric.
744
+ num_last_messages_to_discard : int, optional
745
+ The number of messages to discard at the end of the execution. This does not affect
746
+ the log file or the number of source messages metric.
747
+ latency_threshold : int, optional
748
+ The minimum end-to-end latency in milliseconds to account for in the end-to-end
749
+ latency metric calculations.
750
+ is_limited_tracking : bool, optional
751
+ If true, the tracking is limited to root and leaf nodes, minimizing the timestamps by
752
+ avoiding intermediate operators.
753
+ """
754
+ self.app = app
755
+
756
+ # Check the number of fragment nodes to see if it is a distributed app.
757
+ # Use compose_graph(), not compose() to protect against repeated compose() calls.
758
+ self.app.compose_graph()
759
+ self.is_distributed_app = len(app.fragment_graph.get_nodes()) > 0
760
+
761
+ self.enable_logging = filename is not None
762
+ if self.enable_logging:
763
+ self.logging_kwargs = dict(
764
+ filename=filename,
765
+ num_buffered_messages=num_buffered_messages,
766
+ )
767
+ self.tracker_kwargs = dict(
768
+ num_start_messages_to_skip=num_start_messages_to_skip,
769
+ num_last_messages_to_discard=num_last_messages_to_discard,
770
+ latency_threshold=latency_threshold,
771
+ is_limited_tracking=is_limited_tracking,
772
+ )
773
+
774
+ def __enter__(self):
775
+ if self.is_distributed_app:
776
+ self.trackers = self.app.track_distributed(**self.tracker_kwargs)
777
+ for tracker in self.trackers.values():
778
+ if self.enable_logging:
779
+ tracker.enable_logging(**self.logging_kwargs)
780
+ return self.trackers
781
+ else:
782
+ self.tracker = self.app.track(**self.tracker_kwargs)
783
+ if self.enable_logging:
784
+ self.tracker.enable_logging(**self.logging_kwargs)
785
+ return self.tracker
786
+
787
+ def __exit__(self, exc_type, exc_value, exc_tb):
788
+ if self.enable_logging:
789
+ if self.is_distributed_app:
790
+ for tracker in self.trackers.values():
791
+ tracker.end_logging()
792
+ else:
793
+ self.tracker.end_logging()
794
+
795
+
796
+ _registry_context = _RegistryContext()
797
+ io_type_registry = _registry_context.registry()
798
+
799
+ _register_types(io_type_registry)