flyte 0.2.0b1__py3-none-any.whl → 2.0.0b46__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.
Files changed (266) hide show
  1. flyte/__init__.py +83 -30
  2. flyte/_bin/connect.py +61 -0
  3. flyte/_bin/debug.py +38 -0
  4. flyte/_bin/runtime.py +87 -19
  5. flyte/_bin/serve.py +351 -0
  6. flyte/_build.py +3 -2
  7. flyte/_cache/cache.py +6 -5
  8. flyte/_cache/local_cache.py +216 -0
  9. flyte/_code_bundle/_ignore.py +31 -5
  10. flyte/_code_bundle/_packaging.py +42 -11
  11. flyte/_code_bundle/_utils.py +57 -34
  12. flyte/_code_bundle/bundle.py +130 -27
  13. flyte/_constants.py +1 -0
  14. flyte/_context.py +21 -5
  15. flyte/_custom_context.py +73 -0
  16. flyte/_debug/constants.py +37 -0
  17. flyte/_debug/utils.py +17 -0
  18. flyte/_debug/vscode.py +315 -0
  19. flyte/_deploy.py +396 -75
  20. flyte/_deployer.py +109 -0
  21. flyte/_environment.py +94 -11
  22. flyte/_excepthook.py +37 -0
  23. flyte/_group.py +2 -1
  24. flyte/_hash.py +1 -16
  25. flyte/_image.py +544 -231
  26. flyte/_initialize.py +456 -316
  27. flyte/_interface.py +40 -5
  28. flyte/_internal/controllers/__init__.py +22 -8
  29. flyte/_internal/controllers/_local_controller.py +159 -35
  30. flyte/_internal/controllers/_trace.py +18 -10
  31. flyte/_internal/controllers/remote/__init__.py +38 -9
  32. flyte/_internal/controllers/remote/_action.py +82 -12
  33. flyte/_internal/controllers/remote/_client.py +6 -2
  34. flyte/_internal/controllers/remote/_controller.py +290 -64
  35. flyte/_internal/controllers/remote/_core.py +155 -95
  36. flyte/_internal/controllers/remote/_informer.py +40 -20
  37. flyte/_internal/controllers/remote/_service_protocol.py +2 -2
  38. flyte/_internal/imagebuild/__init__.py +2 -10
  39. flyte/_internal/imagebuild/docker_builder.py +391 -84
  40. flyte/_internal/imagebuild/image_builder.py +111 -55
  41. flyte/_internal/imagebuild/remote_builder.py +409 -0
  42. flyte/_internal/imagebuild/utils.py +79 -0
  43. flyte/_internal/resolvers/_app_env_module.py +92 -0
  44. flyte/_internal/resolvers/_task_module.py +5 -38
  45. flyte/_internal/resolvers/app_env.py +26 -0
  46. flyte/_internal/resolvers/common.py +8 -1
  47. flyte/_internal/resolvers/default.py +2 -2
  48. flyte/_internal/runtime/convert.py +319 -36
  49. flyte/_internal/runtime/entrypoints.py +106 -18
  50. flyte/_internal/runtime/io.py +71 -23
  51. flyte/_internal/runtime/resources_serde.py +21 -7
  52. flyte/_internal/runtime/reuse.py +125 -0
  53. flyte/_internal/runtime/rusty.py +196 -0
  54. flyte/_internal/runtime/task_serde.py +239 -66
  55. flyte/_internal/runtime/taskrunner.py +48 -8
  56. flyte/_internal/runtime/trigger_serde.py +162 -0
  57. flyte/_internal/runtime/types_serde.py +7 -16
  58. flyte/_keyring/file.py +115 -0
  59. flyte/_link.py +30 -0
  60. flyte/_logging.py +241 -42
  61. flyte/_map.py +312 -0
  62. flyte/_metrics.py +59 -0
  63. flyte/_module.py +74 -0
  64. flyte/_pod.py +30 -0
  65. flyte/_resources.py +296 -33
  66. flyte/_retry.py +1 -7
  67. flyte/_reusable_environment.py +72 -7
  68. flyte/_run.py +462 -132
  69. flyte/_secret.py +47 -11
  70. flyte/_serve.py +333 -0
  71. flyte/_task.py +245 -56
  72. flyte/_task_environment.py +219 -97
  73. flyte/_task_plugins.py +47 -0
  74. flyte/_tools.py +8 -8
  75. flyte/_trace.py +15 -24
  76. flyte/_trigger.py +1027 -0
  77. flyte/_utils/__init__.py +12 -1
  78. flyte/_utils/asyn.py +3 -1
  79. flyte/_utils/async_cache.py +139 -0
  80. flyte/_utils/coro_management.py +5 -4
  81. flyte/_utils/description_parser.py +19 -0
  82. flyte/_utils/docker_credentials.py +173 -0
  83. flyte/_utils/helpers.py +45 -19
  84. flyte/_utils/module_loader.py +123 -0
  85. flyte/_utils/org_discovery.py +57 -0
  86. flyte/_utils/uv_script_parser.py +8 -1
  87. flyte/_version.py +16 -3
  88. flyte/app/__init__.py +27 -0
  89. flyte/app/_app_environment.py +362 -0
  90. flyte/app/_connector_environment.py +40 -0
  91. flyte/app/_deploy.py +130 -0
  92. flyte/app/_parameter.py +343 -0
  93. flyte/app/_runtime/__init__.py +3 -0
  94. flyte/app/_runtime/app_serde.py +383 -0
  95. flyte/app/_types.py +113 -0
  96. flyte/app/extras/__init__.py +9 -0
  97. flyte/app/extras/_auth_middleware.py +217 -0
  98. flyte/app/extras/_fastapi.py +93 -0
  99. flyte/app/extras/_model_loader/__init__.py +3 -0
  100. flyte/app/extras/_model_loader/config.py +7 -0
  101. flyte/app/extras/_model_loader/loader.py +288 -0
  102. flyte/cli/__init__.py +12 -0
  103. flyte/cli/_abort.py +28 -0
  104. flyte/cli/_build.py +114 -0
  105. flyte/cli/_common.py +493 -0
  106. flyte/cli/_create.py +371 -0
  107. flyte/cli/_delete.py +45 -0
  108. flyte/cli/_deploy.py +401 -0
  109. flyte/cli/_gen.py +316 -0
  110. flyte/cli/_get.py +446 -0
  111. flyte/cli/_option.py +33 -0
  112. flyte/{_cli → cli}/_params.py +57 -17
  113. flyte/cli/_plugins.py +209 -0
  114. flyte/cli/_prefetch.py +292 -0
  115. flyte/cli/_run.py +690 -0
  116. flyte/cli/_serve.py +338 -0
  117. flyte/cli/_update.py +86 -0
  118. flyte/cli/_user.py +20 -0
  119. flyte/cli/main.py +246 -0
  120. flyte/config/__init__.py +2 -167
  121. flyte/config/_config.py +215 -163
  122. flyte/config/_internal.py +10 -1
  123. flyte/config/_reader.py +225 -0
  124. flyte/connectors/__init__.py +11 -0
  125. flyte/connectors/_connector.py +330 -0
  126. flyte/connectors/_server.py +194 -0
  127. flyte/connectors/utils.py +159 -0
  128. flyte/errors.py +134 -2
  129. flyte/extend.py +24 -0
  130. flyte/extras/_container.py +69 -56
  131. flyte/git/__init__.py +3 -0
  132. flyte/git/_config.py +279 -0
  133. flyte/io/__init__.py +8 -1
  134. flyte/io/{structured_dataset → _dataframe}/__init__.py +32 -30
  135. flyte/io/{structured_dataset → _dataframe}/basic_dfs.py +75 -68
  136. flyte/io/{structured_dataset/structured_dataset.py → _dataframe/dataframe.py} +207 -242
  137. flyte/io/_dir.py +575 -113
  138. flyte/io/_file.py +587 -141
  139. flyte/io/_hashing_io.py +342 -0
  140. flyte/io/extend.py +7 -0
  141. flyte/models.py +635 -0
  142. flyte/prefetch/__init__.py +22 -0
  143. flyte/prefetch/_hf_model.py +563 -0
  144. flyte/remote/__init__.py +14 -3
  145. flyte/remote/_action.py +879 -0
  146. flyte/remote/_app.py +346 -0
  147. flyte/remote/_auth_metadata.py +42 -0
  148. flyte/remote/_client/_protocols.py +62 -4
  149. flyte/remote/_client/auth/_auth_utils.py +19 -0
  150. flyte/remote/_client/auth/_authenticators/base.py +8 -2
  151. flyte/remote/_client/auth/_authenticators/device_code.py +4 -5
  152. flyte/remote/_client/auth/_authenticators/factory.py +4 -0
  153. flyte/remote/_client/auth/_authenticators/passthrough.py +79 -0
  154. flyte/remote/_client/auth/_authenticators/pkce.py +17 -18
  155. flyte/remote/_client/auth/_channel.py +47 -18
  156. flyte/remote/_client/auth/_client_config.py +5 -3
  157. flyte/remote/_client/auth/_keyring.py +15 -2
  158. flyte/remote/_client/auth/_token_client.py +3 -3
  159. flyte/remote/_client/controlplane.py +206 -18
  160. flyte/remote/_common.py +66 -0
  161. flyte/remote/_data.py +107 -22
  162. flyte/remote/_logs.py +116 -33
  163. flyte/remote/_project.py +21 -19
  164. flyte/remote/_run.py +164 -631
  165. flyte/remote/_secret.py +72 -29
  166. flyte/remote/_task.py +387 -46
  167. flyte/remote/_trigger.py +368 -0
  168. flyte/remote/_user.py +43 -0
  169. flyte/report/_report.py +10 -6
  170. flyte/storage/__init__.py +13 -1
  171. flyte/storage/_config.py +237 -0
  172. flyte/storage/_parallel_reader.py +289 -0
  173. flyte/storage/_storage.py +268 -59
  174. flyte/syncify/__init__.py +56 -0
  175. flyte/syncify/_api.py +414 -0
  176. flyte/types/__init__.py +39 -0
  177. flyte/types/_interface.py +22 -7
  178. flyte/{io/pickle/transformer.py → types/_pickle.py} +37 -9
  179. flyte/types/_string_literals.py +8 -9
  180. flyte/types/_type_engine.py +226 -126
  181. flyte/types/_utils.py +1 -1
  182. flyte-2.0.0b46.data/scripts/debug.py +38 -0
  183. flyte-2.0.0b46.data/scripts/runtime.py +194 -0
  184. flyte-2.0.0b46.dist-info/METADATA +352 -0
  185. flyte-2.0.0b46.dist-info/RECORD +221 -0
  186. flyte-2.0.0b46.dist-info/entry_points.txt +8 -0
  187. flyte-2.0.0b46.dist-info/licenses/LICENSE +201 -0
  188. flyte/_api_commons.py +0 -3
  189. flyte/_cli/_common.py +0 -299
  190. flyte/_cli/_create.py +0 -42
  191. flyte/_cli/_delete.py +0 -23
  192. flyte/_cli/_deploy.py +0 -140
  193. flyte/_cli/_get.py +0 -235
  194. flyte/_cli/_run.py +0 -174
  195. flyte/_cli/main.py +0 -98
  196. flyte/_datastructures.py +0 -342
  197. flyte/_internal/controllers/pbhash.py +0 -39
  198. flyte/_protos/common/authorization_pb2.py +0 -66
  199. flyte/_protos/common/authorization_pb2.pyi +0 -108
  200. flyte/_protos/common/authorization_pb2_grpc.py +0 -4
  201. flyte/_protos/common/identifier_pb2.py +0 -71
  202. flyte/_protos/common/identifier_pb2.pyi +0 -82
  203. flyte/_protos/common/identifier_pb2_grpc.py +0 -4
  204. flyte/_protos/common/identity_pb2.py +0 -48
  205. flyte/_protos/common/identity_pb2.pyi +0 -72
  206. flyte/_protos/common/identity_pb2_grpc.py +0 -4
  207. flyte/_protos/common/list_pb2.py +0 -36
  208. flyte/_protos/common/list_pb2.pyi +0 -69
  209. flyte/_protos/common/list_pb2_grpc.py +0 -4
  210. flyte/_protos/common/policy_pb2.py +0 -37
  211. flyte/_protos/common/policy_pb2.pyi +0 -27
  212. flyte/_protos/common/policy_pb2_grpc.py +0 -4
  213. flyte/_protos/common/role_pb2.py +0 -37
  214. flyte/_protos/common/role_pb2.pyi +0 -53
  215. flyte/_protos/common/role_pb2_grpc.py +0 -4
  216. flyte/_protos/common/runtime_version_pb2.py +0 -28
  217. flyte/_protos/common/runtime_version_pb2.pyi +0 -24
  218. flyte/_protos/common/runtime_version_pb2_grpc.py +0 -4
  219. flyte/_protos/logs/dataplane/payload_pb2.py +0 -96
  220. flyte/_protos/logs/dataplane/payload_pb2.pyi +0 -168
  221. flyte/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
  222. flyte/_protos/secret/definition_pb2.py +0 -49
  223. flyte/_protos/secret/definition_pb2.pyi +0 -93
  224. flyte/_protos/secret/definition_pb2_grpc.py +0 -4
  225. flyte/_protos/secret/payload_pb2.py +0 -62
  226. flyte/_protos/secret/payload_pb2.pyi +0 -94
  227. flyte/_protos/secret/payload_pb2_grpc.py +0 -4
  228. flyte/_protos/secret/secret_pb2.py +0 -38
  229. flyte/_protos/secret/secret_pb2.pyi +0 -6
  230. flyte/_protos/secret/secret_pb2_grpc.py +0 -198
  231. flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
  232. flyte/_protos/validate/validate/validate_pb2.py +0 -76
  233. flyte/_protos/workflow/node_execution_service_pb2.py +0 -26
  234. flyte/_protos/workflow/node_execution_service_pb2.pyi +0 -4
  235. flyte/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
  236. flyte/_protos/workflow/queue_service_pb2.py +0 -106
  237. flyte/_protos/workflow/queue_service_pb2.pyi +0 -141
  238. flyte/_protos/workflow/queue_service_pb2_grpc.py +0 -172
  239. flyte/_protos/workflow/run_definition_pb2.py +0 -128
  240. flyte/_protos/workflow/run_definition_pb2.pyi +0 -310
  241. flyte/_protos/workflow/run_definition_pb2_grpc.py +0 -4
  242. flyte/_protos/workflow/run_logs_service_pb2.py +0 -41
  243. flyte/_protos/workflow/run_logs_service_pb2.pyi +0 -28
  244. flyte/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
  245. flyte/_protos/workflow/run_service_pb2.py +0 -133
  246. flyte/_protos/workflow/run_service_pb2.pyi +0 -175
  247. flyte/_protos/workflow/run_service_pb2_grpc.py +0 -412
  248. flyte/_protos/workflow/state_service_pb2.py +0 -58
  249. flyte/_protos/workflow/state_service_pb2.pyi +0 -71
  250. flyte/_protos/workflow/state_service_pb2_grpc.py +0 -138
  251. flyte/_protos/workflow/task_definition_pb2.py +0 -72
  252. flyte/_protos/workflow/task_definition_pb2.pyi +0 -65
  253. flyte/_protos/workflow/task_definition_pb2_grpc.py +0 -4
  254. flyte/_protos/workflow/task_service_pb2.py +0 -44
  255. flyte/_protos/workflow/task_service_pb2.pyi +0 -31
  256. flyte/_protos/workflow/task_service_pb2_grpc.py +0 -104
  257. flyte/io/_dataframe.py +0 -0
  258. flyte/io/pickle/__init__.py +0 -0
  259. flyte/remote/_console.py +0 -18
  260. flyte-0.2.0b1.dist-info/METADATA +0 -179
  261. flyte-0.2.0b1.dist-info/RECORD +0 -204
  262. flyte-0.2.0b1.dist-info/entry_points.txt +0 -3
  263. /flyte/{_cli → _debug}/__init__.py +0 -0
  264. /flyte/{_protos → _keyring}/__init__.py +0 -0
  265. {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/WHEEL +0 -0
  266. {flyte-0.2.0b1.dist-info → flyte-2.0.0b46.dist-info}/top_level.txt +0 -0
flyte/remote/_run.py CHANGED
@@ -1,92 +1,25 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  from dataclasses import dataclass, field
5
- from datetime import datetime, timedelta, timezone
6
- from typing import AsyncGenerator, AsyncIterator, Iterator, Literal, Tuple, Union, cast
4
+ from typing import AsyncGenerator, AsyncIterator, Literal, Tuple
7
5
 
8
6
  import grpc
9
7
  import rich.repr
10
- from google.protobuf import timestamp
11
- from rich.console import Console
12
- from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
8
+ from flyteidl2.common import identifier_pb2, list_pb2, phase_pb2
9
+ from flyteidl2.workflow import run_definition_pb2, run_service_pb2
13
10
 
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
11
+ from flyte._initialize import ensure_client, get_client, get_init_config
12
+ from flyte._logging import logger
13
+ from flyte.models import ActionPhase
14
+ from flyte.syncify import syncify
18
15
 
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
- ]
16
+ from . import Action, ActionDetails, ActionInputs, ActionOutputs
17
+ from ._action import _action_details_rich_repr, _action_rich_repr
18
+ from ._common import ToJSONMixin, filtering, sorting
86
19
 
