flyte 0.0.1b0__py3-none-any.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.

Potentially problematic release.


This version of flyte might be problematic. Click here for more details.

Files changed (390) hide show
  1. flyte/__init__.py +62 -0
  2. flyte/_api_commons.py +3 -0
  3. flyte/_bin/__init__.py +0 -0
  4. flyte/_bin/runtime.py +126 -0
  5. flyte/_build.py +25 -0
  6. flyte/_cache/__init__.py +12 -0
  7. flyte/_cache/cache.py +146 -0
  8. flyte/_cache/defaults.py +9 -0
  9. flyte/_cache/policy_function_body.py +42 -0
  10. flyte/_cli/__init__.py +0 -0
  11. flyte/_cli/_common.py +287 -0
  12. flyte/_cli/_create.py +42 -0
  13. flyte/_cli/_delete.py +23 -0
  14. flyte/_cli/_deploy.py +140 -0
  15. flyte/_cli/_get.py +235 -0
  16. flyte/_cli/_run.py +152 -0
  17. flyte/_cli/main.py +72 -0
  18. flyte/_code_bundle/__init__.py +8 -0
  19. flyte/_code_bundle/_ignore.py +113 -0
  20. flyte/_code_bundle/_packaging.py +187 -0
  21. flyte/_code_bundle/_utils.py +339 -0
  22. flyte/_code_bundle/bundle.py +178 -0
  23. flyte/_context.py +146 -0
  24. flyte/_datastructures.py +342 -0
  25. flyte/_deploy.py +202 -0
  26. flyte/_doc.py +29 -0
  27. flyte/_docstring.py +32 -0
  28. flyte/_environment.py +43 -0
  29. flyte/_group.py +31 -0
  30. flyte/_hash.py +23 -0
  31. flyte/_image.py +760 -0
  32. flyte/_initialize.py +634 -0
  33. flyte/_interface.py +84 -0
  34. flyte/_internal/__init__.py +3 -0
  35. flyte/_internal/controllers/__init__.py +115 -0
  36. flyte/_internal/controllers/_local_controller.py +118 -0
  37. flyte/_internal/controllers/_trace.py +40 -0
  38. flyte/_internal/controllers/pbhash.py +39 -0
  39. flyte/_internal/controllers/remote/__init__.py +40 -0
  40. flyte/_internal/controllers/remote/_action.py +141 -0
  41. flyte/_internal/controllers/remote/_client.py +43 -0
  42. flyte/_internal/controllers/remote/_controller.py +361 -0
  43. flyte/_internal/controllers/remote/_core.py +402 -0
  44. flyte/_internal/controllers/remote/_informer.py +361 -0
  45. flyte/_internal/controllers/remote/_service_protocol.py +50 -0
  46. flyte/_internal/imagebuild/__init__.py +11 -0
  47. flyte/_internal/imagebuild/docker_builder.py +416 -0
  48. flyte/_internal/imagebuild/image_builder.py +241 -0
  49. flyte/_internal/imagebuild/remote_builder.py +0 -0
  50. flyte/_internal/resolvers/__init__.py +0 -0
  51. flyte/_internal/resolvers/_task_module.py +54 -0
  52. flyte/_internal/resolvers/common.py +31 -0
  53. flyte/_internal/resolvers/default.py +28 -0
  54. flyte/_internal/runtime/__init__.py +0 -0
  55. flyte/_internal/runtime/convert.py +199 -0
  56. flyte/_internal/runtime/entrypoints.py +135 -0
  57. flyte/_internal/runtime/io.py +136 -0
  58. flyte/_internal/runtime/resources_serde.py +138 -0
  59. flyte/_internal/runtime/task_serde.py +210 -0
  60. flyte/_internal/runtime/taskrunner.py +190 -0
  61. flyte/_internal/runtime/types_serde.py +54 -0
  62. flyte/_logging.py +124 -0
  63. flyte/_protos/__init__.py +0 -0
  64. flyte/_protos/common/authorization_pb2.py +66 -0
  65. flyte/_protos/common/authorization_pb2.pyi +108 -0
  66. flyte/_protos/common/authorization_pb2_grpc.py +4 -0
  67. flyte/_protos/common/identifier_pb2.py +71 -0
  68. flyte/_protos/common/identifier_pb2.pyi +82 -0
  69. flyte/_protos/common/identifier_pb2_grpc.py +4 -0
  70. flyte/_protos/common/identity_pb2.py +48 -0
  71. flyte/_protos/common/identity_pb2.pyi +72 -0
  72. flyte/_protos/common/identity_pb2_grpc.py +4 -0
  73. flyte/_protos/common/list_pb2.py +36 -0
  74. flyte/_protos/common/list_pb2.pyi +69 -0
  75. flyte/_protos/common/list_pb2_grpc.py +4 -0
  76. flyte/_protos/common/policy_pb2.py +37 -0
  77. flyte/_protos/common/policy_pb2.pyi +27 -0
  78. flyte/_protos/common/policy_pb2_grpc.py +4 -0
  79. flyte/_protos/common/role_pb2.py +37 -0
  80. flyte/_protos/common/role_pb2.pyi +53 -0
  81. flyte/_protos/common/role_pb2_grpc.py +4 -0
  82. flyte/_protos/common/runtime_version_pb2.py +28 -0
  83. flyte/_protos/common/runtime_version_pb2.pyi +24 -0
  84. flyte/_protos/common/runtime_version_pb2_grpc.py +4 -0
  85. flyte/_protos/logs/dataplane/payload_pb2.py +96 -0
  86. flyte/_protos/logs/dataplane/payload_pb2.pyi +168 -0
  87. flyte/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
  88. flyte/_protos/secret/definition_pb2.py +49 -0
  89. flyte/_protos/secret/definition_pb2.pyi +93 -0
  90. flyte/_protos/secret/definition_pb2_grpc.py +4 -0
  91. flyte/_protos/secret/payload_pb2.py +62 -0
  92. flyte/_protos/secret/payload_pb2.pyi +94 -0
  93. flyte/_protos/secret/payload_pb2_grpc.py +4 -0
  94. flyte/_protos/secret/secret_pb2.py +38 -0
  95. flyte/_protos/secret/secret_pb2.pyi +6 -0
  96. flyte/_protos/secret/secret_pb2_grpc.py +198 -0
  97. flyte/_protos/secret/secret_pb2_grpc_grpc.py +198 -0
  98. flyte/_protos/validate/validate/validate_pb2.py +76 -0
  99. flyte/_protos/workflow/node_execution_service_pb2.py +26 -0
  100. flyte/_protos/workflow/node_execution_service_pb2.pyi +4 -0
  101. flyte/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
  102. flyte/_protos/workflow/queue_service_pb2.py +106 -0
  103. flyte/_protos/workflow/queue_service_pb2.pyi +141 -0
  104. flyte/_protos/workflow/queue_service_pb2_grpc.py +172 -0
  105. flyte/_protos/workflow/run_definition_pb2.py +128 -0
  106. flyte/_protos/workflow/run_definition_pb2.pyi +310 -0
  107. flyte/_protos/workflow/run_definition_pb2_grpc.py +4 -0
  108. flyte/_protos/workflow/run_logs_service_pb2.py +41 -0
  109. flyte/_protos/workflow/run_logs_service_pb2.pyi +28 -0
  110. flyte/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
  111. flyte/_protos/workflow/run_service_pb2.py +133 -0
  112. flyte/_protos/workflow/run_service_pb2.pyi +175 -0
  113. flyte/_protos/workflow/run_service_pb2_grpc.py +412 -0
  114. flyte/_protos/workflow/state_service_pb2.py +58 -0
  115. flyte/_protos/workflow/state_service_pb2.pyi +71 -0
  116. flyte/_protos/workflow/state_service_pb2_grpc.py +138 -0
  117. flyte/_protos/workflow/task_definition_pb2.py +72 -0
  118. flyte/_protos/workflow/task_definition_pb2.pyi +65 -0
  119. flyte/_protos/workflow/task_definition_pb2_grpc.py +4 -0
  120. flyte/_protos/workflow/task_service_pb2.py +44 -0
  121. flyte/_protos/workflow/task_service_pb2.pyi +31 -0
  122. flyte/_protos/workflow/task_service_pb2_grpc.py +104 -0
  123. flyte/_resources.py +226 -0
  124. flyte/_retry.py +32 -0
  125. flyte/_reusable_environment.py +25 -0
  126. flyte/_run.py +411 -0
  127. flyte/_secret.py +61 -0
  128. flyte/_task.py +367 -0
  129. flyte/_task_environment.py +200 -0
  130. flyte/_timeout.py +47 -0
  131. flyte/_tools.py +27 -0
  132. flyte/_trace.py +128 -0
  133. flyte/_utils/__init__.py +20 -0
  134. flyte/_utils/asyn.py +119 -0
  135. flyte/_utils/coro_management.py +25 -0
  136. flyte/_utils/file_handling.py +72 -0
  137. flyte/_utils/helpers.py +108 -0
  138. flyte/_utils/lazy_module.py +54 -0
  139. flyte/_utils/uv_script_parser.py +49 -0
  140. flyte/_version.py +21 -0
  141. flyte/connectors/__init__.py +0 -0
  142. flyte/errors.py +143 -0
  143. flyte/extras/__init__.py +5 -0
  144. flyte/extras/_container.py +273 -0
  145. flyte/io/__init__.py +11 -0
  146. flyte/io/_dataframe.py +0 -0
  147. flyte/io/_dir.py +448 -0
  148. flyte/io/_file.py +468 -0
  149. flyte/io/pickle/__init__.py +0 -0
  150. flyte/io/pickle/transformer.py +117 -0
  151. flyte/io/structured_dataset/__init__.py +129 -0
  152. flyte/io/structured_dataset/basic_dfs.py +219 -0
  153. flyte/io/structured_dataset/structured_dataset.py +1061 -0
  154. flyte/py.typed +0 -0
  155. flyte/remote/__init__.py +25 -0
  156. flyte/remote/_client/__init__.py +0 -0
  157. flyte/remote/_client/_protocols.py +131 -0
  158. flyte/remote/_client/auth/__init__.py +12 -0
  159. flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
  160. flyte/remote/_client/auth/_authenticators/base.py +397 -0
  161. flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
  162. flyte/remote/_client/auth/_authenticators/device_code.py +118 -0
  163. flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
  164. flyte/remote/_client/auth/_authenticators/factory.py +200 -0
  165. flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
  166. flyte/remote/_client/auth/_channel.py +184 -0
  167. flyte/remote/_client/auth/_client_config.py +83 -0
  168. flyte/remote/_client/auth/_default_html.py +32 -0
  169. flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  170. flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
  171. flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
  172. flyte/remote/_client/auth/_keyring.py +143 -0
  173. flyte/remote/_client/auth/_token_client.py +260 -0
  174. flyte/remote/_client/auth/errors.py +16 -0
  175. flyte/remote/_client/controlplane.py +95 -0
  176. flyte/remote/_console.py +18 -0
  177. flyte/remote/_data.py +155 -0
  178. flyte/remote/_logs.py +116 -0
  179. flyte/remote/_project.py +86 -0
  180. flyte/remote/_run.py +873 -0
  181. flyte/remote/_secret.py +132 -0
  182. flyte/remote/_task.py +227 -0
  183. flyte/report/__init__.py +3 -0
  184. flyte/report/_report.py +178 -0
  185. flyte/report/_template.html +124 -0
  186. flyte/storage/__init__.py +24 -0
  187. flyte/storage/_remote_fs.py +34 -0
  188. flyte/storage/_storage.py +251 -0
  189. flyte/storage/_utils.py +5 -0
  190. flyte/types/__init__.py +13 -0
  191. flyte/types/_interface.py +25 -0
  192. flyte/types/_renderer.py +162 -0
  193. flyte/types/_string_literals.py +120 -0
  194. flyte/types/_type_engine.py +2210 -0
  195. flyte/types/_utils.py +80 -0
  196. flyte-0.0.1b0.dist-info/METADATA +179 -0
  197. flyte-0.0.1b0.dist-info/RECORD +390 -0
  198. flyte-0.0.1b0.dist-info/WHEEL +5 -0
  199. flyte-0.0.1b0.dist-info/entry_points.txt +3 -0
  200. flyte-0.0.1b0.dist-info/top_level.txt +1 -0
  201. union/__init__.py +54 -0
  202. union/_api_commons.py +3 -0
  203. union/_bin/__init__.py +0 -0
  204. union/_bin/runtime.py +113 -0
  205. union/_build.py +25 -0
  206. union/_cache/__init__.py +12 -0
  207. union/_cache/cache.py +141 -0
  208. union/_cache/defaults.py +9 -0
  209. union/_cache/policy_function_body.py +42 -0
  210. union/_cli/__init__.py +0 -0
  211. union/_cli/_common.py +263 -0
  212. union/_cli/_create.py +40 -0
  213. union/_cli/_delete.py +23 -0
  214. union/_cli/_deploy.py +120 -0
  215. union/_cli/_get.py +162 -0
  216. union/_cli/_params.py +579 -0
  217. union/_cli/_run.py +150 -0
  218. union/_cli/main.py +72 -0
  219. union/_code_bundle/__init__.py +8 -0
  220. union/_code_bundle/_ignore.py +113 -0
  221. union/_code_bundle/_packaging.py +187 -0
  222. union/_code_bundle/_utils.py +342 -0
  223. union/_code_bundle/bundle.py +176 -0
  224. union/_context.py +146 -0
  225. union/_datastructures.py +295 -0
  226. union/_deploy.py +185 -0
  227. union/_doc.py +29 -0
  228. union/_docstring.py +26 -0
  229. union/_environment.py +43 -0
  230. union/_group.py +31 -0
  231. union/_hash.py +23 -0
  232. union/_image.py +760 -0
  233. union/_initialize.py +585 -0
  234. union/_interface.py +84 -0
  235. union/_internal/__init__.py +3 -0
  236. union/_internal/controllers/__init__.py +77 -0
  237. union/_internal/controllers/_local_controller.py +77 -0
  238. union/_internal/controllers/pbhash.py +39 -0
  239. union/_internal/controllers/remote/__init__.py +40 -0
  240. union/_internal/controllers/remote/_action.py +131 -0
  241. union/_internal/controllers/remote/_client.py +43 -0
  242. union/_internal/controllers/remote/_controller.py +169 -0
  243. union/_internal/controllers/remote/_core.py +341 -0
  244. union/_internal/controllers/remote/_informer.py +260 -0
  245. union/_internal/controllers/remote/_service_protocol.py +44 -0
  246. union/_internal/imagebuild/__init__.py +11 -0
  247. union/_internal/imagebuild/docker_builder.py +416 -0
  248. union/_internal/imagebuild/image_builder.py +243 -0
  249. union/_internal/imagebuild/remote_builder.py +0 -0
  250. union/_internal/resolvers/__init__.py +0 -0
  251. union/_internal/resolvers/_task_module.py +31 -0
  252. union/_internal/resolvers/common.py +24 -0
  253. union/_internal/resolvers/default.py +27 -0
  254. union/_internal/runtime/__init__.py +0 -0
  255. union/_internal/runtime/convert.py +163 -0
  256. union/_internal/runtime/entrypoints.py +121 -0
  257. union/_internal/runtime/io.py +136 -0
  258. union/_internal/runtime/resources_serde.py +134 -0
  259. union/_internal/runtime/task_serde.py +202 -0
  260. union/_internal/runtime/taskrunner.py +179 -0
  261. union/_internal/runtime/types_serde.py +53 -0
  262. union/_logging.py +124 -0
  263. union/_protos/__init__.py +0 -0
  264. union/_protos/common/authorization_pb2.py +66 -0
  265. union/_protos/common/authorization_pb2.pyi +106 -0
  266. union/_protos/common/authorization_pb2_grpc.py +4 -0
  267. union/_protos/common/identifier_pb2.py +71 -0
  268. union/_protos/common/identifier_pb2.pyi +82 -0
  269. union/_protos/common/identifier_pb2_grpc.py +4 -0
  270. union/_protos/common/identity_pb2.py +48 -0
  271. union/_protos/common/identity_pb2.pyi +72 -0
  272. union/_protos/common/identity_pb2_grpc.py +4 -0
  273. union/_protos/common/list_pb2.py +36 -0
  274. union/_protos/common/list_pb2.pyi +69 -0
  275. union/_protos/common/list_pb2_grpc.py +4 -0
  276. union/_protos/common/policy_pb2.py +37 -0
  277. union/_protos/common/policy_pb2.pyi +27 -0
  278. union/_protos/common/policy_pb2_grpc.py +4 -0
  279. union/_protos/common/role_pb2.py +37 -0
  280. union/_protos/common/role_pb2.pyi +51 -0
  281. union/_protos/common/role_pb2_grpc.py +4 -0
  282. union/_protos/common/runtime_version_pb2.py +28 -0
  283. union/_protos/common/runtime_version_pb2.pyi +24 -0
  284. union/_protos/common/runtime_version_pb2_grpc.py +4 -0
  285. union/_protos/logs/dataplane/payload_pb2.py +96 -0
  286. union/_protos/logs/dataplane/payload_pb2.pyi +168 -0
  287. union/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
  288. union/_protos/secret/definition_pb2.py +49 -0
  289. union/_protos/secret/definition_pb2.pyi +93 -0
  290. union/_protos/secret/definition_pb2_grpc.py +4 -0
  291. union/_protos/secret/payload_pb2.py +62 -0
  292. union/_protos/secret/payload_pb2.pyi +94 -0
  293. union/_protos/secret/payload_pb2_grpc.py +4 -0
  294. union/_protos/secret/secret_pb2.py +38 -0
  295. union/_protos/secret/secret_pb2.pyi +6 -0
  296. union/_protos/secret/secret_pb2_grpc.py +198 -0
  297. union/_protos/validate/validate/validate_pb2.py +76 -0
  298. union/_protos/workflow/node_execution_service_pb2.py +26 -0
  299. union/_protos/workflow/node_execution_service_pb2.pyi +4 -0
  300. union/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
  301. union/_protos/workflow/queue_service_pb2.py +75 -0
  302. union/_protos/workflow/queue_service_pb2.pyi +103 -0
  303. union/_protos/workflow/queue_service_pb2_grpc.py +172 -0
  304. union/_protos/workflow/run_definition_pb2.py +100 -0
  305. union/_protos/workflow/run_definition_pb2.pyi +256 -0
  306. union/_protos/workflow/run_definition_pb2_grpc.py +4 -0
  307. union/_protos/workflow/run_logs_service_pb2.py +41 -0
  308. union/_protos/workflow/run_logs_service_pb2.pyi +28 -0
  309. union/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
  310. union/_protos/workflow/run_service_pb2.py +133 -0
  311. union/_protos/workflow/run_service_pb2.pyi +173 -0
  312. union/_protos/workflow/run_service_pb2_grpc.py +412 -0
  313. union/_protos/workflow/state_service_pb2.py +58 -0
  314. union/_protos/workflow/state_service_pb2.pyi +69 -0
  315. union/_protos/workflow/state_service_pb2_grpc.py +138 -0
  316. union/_protos/workflow/task_definition_pb2.py +72 -0
  317. union/_protos/workflow/task_definition_pb2.pyi +65 -0
  318. union/_protos/workflow/task_definition_pb2_grpc.py +4 -0
  319. union/_protos/workflow/task_service_pb2.py +44 -0
  320. union/_protos/workflow/task_service_pb2.pyi +31 -0
  321. union/_protos/workflow/task_service_pb2_grpc.py +104 -0
  322. union/_resources.py +226 -0
  323. union/_retry.py +32 -0
  324. union/_reusable_environment.py +25 -0
  325. union/_run.py +374 -0
  326. union/_secret.py +61 -0
  327. union/_task.py +354 -0
  328. union/_task_environment.py +186 -0
  329. union/_timeout.py +47 -0
  330. union/_tools.py +27 -0
  331. union/_utils/__init__.py +11 -0
  332. union/_utils/asyn.py +119 -0
  333. union/_utils/file_handling.py +71 -0
  334. union/_utils/helpers.py +46 -0
  335. union/_utils/lazy_module.py +54 -0
  336. union/_utils/uv_script_parser.py +49 -0
  337. union/_version.py +21 -0
  338. union/connectors/__init__.py +0 -0
  339. union/errors.py +128 -0
  340. union/extras/__init__.py +5 -0
  341. union/extras/_container.py +263 -0
  342. union/io/__init__.py +11 -0
  343. union/io/_dataframe.py +0 -0
  344. union/io/_dir.py +425 -0
  345. union/io/_file.py +418 -0
  346. union/io/pickle/__init__.py +0 -0
  347. union/io/pickle/transformer.py +117 -0
  348. union/io/structured_dataset/__init__.py +122 -0
  349. union/io/structured_dataset/basic_dfs.py +219 -0
  350. union/io/structured_dataset/structured_dataset.py +1057 -0
  351. union/py.typed +0 -0
  352. union/remote/__init__.py +23 -0
  353. union/remote/_client/__init__.py +0 -0
  354. union/remote/_client/_protocols.py +129 -0
  355. union/remote/_client/auth/__init__.py +12 -0
  356. union/remote/_client/auth/_authenticators/__init__.py +0 -0
  357. union/remote/_client/auth/_authenticators/base.py +391 -0
  358. union/remote/_client/auth/_authenticators/client_credentials.py +73 -0
  359. union/remote/_client/auth/_authenticators/device_code.py +120 -0
  360. union/remote/_client/auth/_authenticators/external_command.py +77 -0
  361. union/remote/_client/auth/_authenticators/factory.py +200 -0
  362. union/remote/_client/auth/_authenticators/pkce.py +515 -0
  363. union/remote/_client/auth/_channel.py +184 -0
  364. union/remote/_client/auth/_client_config.py +83 -0
  365. union/remote/_client/auth/_default_html.py +32 -0
  366. union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  367. union/remote/_client/auth/_grpc_utils/auth_interceptor.py +204 -0
  368. union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +144 -0
  369. union/remote/_client/auth/_keyring.py +154 -0
  370. union/remote/_client/auth/_token_client.py +258 -0
  371. union/remote/_client/auth/errors.py +16 -0
  372. union/remote/_client/controlplane.py +86 -0
  373. union/remote/_data.py +149 -0
  374. union/remote/_logs.py +74 -0
  375. union/remote/_project.py +86 -0
  376. union/remote/_run.py +820 -0
  377. union/remote/_secret.py +132 -0
  378. union/remote/_task.py +193 -0
  379. union/report/__init__.py +3 -0
  380. union/report/_report.py +178 -0
  381. union/report/_template.html +124 -0
  382. union/storage/__init__.py +24 -0
  383. union/storage/_remote_fs.py +34 -0
  384. union/storage/_storage.py +247 -0
  385. union/storage/_utils.py +5 -0
  386. union/types/__init__.py +11 -0
  387. union/types/_renderer.py +162 -0
  388. union/types/_string_literals.py +120 -0
  389. union/types/_type_engine.py +2131 -0
  390. union/types/_utils.py +80 -0