87
20
 
88
21
  @dataclass
89
- class Run:
22
+ class Run(ToJSONMixin):
90
23
  """
91
24
  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
25
  Union API.
@@ -104,32 +37,84 @@ class Run:
104
37
  raise RuntimeError("Run does not have an action")
105
38
  self.action = Action(self.pb2.action)
106
39
 
40
+ @syncify
107
41
  @classmethod
108
- @requires_client
109
- @syncer.wrap
110
42
  async def listall(
111
43
  cls,
112
- filters: str | None = None,
44
+ in_phase: Tuple[ActionPhase | str, ...] | None = None,
45
+ task_name: str | None = None,
46
+ task_version: str | None = None,
47
+ created_by_subject: str | None = None,
113
48
  sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
114
- ) -> Union[Iterator[Run], AsyncGenerator[Run, None]]:
49
+ limit: int = 100,
50
+ ) -> AsyncIterator[Run]:
115
51
  """
116
52
  Get all runs for the current project and domain.
117
53
 
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).
54
+ :param in_phase: Filter runs by one or more phases.
55
+ :param task_name: Filter runs by task name.
56
+ :param task_version: Filter runs by task version.
57
+ :param created_by_subject: Filter runs by the subject that created them. (this is not username, but the subject)
58
+ :param sort_by: The sorting criteria for the Run list, in the format (field, order).
59
+ :param limit: The maximum number of runs to return.
120
60
  :return: An iterator of runs.
121
61
  """
62
+ ensure_client()
122
63
  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()
64
+ sort_pb2 = sorting(sort_by)
65
+ filters = []
66
+ if in_phase:
67
+ phases = [
68
+ str(p.to_protobuf_value())
69
+ if isinstance(p, ActionPhase)
70
+ else str(phase_pb2.ActionPhase.Value(f"ACTION_PHASE_{p.upper()}"))
71
+ for p in in_phase
72
+ ]
73
+ logger.debug(f"Fetching run phases: {phases}")
74
+ if len(phases) > 1:
75
+ filters.append(
76
+ list_pb2.Filter(
77
+ function=list_pb2.Filter.Function.VALUE_IN,
78
+ field="phase",
79
+ values=phases,
80
+ ),
81
+ )
82
+ else:
83
+ filters.append(
84
+ list_pb2.Filter(
85
+ function=list_pb2.Filter.Function.EQUAL,
86
+ field="phase",
87
+ values=phases[0],
88
+ ),
89
+ )
90
+
91
+ if task_name:
92
+ filters.append(
93
+ list_pb2.Filter(
94
+ function=list_pb2.Filter.Function.EQUAL,
95
+ field="task_name",
96
+ values=[task_name],
97
+ ),
98
+ )
99
+ if task_version:
100
+ filters.append(
101
+ list_pb2.Filter(
102
+ function=list_pb2.Filter.Function.EQUAL,
103
+ field="task_version",
104
+ values=[task_version],
105
+ ),
106
+ )
107
+
108
+ filters = filtering(created_by_subject, *filters)
109
+
110
+ cfg = get_init_config()
111
+ i = 0
128
112
  while True:
129
113
  req = list_pb2.ListRequest(
130
- limit=100,
114
+ limit=min(100, limit),
131
115
  token=token,
132
116
  sort_by=sort_pb2,
117
+ filters=filters,
133
118
  )
134
119
  resp = await get_client().run_service.ListRuns(
135
120
  run_service_pb2.ListRunsRequest(
@@ -144,20 +129,23 @@ class Run:
144
129
  )
145
130
  token = resp.token
146
131
  for r in resp.runs:
132
+ i += 1
133
+ if i > limit:
134
+ return
147
135
  yield cls(r)
148
136
  if not token:
149
137
  break
150
138
 
139
+ @syncify
151
140
  @classmethod
152
- @requires_client
153
- @syncer.wrap
154
141
  async def get(cls, name: str) -> Run:
155
142
  """