flyte/remote/_run.py ADDED
@@ -0,0 +1,873 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from dataclasses import dataclass, field
5
+ from datetime import datetime, timedelta, timezone
6
+ from typing import AsyncGenerator, AsyncIterator, Iterator, Literal, Tuple, Union, cast
7
+
8
+ import grpc
9
+ import rich.repr
10
+ from google.protobuf import timestamp
11
+ from rich.console import Console
12
+ from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
13
+
14
+ from flyte._api_commons import syncer
15
+ from flyte._initialize import get_client, get_common_config, requires_client
16
+ from flyte._protos.common import identifier_pb2, list_pb2
17
+ from flyte._protos.workflow import run_definition_pb2, run_service_pb2
18
+
19
+ from .._protos.workflow.run_service_pb2 import WatchActionDetailsResponse
20
+ from ._console import get_run_url
21
+ from ._logs import Logs
22
+
23
+
24
+ def _action_time_phase(action: run_definition_pb2.Action | run_definition_pb2.ActionDetails) -> rich.repr.Result:
25
+ """
26
+ Rich representation of the action time and phase.
27
+ """
28
+ start_time = timestamp.to_datetime(action.status.start_time, timezone.utc)
29
+ yield "start_time", start_time.isoformat()
30
+ if action.status.phase in [
31
+ run_definition_pb2.PHASE_FAILED,
32
+ run_definition_pb2.PHASE_SUCCEEDED,
33
+ run_definition_pb2.PHASE_ABORTED,
34
+ run_definition_pb2.PHASE_TIMED_OUT,
35
+ ]:
36
+ end_time = timestamp.to_datetime(action.status.end_time, timezone.utc)
37
+ yield "end_time", end_time.isoformat()
38
+ yield "run_time", f"{(end_time - start_time).seconds} secs"
39
+ else:
40
+ yield "end_time", None
41
+ yield "run_time", f"{(datetime.now(timezone.utc) - start_time).seconds} secs"
42
+ yield "phase", run_definition_pb2.Phase.Name(action.status.phase)
43
+ if isinstance(action, run_definition_pb2.ActionDetails):
44
+ yield "error", action.error_info if action.HasField("error_info") else "NA"
45
+
46
+
47
+ def _action_rich_repr(action: run_definition_pb2.Action, root: bool = False) -> rich.repr.Result:
48
+ """
49
+ Rich representation of the action.
50
+ """
51
+ yield "run-name", action.id.run.name
52
+ yield "name", action.id.name
53
+ yield from _action_time_phase(action)
54
+ yield "task", action.metadata.task.id.name
55
+ if not root:
56
+ yield "group", action.metadata.group
57
+ yield "parent", action.metadata.parent
58
+
59
+
60
+ def _action_details_rich_repr(action: run_definition_pb2.ActionDetails, root: bool = False) -> rich.repr.Result:
61
+ """
62
+ Rich representation of the action details.
63
+ """
64
+ yield "name", action.id.run.name
65
+ yield from _action_time_phase(action)
66
+ # yield "task", action.metadata.task.id.name
67
+ yield "task", action.resolved_task_spec.task_template.id.name
68
+ yield "task_type", action.resolved_task_spec.task_template.type
69
+ yield "task_version", action.resolved_task_spec.task_template.id.version
70
+ if not root:
71
+ yield "group", action.metadata.group
72
+ yield "parent", action.metadata.parent
73
+ # TODO attempt info
74
+
75
+
76
+ def _action_done_check(phase: run_definition_pb2.Phase) -> bool:
77
+ """
78
+ Check if the action is done.
79
+ """
80
+ return phase in [
81
+ run_definition_pb2.PHASE_FAILED,
82
+ run_definition_pb2.PHASE_SUCCEEDED,
83
+ run_definition_pb2.PHASE_ABORTED,
84
+ run_definition_pb2.PHASE_TIMED_OUT,
85
+ ]
86
+
87
+
88
+ @dataclass
89
+ class Run:
90
+ """
91
+ A class representing a run of a task. It is used to manage the run of a task and its state on the remote
92
+ Union API.
93
+ """
94
+
95
+ pb2: run_definition_pb2.Run
96
+ action: Action = field(init=False)
97
+ _details: RunDetails | None = None
98
+
99
+ def __post_init__(self):
100
+ """
101
+ Initialize the Run object with the given run definition.
102
+ """
103
+ if not self.pb2.HasField("action"):
104
+ raise RuntimeError("Run does not have an action")
105
+ self.action = Action(self.pb2.action)
106
+
107
+ @classmethod
108
+ @requires_client
109
+ @syncer.wrap
110
+ async def listall(
111
+ cls,
112
+ filters: str | None = None,
113
+ sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
114
+ ) -> Union[Iterator[Run], AsyncGenerator[Run, None]]:
115
+ """
116
+ Get all runs for the current project and domain.
117
+
118
+ :param filters: The filters to apply to the project list.
119
+ :param sort_by: The sorting criteria for the project list, in the format (field, order).
120
+ :return: An iterator of runs.
121
+ """
122
+ token = None
123
+ sort_by = sort_by or ("created_at", "asc")
124
+ sort_pb2 = list_pb2.Sort(
125
+ key=sort_by[0], direction=list_pb2.Sort.ASCENDING if sort_by[1] == "asc" else list_pb2.Sort.DESCENDING
126
+ )
127
+ cfg = get_common_config()
128
+ while True:
129
+ req = list_pb2.ListRequest(
130
+ limit=100,
131
+ token=token,
132
+ sort_by=sort_pb2,
133
+ )
134
+ resp = await get_client().run_service.ListRuns(
135
+ run_service_pb2.ListRunsRequest(
136
+ request=req,
137
+ org=cfg.org,
138
+ project_id=identifier_pb2.ProjectIdentifier(
139
+ organization=cfg.org,
140
+ domain=cfg.domain,
141
+ name=cfg.project,
142
+ ),
143
+ )
144
+ )
145
+ token = resp.token
146
+ for r in resp.runs:
147
+ yield cls(r)
148
+ if not token:
149
+ break
150
+
151
+ @classmethod
152
+ @requires_client
153
+ @syncer.wrap
154
+ async def get(cls, name: str) -> Run:
155
+ """
156
+ Get the current run.
157
+
158
+ :return: The current run.
159
+ """
160
+ run_details: RunDetails = await RunDetails.get.aio(RunDetails, name=name)
161
+ run = run_definition_pb2.Run(
162
+ action=run_definition_pb2.Action(
163
+ id=run_details.action_id,
164
+ metadata=run_details.action_details.pb2.metadata,
165
+ status=run_details.action_details.pb2.status,
166
+ ),
167
+ )
168
+ return cls(pb2=run, _details=run_details)
169
+
170
+ @property
171
+ def name(self) -> str:
172
+ """
173
+ Get the name of the run.
174
+ """
175
+ return self.pb2.action.id.run.name
176
+
177
+ @property
178
+ def phase(self) -> str:
179
+ """
180
+ Get the phase of the run.
181
+ """
182
+ return run_definition_pb2.Phase.Name(self.action.phase)
183
+
184
+ @syncer.wrap
185
+ async def wait(self, quiet: bool = False) -> None:
186
+ """
187
+ Wait for the run to complete, displaying a rich progress panel with status transitions,
188
+ time elapsed, and error details in case of failure.
189
+ """
190
+ console = Console()
191
+ if self.done():
192
+ if not quiet:
193
+ console.print(f"[bold green]Run '{self.name}' is already completed.[/bold green]")
194
+ return
195
+
196
+ try:
197
+ with Progress(
198
+ SpinnerColumn(),
199
+ TextColumn("[progress.description]{task.description}"),
200
+ TimeElapsedColumn(),
201
+ console=console,
202
+ transient=True,
203
+ disable=quiet,
204
+ ) as progress:
205
+ task_id = progress.add_task(f"Waiting for run '{self.name}'...", start=False)
206
+
207
+ async for ad in self.watch(cache_data_on_done=True):
208
+ if ad is None:
209
+ break
210
+
211
+ # Update progress description with the current phase
212
+ progress.update(
213
+ task_id,
214
+ description=f"Run: {self.name} in {ad.phase}, Runtime: {ad.runtime} secs "
215
+ f"Attempts[{ad.attempts}]",
216
+ )
217
+ progress.start_task(task_id)
218
+
219
+ # If the action is done, handle the final state
220
+ if ad.done():
221
+ progress.stop_task(task_id)
222
+ if ad.pb2.status.phase == run_definition_pb2.PHASE_SUCCEEDED:
223
+ console.print(f"[bold green]Run '{self.name}' completed successfully.[/bold green]")
224
+ else:
225
+ console.print(
226
+ f"[bold red]Run '{self.name}' exited unsuccessfully in state {ad.phase}"
227
+ f"with error: {ad.error_info}[/bold red]"
228
+ )
229
+ break
230
+ except asyncio.CancelledError:
231
+ # Handle cancellation gracefully
232
+ pass
233
+ except KeyboardInterrupt:
234
+ # Handle keyboard interrupt gracefully
235
+ console.print(f"\n[bold yellow]Run '{self.name}' was interrupted.[/bold yellow]")
236
+
237
+ async def watch(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
238
+ """
239
+ Get the details of the run. This is a placeholder for getting the run details.
240
+ """
241
+ async for ad in self.action.watch_details(cache_data_on_done=cache_data_on_done):
242
+ if ad is None:
243
+ return
244
+ yield ad
245
+
246
+ async def show_logs(self, attempt: int = 1, max_lines: int = 100, show_ts: bool = False, raw: bool = False):
247
+ return await Logs.create_viewer(
248
+ action_id=self.action.action_id,
249
+ attempt=attempt,
250
+ max_lines=max_lines,
251
+ show_ts=show_ts,
252
+ raw=raw,
253
+ )
254
+
255
+ async def details(self) -> RunDetails:
256
+ """
257
+ Get the details of the run. This is a placeholder for getting the run details.
258
+ """
259
+ if self._details is None:
260
+ self._details = await RunDetails.get_details(RunDetails, self.pb2.action.id.run)
261
+ return self._details
262
+
263
+ @property
264
+ @requires_client
265
+ def url(self) -> str:
266
+ """
267
+ Get the URL of the run.
268
+ """
269
+ client = get_client()
270
+ return get_run_url(
271
+ client.endpoint,
272
+ insecure=client.insecure,
273
+ project=self.pb2.action.id.run.project,
274
+ domain=self.pb2.action.id.run.domain,
275
+ run_name=self.name,
276
+ )
277
+
278
+ @syncer.wrap
279
+ async def cancel(self) -> None:
280
+ """
281
+ Cancel the run.
282
+ """
283
+ await get_client().run_service.AbortRun(
284
+ run_service_pb2.AbortRunRequest(
285
+ run_id=self.pb2.action.id.run,
286
+ )
287
+ )
288
+
289
+ def done(self) -> bool:
290
+ """
291
+ Check if the run is done.
292
+ """
293
+ return self.action.done()
294
+
295
+ def sync(self) -> Run:
296
+ """
297
+ Sync the run with the remote server. This is a placeholder for syncing the run.
298
+ """
299
+ return self
300
+
301
+ # TODO add add_done_callback, maybe implement sync apis etc
302
+
303
+ def __rich_repr__(self) -> rich.repr.Result:
304
+ """
305
+ Rich representation of the Run object.
306
+ """
307
+ yield from _action_rich_repr(self.pb2.action, root=True)
308
+
309
+ def __repr__(self) -> str:
310
+ """
311
+ String representation of the Action object.
312
+ """
313
+ import rich.pretty
314
+
315
+ return rich.pretty.pretty_repr(self)
316
+
317
+
318
+ @dataclass
319
+ class RunDetails:
320
+ """
321
+ A class representing a run of a task. It is used to manage the run of a task and its state on the remote
322
+ Union API.
323
+ """
324
+
325
+ pb2: run_definition_pb2.RunDetails
326
+ action_details: ActionDetails = field(init=False)
327
+
328
+ def __post_init__(self):
329
+ """
330
+ Initialize the RunDetails object with the given run definition.
331
+ """
332
+ self.action_details = ActionDetails(self.pb2.action)
333
+
334
+ @classmethod
335
+ @requires_client
336
+ @syncer.wrap
337
+ async def get_details(cls, run_id: run_definition_pb2.RunIdentifier) -> RunDetails:
338
+ """
339
+ Get the details of the run. This is a placeholder for getting the run details.
340
+ """
341
+ resp = await get_client().run_service.GetRunDetails(
342
+ run_service_pb2.GetRunDetailsRequest(
343
+ run_id=run_id,
344
+ )
345
+ )
346
+ return cls(resp.details)
347
+
348
+ @classmethod
349
+ @requires_client
350
+ @syncer.wrap
351
+ async def get(cls, name: str | None = None) -> RunDetails:
352
+ """
353
+ Get a run by its ID or name. If both are provided, the ID will take precedence.
354
+
355
+ :param uri: The URI of the run.
356
+ :param name: The name of the run.
357
+ """
358
+ cfg = get_common_config()
359
+ return await RunDetails.get_details.aio(
360
+ cls,
361
+ run_id=run_definition_pb2.RunIdentifier(
362
+ org=cfg.org,
363
+ project=cfg.project,
364
+ domain=cfg.domain,
365
+ name=name,
366
+ ),
367
+ )
368
+
369
+ @property
370
+ def name(self) -> str:
371
+ """
372
+ Get the name of the action.
373
+ """
374
+ return self.action_details.run_name
375
+
376
+ @property
377
+ def task_name(self) -> str | None:
378
+ """
379
+ Get the name of the task.
380
+ """
381
+ return self.action_details.task_name
382
+
383
+ @property
384
+ def action_id(self) -> run_definition_pb2.ActionIdentifier:
385
+ """
386
+ Get the action ID.
387
+ """
388
+ return self.action_details.action_id
389
+
390
+ def done(self) -> bool:
391
+ """
392
+ Check if the run is in a terminal state (completed or failed). This is a placeholder for checking the
393
+ run state.
394
+ """
395
+ return self.action_details.done()
396
+
397
+ async def inputs(self) -> ActionInputs:
398
+ """
399
+ Placeholder for inputs. This can be extended to handle inputs from the run context.
400
+ """
401
+ return await self.action_details.inputs()
402
+
403
+ async def outputs(self) -> ActionOutputs:
404
+ """
405
+ Placeholder for outputs. This can be extended to handle outputs from the run context.
406
+ """
407
+ return await self.action_details.outputs()
408
+
409
+ def __rich_repr__(self) -> rich.repr.Result:
410
+ """
411
+ Rich representation of the Run object.
412
+ """
413
+ yield from _action_details_rich_repr(self.pb2.action, root=True)
414
+
415
+ def __repr__(self) -> str:
416
+ """
417
+ String representation of the Action object.
418
+ """
419
+ import rich.pretty
420
+
421
+ return rich.pretty.pretty_repr(self)
422
+
423
+
424
+ @dataclass
425
+ class Action:
426
+ """
427
+ A class representing an action. It is used to manage the run of a task and its state on the remote Union API.
428
+ """
429
+
430
+ pb2: run_definition_pb2.Action
431
+ _details: ActionDetails | None = None
432
+
433
+ @classmethod
434
+ @requires_client
435
+ @syncer.wrap
436
+ async def listall(
437
+ cls,
438
+ for_run_name: str,
439
+ filters: str | None = None,
440
+ sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
441
+ ) -> Union[Iterator[Action], AsyncGenerator[Action, None]]:
442
+ """
443
+ Get all actions for a given run.
444
+
445
+ :param for_run_name: The name of the run.
446
+ :param filters: The filters to apply to the project list.
447
+ :param sort_by: The sorting criteria for the project list, in the format (field, order).
448
+ :return: An iterator of projects.
449
+ """
450
+ token = None
451
+ sort_by = sort_by or ("created_at", "asc")
452
+ sort_pb2 = list_pb2.Sort(
453
+ key=sort_by[0], direction=list_pb2.Sort.ASCENDING if sort_by[1] == "asc" else list_pb2.Sort.DESCENDING
454
+ )
455
+ cfg = get_common_config()
456
+ while True:
457
+ req = list_pb2.ListRequest(
458
+ limit=100,
459
+ token=token,
460
+ sort_by=sort_pb2,
461
+ )
462
+ resp = await get_client().run_service.ListActions(
463
+ run_service_pb2.ListActionsRequest(
464
+ request=req,
465
+ run_id=run_definition_pb2.RunIdentifier(
466
+ org=cfg.org,
467
+ project=cfg.project,
468
+ domain=cfg.domain,
469
+ name=for_run_name,
470
+ ),
471
+ )
472
+ )
473
+ token = resp.token
474
+ for r in resp.actions:
475
+ yield cls(r)
476
+ if not token:
477
+ break
478
+
479
+ @classmethod
480
+ @requires_client
481
+ @syncer.wrap
482
+ async def get(cls, uri: str | None = None, /, run_name: str | None = None, name: str | None = None) -> Action:
483
+ """
484
+ Get a run by its ID or name. If both are provided, the ID will take precedence.
485
+
486
+ :param uri: The URI of the action.
487
+ :param run_name: The name of the action.
488
+ :param name: The name of the action.
489
+ """
490
+ cfg = get_common_config()
491
+ details: ActionDetails = await ActionDetails.get_details.aio(
492
+ cls,
493
+ run_definition_pb2.ActionIdentifier(
494
+ run=run_definition_pb2.RunIdentifier(
495
+ org=cfg.org,
496
+ project=cfg.project,
497
+ domain=cfg.domain,
498
+ name=run_name,
499
+ ),
500
+ name=name,
501
+ ),
502
+ )
503
+ return cls(
504
+ pb2=run_definition_pb2.Action(
505
+ id=details.action_id,
506
+ metadata=details.pb2.metadata,
507
+ status=details.pb2.status,
508
+ ),
509
+ _details=details,
510
+ )
511
+
512
+ @property
513
+ def phase(self) -> str:
514
+ """
515
+ Get the phase of the action.
516
+ """
517
+ return run_definition_pb2.Phase.Name(self.pb2.status.phase)
518
+
519
+ @property
520
+ def name(self) -> str:
521
+ """
522
+ Get the name of the action.
523
+ """
524
+ return self.action_id.name
525
+
526
+ @property
527
+ def run_name(self) -> str:
528
+ """
529
+ Get the name of the run.
530
+ """
531
+ return self.action_id.run.name
532
+
533
+ @property
534
+ def task_name(self) -> str | None:
535
+ """
536
+ Get the name of the task.
537
+ """
538
+ if self.pb2.metadata.HasField("task") and self.pb2.metadata.task.HasField("id"):
539
+ return self.pb2.metadata.task.id.name
540
+ return None
541
+
542
+ @property
543
+ def action_id(self) -> run_definition_pb2.ActionIdentifier:
544
+ """
545
+ Get the action ID.
546
+ """
547
+ return self.pb2.id
548
+
549
+ async def show_logs(
550
+ self, attempt: int | None = None, max_lines: int = 30, show_ts: bool = False, raw: bool = False
551
+ ):
552
+ details = await self.details()
553
+ if not attempt:
554
+ attempt = details.attempts
555
+ if details.phase in [
556
+ run_definition_pb2.PHASE_QUEUED,
557
+ run_definition_pb2.PHASE_INITIALIZING,
558
+ run_definition_pb2.PHASE_WAITING_FOR_RESOURCES,
559
+ ]:
560
+ raise RuntimeError("Action has not yet started, so logs are not available.")
561
+ return await Logs.create_viewer(
562
+ action_id=self.action_id, attempt=attempt, max_lines=max_lines, show_ts=show_ts, raw=raw
563
+ )
564
+
565
+ async def details(self) -> ActionDetails:
566
+ """
567
+ Get the details of the action. This is a placeholder for getting the action details.
568
+ """
569
+ if not self._details:
570
+ self._details = await ActionDetails.get_details.aio(ActionDetails, self.action_id)
571
+ return cast(ActionDetails, self._details)
572
+
573
+ async def watch_details(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
574
+ """
575
+ Watch the action for updates. This is a placeholder for watching the action.
576
+ """
577
+ ad = None
578
+ async for ad in ActionDetails.watch.aio(ActionDetails, self.action_id):
579
+ if ad is None:
580
+ return
581
+ self._details = ad
582
+ yield ad
583
+ if cache_data_on_done and ad and ad.done():
584
+ await cast(ActionDetails, self._details).outputs()
585
+
586
+ def done(self) -> bool:
587
+ """
588
+ Check if the action is done.
589
+ """
590
+ return _action_done_check(self.pb2.status.phase)
591
+
592
+ async def sync(self) -> Action:
593
+ """
594
+ Sync the action with the remote server. This is a placeholder for syncing the action.
595
+ """
596
+ return self
597
+
598
+ def __rich_repr__(self) -> rich.repr.Result:
599
+ """
600
+ Rich representation of the Action object.
601
+ """
602
+ yield from _action_rich_repr(self.pb2, root=True)
603
+
604
+ def __repr__(self) -> str:
605
+ """
606
+ String representation of the Action object.
607
+ """
608
+ import rich.pretty
609
+
610
+ return rich.pretty.pretty_repr(self)
611
+
612
+
613
+ @dataclass
614
+ class ActionDetails:
615
+ """
616
+ A class representing an action. It is used to manage the run of a task and its state on the remote Union API.
617
+ """
618
+
619
+ pb2: run_definition_pb2.ActionDetails
620
+ _inputs: ActionInputs | None = None
621
+ _outputs: ActionOutputs | None = None
622
+
623
+ @classmethod
624
+ @requires_client
625
+ @syncer.wrap
626
+ async def get_details(cls, action_id: run_definition_pb2.ActionIdentifier) -> ActionDetails:
627
+ """
628
+ Get the details of the action. This is a placeholder for getting the action details.
629
+ """
630
+ resp = await get_client().run_service.GetActionDetails(
631
+ run_service_pb2.GetActionDetailsRequest(
632
+ action_id=action_id,
633
+ )
634
+ )
635
+ return ActionDetails(resp.details)
636
+
637
+ @classmethod
638
+ @requires_client
639
+ @syncer.wrap
640
+ async def get(
641
+ cls, uri: str | None = None, /, run_name: str | None = None, name: str | None = None
642
+ ) -> ActionDetails:
643
+ """
644
+ Get a run by its ID or name. If both are provided, the ID will take precedence.
645
+
646
+ :param uri: The URI of the action.
647
+ :param name: The name of the action.
648
+ :param run_name: The name of the run.
649
+ """
650
+ if not uri:
651
+ assert name is not None and run_name is not None, "Either uri or name and run_name must be provided"
652
+ cfg = get_common_config()
653
+ return await cls.get_details.aio(
654
+ cls,
655
+ run_definition_pb2.ActionIdentifier(
656
+ run=run_definition_pb2.RunIdentifier(
657
+ org=cfg.org,
658
+ project=cfg.project,
659
+ domain=cfg.domain,
660
+ name=run_name,
661
+ ),
662
+ name=name,
663
+ ),
664
+ )
665
+
666
+ @classmethod
667
+ @requires_client
668
+ @syncer.wrap
669
+ async def watch(cls, action_id: run_definition_pb2.ActionIdentifier) -> AsyncGenerator[ActionDetails, None]:
670
+ """
671
+ Watch the action for updates. This is a placeholder for watching the action.
672
+ """
673
+ if not action_id:
674
+ raise ValueError("Action ID is required")
675
+
676
+ call = cast(
677
+ AsyncIterator[WatchActionDetailsResponse],
678
+ get_client().run_service.WatchActionDetails(
679
+ request=run_service_pb2.WatchActionDetailsRequest(
680
+ action_id=action_id,
681
+ )
682
+ ),
683
+ )
684
+ try:
685
+ async for resp in call:
686
+ v = cls(resp.details)
687
+ yield v
688
+ if v.done():
689
+ return
690
+ except grpc.aio.AioRpcError as e:
691
+ if e.code() == grpc.StatusCode.CANCELLED:
692
+ pass
693
+ else:
694
+ raise e
695
+
696
+ async def watch_updates(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
697
+ async for d in self.watch.aio(action_id=self.pb2.id):
698
+ yield d
699
+ if d.done():
700
+ self.pb2 = d.pb2
701
+ break
702
+
703
+ if cache_data_on_done and self.done():
704
+ await self._cache_data.aio(self)
705
+
706
+ @property
707
+ def phase(self) -> str:
708
+ """
709
+ Get the phase of the action.
710
+ """
711
+ return run_definition_pb2.Phase.Name(self.status.phase)
712
+
713
+ @property
714
+ def name(self) -> str:
715
+ """
716
+ Get the name of the action.
717
+ """
718
+ return self.action_id.name
719
+
720
+ @property
721
+ def run_name(self) -> str:
722
+ """
723
+ Get the name of the run.
724
+ """
725
+ return self.action_id.run.name
726
+
727
+ @property
728
+ def task_name(self) -> str | None:
729
+ """
730
+ Get the name of the task.
731
+ """
732
+ if self.pb2.metadata.HasField("task") and self.pb2.metadata.task.HasField("id"):
733
+ return self.pb2.metadata.task.id.name
734
+ return None
735
+
736
+ @property
737
+ def action_id(self) -> run_definition_pb2.ActionIdentifier:
738
+ """
739
+ Get the action ID.
740
+ """
741
+ return self.pb2.id
742
+
743
+ @property
744
+ def metadata(self) -> run_definition_pb2.ActionMetadata:
745
+ return self.pb2.metadata
746
+
747
+ @property
748
+ def status(self) -> run_definition_pb2.ActionStatus:
749
+ return self.pb2.status
750
+
751
+ @property
752
+ def error_info(self) -> run_definition_pb2.ErrorInfo | None:
753
+ if self.pb2.HasField("error_info"):
754
+ return self.pb2.error_info
755
+ return None
756
+
757
+ @property
758
+ def abort_info(self) -> run_definition_pb2.AbortInfo | None:
759
+ if self.pb2.HasField("abort_info"):
760
+ return self.pb2.abort_info
761
+ return None
762
+
763
+ @property
764
+ def runtime(self) -> timedelta:
765
+ """
766
+ Get the runtime of the action.
767
+ """
768
+ start_time = timestamp.to_datetime(self.pb2.status.start_time, timezone.utc)
769
+ if self.pb2.status.HasField("end_time"):
770
+ end_time = timestamp.to_datetime(self.pb2.status.end_time, timezone.utc)
771
+ return end_time - start_time
772
+ return datetime.now(timezone.utc) - start_time
773
+
774
+ @property
775
+ def attempts(self) -> int:
776
+ """
777
+ Get the number of attempts of the action.
778
+ """
779
+ return self.pb2.status.attempts
780
+
781
+ @syncer.wrap
782
+ async def _cache_data(self) -> bool:
783
+ """
784
+ Cache the inputs and outputs of the action.
785
+ :return: Returns True if Action is terminal and all data is cached else False.
786
+ """
787
+ if self._inputs and self._outputs:
788
+ return True
789
+ if self._inputs and not self.done():
790
+ return False
791
+ resp = await get_client().run_service.GetActionData(
792
+ request=run_service_pb2.GetActionDataRequest(
793
+ action_id=self.pb2.id,
794
+ )
795
+ )
796
+ self._inputs = ActionInputs(resp.inputs)
797
+ self._outputs = ActionOutputs(resp.outputs) if resp.HasField("outputs") else None
798
+ return self._outputs is not None
799
+
800
+ async def inputs(self) -> ActionInputs:
801
+ """
802
+ Placeholder for inputs. This can be extended to handle inputs from the run context.
803
+ """
804
+ if not self._inputs:
805
+ await self._cache_data.aio(self)
806
+ return cast(ActionInputs, self._inputs)
807
+
808
+ async def outputs(self) -> ActionOutputs:
809
+ """
810
+ Placeholder for outputs. This can be extended to handle outputs from the run context.
811
+ """
812
+ if not self._outputs:
813
+ if not await self._cache_data.aio(self):
814
+ raise RuntimeError(
815
+ "Action is not in a terminal state, outputs are not available. "
816
+ "Please wait for the action to complete."
817
+ )
818
+ return cast(ActionOutputs, self._outputs)
819
+
820
+ def done(self) -> bool:
821
+ """
822
+ Check if the action is in a terminal state (completed or failed). This is a placeholder for checking the
823
+ action state.
824
+ """
825
+ return _action_done_check(self.pb2.status.phase)
826
+
827
+ def __rich_repr__(self) -> rich.repr.Result:
828
+ """
829
+ Rich representation of the Action object.
830
+ """
831
+ yield from _action_details_rich_repr(self.pb2, root=True)
832
+
833
+ def __repr__(self) -> str:
834
+ """
835
+ String representation of the Action object.
836
+ """
837
+ import rich.pretty
838
+
839
+ return rich.pretty.pretty_repr(self)
840
+
841
+
842
+ @dataclass
843
+ class ActionInputs:
844
+ """
845
+ A class representing the inputs of an action. It is used to manage the inputs of a task and its state on the
846
+ remote Union API.
847
+ """
848
+
849
+ pb2: run_definition_pb2.Inputs
850
+
851
+ def __repr__(self):
852
+ import rich.pretty
853
+
854
+ import flyte.types as types
855
+
856
+ return rich.pretty.pretty_repr(types.literal_string_repr(self.pb2))
857
+
858
+
859
+ @dataclass
860
+ class ActionOutputs:
861
+ """
862
+ A class representing the outputs of an action. It is used to manage the outputs of a task and its state on the
863
+ remote Union API.
864
+ """
865
+
866
+ pb2: run_definition_pb2.Outputs
867
+
868
+ def __repr__(self):
869
+ import rich.pretty
870
+
871
+ import flyte.types as types
872
+
873
+ return rich.pretty.pretty_repr(types.literal_string_repr(self.pb2))