156
143
  Get the current run.
157
144
 
158
145
  :return: The current run.
159
146
  """
160
- run_details: RunDetails = await RunDetails.get.aio(RunDetails, name=name)
147
+ ensure_client()
148
+ run_details: RunDetails = await RunDetails.get.aio(name=name)
161
149
  run = run_definition_pb2.Run(
162
150
  action=run_definition_pb2.Action(
163
151
  id=run_details.action_id,
@@ -179,112 +167,104 @@ class Run:
179
167
  """
180
168
  Get the phase of the run.
181
169
  """
182
- return run_definition_pb2.Phase.Name(self.action.phase)
170
+ return self.action.phase
171
+
172
+ @property
173
+ def raw_phase(self) -> phase_pb2.ActionPhase:
174
+ """
175
+ Get the raw phase of the run.
176
+ """
177
+ return self.action.raw_phase
183
178
 
184
- @syncer.wrap
185
- async def wait(self, quiet: bool = False) -> None:
179
+ @syncify
180
+ async def wait(self, quiet: bool = False, wait_for: Literal["terminal", "running"] = "terminal") -> None:
186
181
  """
187
182
  Wait for the run to complete, displaying a rich progress panel with status transitions,
188
183
  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
184
 
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]")
185
+ This method updates the Run's internal state, ensuring that properties like
186
+ `run.action.phase` reflect the final state after waiting completes.
187
+ """
188
+ await self.action.wait(quiet=quiet, wait_for=wait_for)
189
+ # Update the Run's pb2.action to keep it in sync after waiting
190
+ self.pb2.action.CopyFrom(self.action.pb2)
236
191
 
237
192
  async def watch(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
238
193
  """
239
- Get the details of the run. This is a placeholder for getting the run details.
194
+ Watch the run for updates, updating the internal Run state with latest details.
195
+
196
+ This method updates the Run's action state, ensuring that properties like
197
+ `run.action.phase` reflect the current state after watching.
240
198
  """
241
- async for ad in self.action.watch_details(cache_data_on_done=cache_data_on_done):
242
- if ad is None:
243
- return
199
+ async for ad in self.action.watch(cache_data_on_done=cache_data_on_done):
200
+ # The action's pb2 is already updated by Action.watch()
201
+ # Update the Run's pb2.action to keep it in sync
202
+ self.pb2.action.CopyFrom(self.action.pb2)
244
203
  yield ad
245
204
 
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
- )
205
+ @syncify
206
+ async def show_logs(
207
+ self,
208
+ attempt: int | None = None,
209
+ max_lines: int = 100,
210
+ show_ts: bool = False,
211
+ raw: bool = False,
212
+ filter_system: bool = False,
213
+ ):
214
+ await self.action.show_logs.aio(attempt, max_lines, show_ts, raw, filter_system=filter_system)
254
215
 
216
+ @syncify
255
217
  async def details(self) -> RunDetails:
256
218
  """
257
219
  Get the details of the run. This is a placeholder for getting the run details.
258
220
  """
259
- if self._details is None:
260
- self._details = await RunDetails.get_details(RunDetails, self.pb2.action.id.run)
221
+ if self._details is None or not self._details.done():
222
+ self._details = await RunDetails.get_details.aio(self.pb2.action.id.run)
261
223
  return self._details
262
224
 
225
+ @syncify
226
+ async def inputs(self) -> ActionInputs:
227
+ """
228
+ Get the inputs of the run. This is a placeholder for getting the run inputs.
229
+ """
230
+ details = await self.details.aio()
231
+ return await details.inputs()
232
+
233
+ @syncify
234
+ async def outputs(self) -> ActionOutputs:
235
+ """
236
+ Get the outputs of the run. This is a placeholder for getting the run outputs.
237
+ """
238
+ details = await self.details.aio()
239
+ return await details.outputs()
240
+
263
241
  @property
264
- @requires_client
265
242
  def url(self) -> str:
266
243
  """
267
244
  Get the URL of the run.
268
245
  """
269
246
  client = get_client()
270
- return get_run_url(
271
- client.endpoint,
272
- insecure=client.insecure,
247
+ return client.console.run_url(
273
248
  project=self.pb2.action.id.run.project,
274
249
  domain=self.pb2.action.id.run.domain,
275
250
  run_name=self.name,
276
251
  )
277
252
 
278
- @syncer.wrap
279
- async def cancel(self) -> None:
253
+ @syncify
254
+ async def abort(self):
280
255
  """
281
- Cancel the run.
256
+ Aborts / Terminates the run.
282
257
  """
283
- await get_client().run_service.AbortRun(
284
- run_service_pb2.AbortRunRequest(
285
- run_id=self.pb2.action.id.run,
258
+ try:
259
+ await get_client().run_service.AbortRun(
260
+ run_service_pb2.AbortRunRequest(
261
+ run_id=self.pb2.action.id.run,
262
+ )
286
263
  )
287
- )
264
+ except grpc.aio.AioRpcError as e:
265
+ if e.code() == grpc.StatusCode.NOT_FOUND:
266
+ return
267
+ raise
288
268
 
289
269
  def done(self) -> bool:
290
270
  """
@@ -304,7 +284,8 @@ class Run:
304
284
  """
305
285
  Rich representation of the Run object.
306
286
  """
307
- yield from _action_rich_repr(self.pb2.action, root=True)
287
+ yield "url", f"[blue bold][link={self.url}]link[/link][/blue bold]"
288
+ yield from _action_rich_repr(self.pb2.action)
308
289
 
309
290
  def __repr__(self) -> str:
310
291
  """
@@ -316,7 +297,7 @@ class Run:
316
297
 
317
298
 
318
299
  @dataclass
319
- class RunDetails:
300
+ class RunDetails(ToJSONMixin):
320
301
  """
321
302
  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
303
  Union API.
@@ -331,13 +312,13 @@ class RunDetails:
331
312
  """
332
313
  self.action_details = ActionDetails(self.pb2.action)
333
314
 
315
+ @syncify
334
316
  @classmethod
335
- @requires_client
336
- @syncer.wrap
337
- async def get_details(cls, run_id: run_definition_pb2.RunIdentifier) -> RunDetails:
317
+ async def get_details(cls, run_id: identifier_pb2.RunIdentifier) -> RunDetails:
338
318
  """
339
319
  Get the details of the run. This is a placeholder for getting the run details.
340
320
  """
321
+ ensure_client()
341
322
  resp = await get_client().run_service.GetRunDetails(
342
323
  run_service_pb2.GetRunDetailsRequest(
343
324
  run_id=run_id,
@@ -345,9 +326,8 @@ class RunDetails:
345
326
  )
346
327
  return cls(resp.details)
347
328
 
329
+ @syncify
348
330
  @classmethod
349
- @requires_client
350
- @syncer.wrap
351
331
  async def get(cls, name: str | None = None) -> RunDetails:
352
332
  """
353
333
  Get a run by its ID or name. If both are provided, the ID will take precedence.
@@ -355,10 +335,10 @@ class RunDetails:
355
335
  :param uri: The URI of the run.
356
336
  :param name: The name of the run.
357
337
  """
358
- cfg = get_common_config()
338
+ ensure_client()
339
+ cfg = get_init_config()
359
340
  return await RunDetails.get_details.aio(
360
- cls,
361
- run_id=run_definition_pb2.RunIdentifier(
341
+ run_id=identifier_pb2.RunIdentifier(
362
342
  org=cfg.org,
363
343
  project=cfg.project,
364
344
  domain=cfg.domain,
@@ -381,7 +361,7 @@ class RunDetails:
381
361
  return self.action_details.task_name
382
362
 
383
363
  @property
384
- def action_id(self) -> run_definition_pb2.ActionIdentifier:
364
+ def action_id(self) -> identifier_pb2.ActionIdentifier:
385
365
  """
386
366
  Get the action ID.
387
367
  """
@@ -410,196 +390,12 @@ class RunDetails:
410
390
  """
411
391
  Rich representation of the Run object.
412
392
  """
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)
393
+ yield "labels", str(self.pb2.run_spec.labels)
394
+ yield "annotations", str(self.pb2.run_spec.annotations)
395
+ yield "env-vars", str(self.pb2.run_spec.envs)
396
+ yield "is-interruptible", str(self.pb2.run_spec.interruptible)
397
+ yield "cache-overwrite", self.pb2.run_spec.overwrite_cache
398
+ yield from _action_details_rich_repr(self.pb2.action)
603
399
 
604
400
  def __repr__(self) -> str:
605
401
  """
@@ -608,266 +404,3 @@ class Action:
608
404
  import rich.pretty
609
405
 
610
406
  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))