flyte 2.0.0b32__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 (204) hide show
  1. flyte/__init__.py +108 -0
  2. flyte/_bin/__init__.py +0 -0
  3. flyte/_bin/debug.py +38 -0
  4. flyte/_bin/runtime.py +195 -0
  5. flyte/_bin/serve.py +178 -0
  6. flyte/_build.py +26 -0
  7. flyte/_cache/__init__.py +12 -0
  8. flyte/_cache/cache.py +147 -0
  9. flyte/_cache/defaults.py +9 -0
  10. flyte/_cache/local_cache.py +216 -0
  11. flyte/_cache/policy_function_body.py +42 -0
  12. flyte/_code_bundle/__init__.py +8 -0
  13. flyte/_code_bundle/_ignore.py +121 -0
  14. flyte/_code_bundle/_packaging.py +218 -0
  15. flyte/_code_bundle/_utils.py +347 -0
  16. flyte/_code_bundle/bundle.py +266 -0
  17. flyte/_constants.py +1 -0
  18. flyte/_context.py +155 -0
  19. flyte/_custom_context.py +73 -0
  20. flyte/_debug/__init__.py +0 -0
  21. flyte/_debug/constants.py +38 -0
  22. flyte/_debug/utils.py +17 -0
  23. flyte/_debug/vscode.py +307 -0
  24. flyte/_deploy.py +408 -0
  25. flyte/_deployer.py +109 -0
  26. flyte/_doc.py +29 -0
  27. flyte/_docstring.py +32 -0
  28. flyte/_environment.py +122 -0
  29. flyte/_excepthook.py +37 -0
  30. flyte/_group.py +32 -0
  31. flyte/_hash.py +8 -0
  32. flyte/_image.py +1055 -0
  33. flyte/_initialize.py +628 -0
  34. flyte/_interface.py +119 -0
  35. flyte/_internal/__init__.py +3 -0
  36. flyte/_internal/controllers/__init__.py +129 -0
  37. flyte/_internal/controllers/_local_controller.py +239 -0
  38. flyte/_internal/controllers/_trace.py +48 -0
  39. flyte/_internal/controllers/remote/__init__.py +58 -0
  40. flyte/_internal/controllers/remote/_action.py +211 -0
  41. flyte/_internal/controllers/remote/_client.py +47 -0
  42. flyte/_internal/controllers/remote/_controller.py +583 -0
  43. flyte/_internal/controllers/remote/_core.py +465 -0
  44. flyte/_internal/controllers/remote/_informer.py +381 -0
  45. flyte/_internal/controllers/remote/_service_protocol.py +50 -0
  46. flyte/_internal/imagebuild/__init__.py +3 -0
  47. flyte/_internal/imagebuild/docker_builder.py +706 -0
  48. flyte/_internal/imagebuild/image_builder.py +277 -0
  49. flyte/_internal/imagebuild/remote_builder.py +386 -0
  50. flyte/_internal/imagebuild/utils.py +78 -0
  51. flyte/_internal/resolvers/__init__.py +0 -0
  52. flyte/_internal/resolvers/_task_module.py +21 -0
  53. flyte/_internal/resolvers/common.py +31 -0
  54. flyte/_internal/resolvers/default.py +28 -0
  55. flyte/_internal/runtime/__init__.py +0 -0
  56. flyte/_internal/runtime/convert.py +486 -0
  57. flyte/_internal/runtime/entrypoints.py +204 -0
  58. flyte/_internal/runtime/io.py +188 -0
  59. flyte/_internal/runtime/resources_serde.py +152 -0
  60. flyte/_internal/runtime/reuse.py +125 -0
  61. flyte/_internal/runtime/rusty.py +193 -0
  62. flyte/_internal/runtime/task_serde.py +362 -0
  63. flyte/_internal/runtime/taskrunner.py +209 -0
  64. flyte/_internal/runtime/trigger_serde.py +160 -0
  65. flyte/_internal/runtime/types_serde.py +54 -0
  66. flyte/_keyring/__init__.py +0 -0
  67. flyte/_keyring/file.py +115 -0
  68. flyte/_logging.py +300 -0
  69. flyte/_map.py +312 -0
  70. flyte/_module.py +72 -0
  71. flyte/_pod.py +30 -0
  72. flyte/_resources.py +473 -0
  73. flyte/_retry.py +32 -0
  74. flyte/_reusable_environment.py +102 -0
  75. flyte/_run.py +724 -0
  76. flyte/_secret.py +96 -0
  77. flyte/_task.py +550 -0
  78. flyte/_task_environment.py +316 -0
  79. flyte/_task_plugins.py +47 -0
  80. flyte/_timeout.py +47 -0
  81. flyte/_tools.py +27 -0
  82. flyte/_trace.py +119 -0
  83. flyte/_trigger.py +1000 -0
  84. flyte/_utils/__init__.py +30 -0
  85. flyte/_utils/asyn.py +121 -0
  86. flyte/_utils/async_cache.py +139 -0
  87. flyte/_utils/coro_management.py +27 -0
  88. flyte/_utils/docker_credentials.py +173 -0
  89. flyte/_utils/file_handling.py +72 -0
  90. flyte/_utils/helpers.py +134 -0
  91. flyte/_utils/lazy_module.py +54 -0
  92. flyte/_utils/module_loader.py +104 -0
  93. flyte/_utils/org_discovery.py +57 -0
  94. flyte/_utils/uv_script_parser.py +49 -0
  95. flyte/_version.py +34 -0
  96. flyte/app/__init__.py +22 -0
  97. flyte/app/_app_environment.py +157 -0
  98. flyte/app/_deploy.py +125 -0
  99. flyte/app/_input.py +160 -0
  100. flyte/app/_runtime/__init__.py +3 -0
  101. flyte/app/_runtime/app_serde.py +347 -0
  102. flyte/app/_types.py +101 -0
  103. flyte/app/extras/__init__.py +3 -0
  104. flyte/app/extras/_fastapi.py +151 -0
  105. flyte/cli/__init__.py +12 -0
  106. flyte/cli/_abort.py +28 -0
  107. flyte/cli/_build.py +114 -0
  108. flyte/cli/_common.py +468 -0
  109. flyte/cli/_create.py +371 -0
  110. flyte/cli/_delete.py +45 -0
  111. flyte/cli/_deploy.py +293 -0
  112. flyte/cli/_gen.py +176 -0
  113. flyte/cli/_get.py +370 -0
  114. flyte/cli/_option.py +33 -0
  115. flyte/cli/_params.py +554 -0
  116. flyte/cli/_plugins.py +209 -0
  117. flyte/cli/_run.py +597 -0
  118. flyte/cli/_serve.py +64 -0
  119. flyte/cli/_update.py +37 -0
  120. flyte/cli/_user.py +17 -0
  121. flyte/cli/main.py +221 -0
  122. flyte/config/__init__.py +3 -0
  123. flyte/config/_config.py +248 -0
  124. flyte/config/_internal.py +73 -0
  125. flyte/config/_reader.py +225 -0
  126. flyte/connectors/__init__.py +11 -0
  127. flyte/connectors/_connector.py +270 -0
  128. flyte/connectors/_server.py +197 -0
  129. flyte/connectors/utils.py +135 -0
  130. flyte/errors.py +243 -0
  131. flyte/extend.py +19 -0
  132. flyte/extras/__init__.py +5 -0
  133. flyte/extras/_container.py +286 -0
  134. flyte/git/__init__.py +3 -0
  135. flyte/git/_config.py +21 -0
  136. flyte/io/__init__.py +29 -0
  137. flyte/io/_dataframe/__init__.py +131 -0
  138. flyte/io/_dataframe/basic_dfs.py +223 -0
  139. flyte/io/_dataframe/dataframe.py +1026 -0
  140. flyte/io/_dir.py +910 -0
  141. flyte/io/_file.py +914 -0
  142. flyte/io/_hashing_io.py +342 -0
  143. flyte/models.py +479 -0
  144. flyte/py.typed +0 -0
  145. flyte/remote/__init__.py +35 -0
  146. flyte/remote/_action.py +738 -0
  147. flyte/remote/_app.py +57 -0
  148. flyte/remote/_client/__init__.py +0 -0
  149. flyte/remote/_client/_protocols.py +189 -0
  150. flyte/remote/_client/auth/__init__.py +12 -0
  151. flyte/remote/_client/auth/_auth_utils.py +14 -0
  152. flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
  153. flyte/remote/_client/auth/_authenticators/base.py +403 -0
  154. flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
  155. flyte/remote/_client/auth/_authenticators/device_code.py +117 -0
  156. flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
  157. flyte/remote/_client/auth/_authenticators/factory.py +200 -0
  158. flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
  159. flyte/remote/_client/auth/_channel.py +213 -0
  160. flyte/remote/_client/auth/_client_config.py +85 -0
  161. flyte/remote/_client/auth/_default_html.py +32 -0
  162. flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
  163. flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
  164. flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
  165. flyte/remote/_client/auth/_keyring.py +152 -0
  166. flyte/remote/_client/auth/_token_client.py +260 -0
  167. flyte/remote/_client/auth/errors.py +16 -0
  168. flyte/remote/_client/controlplane.py +128 -0
  169. flyte/remote/_common.py +30 -0
  170. flyte/remote/_console.py +19 -0
  171. flyte/remote/_data.py +161 -0
  172. flyte/remote/_logs.py +185 -0
  173. flyte/remote/_project.py +88 -0
  174. flyte/remote/_run.py +386 -0
  175. flyte/remote/_secret.py +142 -0
  176. flyte/remote/_task.py +527 -0
  177. flyte/remote/_trigger.py +306 -0
  178. flyte/remote/_user.py +33 -0
  179. flyte/report/__init__.py +3 -0
  180. flyte/report/_report.py +182 -0
  181. flyte/report/_template.html +124 -0
  182. flyte/storage/__init__.py +36 -0
  183. flyte/storage/_config.py +237 -0
  184. flyte/storage/_parallel_reader.py +274 -0
  185. flyte/storage/_remote_fs.py +34 -0
  186. flyte/storage/_storage.py +456 -0
  187. flyte/storage/_utils.py +5 -0
  188. flyte/syncify/__init__.py +56 -0
  189. flyte/syncify/_api.py +375 -0
  190. flyte/types/__init__.py +52 -0
  191. flyte/types/_interface.py +40 -0
  192. flyte/types/_pickle.py +145 -0
  193. flyte/types/_renderer.py +162 -0
  194. flyte/types/_string_literals.py +119 -0
  195. flyte/types/_type_engine.py +2254 -0
  196. flyte/types/_utils.py +80 -0
  197. flyte-2.0.0b32.data/scripts/debug.py +38 -0
  198. flyte-2.0.0b32.data/scripts/runtime.py +195 -0
  199. flyte-2.0.0b32.dist-info/METADATA +351 -0
  200. flyte-2.0.0b32.dist-info/RECORD +204 -0
  201. flyte-2.0.0b32.dist-info/WHEEL +5 -0
  202. flyte-2.0.0b32.dist-info/entry_points.txt +7 -0
  203. flyte-2.0.0b32.dist-info/licenses/LICENSE +201 -0
  204. flyte-2.0.0b32.dist-info/top_level.txt +1 -0
flyte/remote/_run.py ADDED
@@ -0,0 +1,386 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import AsyncGenerator, AsyncIterator, Literal, Tuple
5
+
6
+ import grpc
7
+ import rich.repr
8
+ from flyteidl2.common import identifier_pb2, list_pb2
9
+ from flyteidl2.workflow import run_definition_pb2, run_service_pb2
10
+
11
+ from flyte._initialize import ensure_client, get_client, get_init_config
12
+ from flyte._logging import logger
13
+ from flyte.syncify import syncify
14
+
15
+ from . import Action, ActionDetails, ActionInputs, ActionOutputs
16
+ from ._action import _action_details_rich_repr, _action_rich_repr
17
+ from ._common import ToJSONMixin
18
+ from ._console import get_run_url
19
+
20
+ # @kumare3 is sadpanda, because we have to create a mirror of phase types here, because protobuf phases are ghastly
21
+ Phase = Literal[
22
+ "queued", "waiting_for_resources", "initializing", "running", "succeeded", "failed", "aborted", "timed_out"
23
+ ]
24
+
25
+
26
+ @dataclass
27
+ class Run(ToJSONMixin):
28
+ """
29
+ A class representing a run of a task. It is used to manage the run of a task and its state on the remote
30
+ Union API.
31
+ """
32
+
33
+ pb2: run_definition_pb2.Run
34
+ action: Action = field(init=False)
35
+ _details: RunDetails | None = None
36
+
37
+ def __post_init__(self):
38
+ """
39
+ Initialize the Run object with the given run definition.
40
+ """
41
+ if not self.pb2.HasField("action"):
42
+ raise RuntimeError("Run does not have an action")
43
+ self.action = Action(self.pb2.action)
44
+
45
+ @syncify
46
+ @classmethod
47
+ async def listall(
48
+ cls,
49
+ in_phase: Tuple[Phase] | None = None,
50
+ created_by_subject: str | None = None,
51
+ sort_by: Tuple[str, Literal["asc", "desc"]] | None = None,
52
+ limit: int = 100,
53
+ ) -> AsyncIterator[Run]:
54
+ """
55
+ Get all runs for the current project and domain.
56
+
57
+ :param in_phase: Filter runs by one or more phases.
58
+ :param created_by_subject: Filter runs by the subject that created them. (this is not username, but the subject)
59
+ :param sort_by: The sorting criteria for the project list, in the format (field, order).
60
+ :param limit: The maximum number of runs to return.
61
+ :return: An iterator of runs.
62
+ """
63
+ ensure_client()
64
+ token = None
65
+ sort_by = sort_by or ("created_at", "asc")
66
+ sort_pb2 = list_pb2.Sort(
67
+ key=sort_by[0],
68
+ direction=(list_pb2.Sort.ASCENDING if sort_by[1] == "asc" else list_pb2.Sort.DESCENDING),
69
+ )
70
+ filters = []
71
+ if in_phase:
72
+ phases = [str(run_definition_pb2.Phase.Value(f"PHASE_{p.upper()}")) for p in in_phase]
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
+ if created_by_subject:
91
+ logger.debug(f"Fetching runs created by: {created_by_subject}")
92
+ filters.append(
93
+ list_pb2.Filter(
94
+ function=list_pb2.Filter.Function.EQUAL,
95
+ field="created_by",
96
+ values=[created_by_subject],
97
+ ),
98
+ )
99
+
100
+ cfg = get_init_config()
101
+ i = 0
102
+ while True:
103
+ req = list_pb2.ListRequest(
104
+ limit=min(100, limit),
105
+ token=token,
106
+ sort_by=sort_pb2,
107
+ filters=filters,
108
+ )
109
+ resp = await get_client().run_service.ListRuns(
110
+ run_service_pb2.ListRunsRequest(
111
+ request=req,
112
+ org=cfg.org,
113
+ project_id=identifier_pb2.ProjectIdentifier(
114
+ organization=cfg.org,
115
+ domain=cfg.domain,
116
+ name=cfg.project,
117
+ ),
118
+ )
119
+ )
120
+ token = resp.token
121
+ for r in resp.runs:
122
+ i += 1
123
+ if i > limit:
124
+ return
125
+ yield cls(r)
126
+ if not token:
127
+ break
128
+
129
+ @syncify
130
+ @classmethod
131
+ async def get(cls, name: str) -> Run:
132
+ """
133
+ Get the current run.
134
+
135
+ :return: The current run.
136
+ """
137
+ ensure_client()
138
+ run_details: RunDetails = await RunDetails.get.aio(name=name)
139
+ run = run_definition_pb2.Run(
140
+ action=run_definition_pb2.Action(
141
+ id=run_details.action_id,
142
+ metadata=run_details.action_details.pb2.metadata,
143
+ status=run_details.action_details.pb2.status,
144
+ ),
145
+ )
146
+ return cls(pb2=run, _details=run_details)
147
+
148
+ @property
149
+ def name(self) -> str:
150
+ """
151
+ Get the name of the run.
152
+ """
153
+ return self.pb2.action.id.run.name
154
+
155
+ @property
156
+ def phase(self) -> str:
157
+ """
158
+ Get the phase of the run.
159
+ """
160
+ return self.action.phase
161
+
162
+ @property
163
+ def raw_phase(self) -> run_definition_pb2.Phase:
164
+ """
165
+ Get the raw phase of the run.
166
+ """
167
+ return self.action.raw_phase
168
+
169
+ @syncify
170
+ async def wait(self, quiet: bool = False, wait_for: Literal["terminal", "running"] = "terminal") -> None:
171
+ """
172
+ Wait for the run to complete, displaying a rich progress panel with status transitions,
173
+ time elapsed, and error details in case of failure.
174
+ """
175
+ return await self.action.wait(quiet=quiet, wait_for=wait_for)
176
+
177
+ async def watch(self, cache_data_on_done: bool = False) -> AsyncGenerator[ActionDetails, None]:
178
+ """
179
+ Get the details of the run. This is a placeholder for getting the run details.
180
+ """
181
+ return self.action.watch(cache_data_on_done=cache_data_on_done)
182
+
183
+ @syncify
184
+ async def show_logs(
185
+ self,
186
+ attempt: int | None = None,
187
+ max_lines: int = 100,
188
+ show_ts: bool = False,
189
+ raw: bool = False,
190
+ filter_system: bool = False,
191
+ ):
192
+ await self.action.show_logs.aio(attempt, max_lines, show_ts, raw, filter_system=filter_system)
193
+
194
+ @syncify
195
+ async def details(self) -> RunDetails:
196
+ """
197
+ Get the details of the run. This is a placeholder for getting the run details.
198
+ """
199
+ if self._details is None or not self._details.done():
200
+ self._details = await RunDetails.get_details.aio(self.pb2.action.id.run)
201
+ return self._details
202
+
203
+ @syncify
204
+ async def inputs(self) -> ActionInputs:
205
+ """
206
+ Get the inputs of the run. This is a placeholder for getting the run inputs.
207
+ """
208
+ details = await self.details.aio()
209
+ return await details.inputs()
210
+
211
+ @syncify
212
+ async def outputs(self) -> ActionOutputs:
213
+ """
214
+ Get the outputs of the run. This is a placeholder for getting the run outputs.
215
+ """
216
+ details = await self.details.aio()
217
+ return await details.outputs()
218
+
219
+ @property
220
+ def url(self) -> str:
221
+ """
222
+ Get the URL of the run.
223
+ """
224
+ client = get_client()
225
+ return get_run_url(
226
+ client.endpoint,
227
+ insecure=client.insecure,
228
+ project=self.pb2.action.id.run.project,
229
+ domain=self.pb2.action.id.run.domain,
230
+ run_name=self.name,
231
+ )
232
+
233
+ @syncify
234
+ async def abort(self):
235
+ """
236
+ Aborts / Terminates the run.
237
+ """
238
+ try:
239
+ await get_client().run_service.AbortRun(
240
+ run_service_pb2.AbortRunRequest(
241
+ run_id=self.pb2.action.id.run,
242
+ )
243
+ )
244
+ except grpc.aio.AioRpcError as e:
245
+ if e.code() == grpc.StatusCode.NOT_FOUND:
246
+ return
247
+ raise
248
+
249
+ def done(self) -> bool:
250
+ """
251
+ Check if the run is done.
252
+ """
253
+ return self.action.done()
254
+
255
+ def sync(self) -> Run:
256
+ """
257
+ Sync the run with the remote server. This is a placeholder for syncing the run.
258
+ """
259
+ return self
260
+
261
+ # TODO add add_done_callback, maybe implement sync apis etc
262
+
263
+ def __rich_repr__(self) -> rich.repr.Result:
264
+ """
265
+ Rich representation of the Run object.
266
+ """
267
+ yield "url", f"[blue bold][link={self.url}]link[/link][/blue bold]"
268
+ yield from _action_rich_repr(self.pb2.action)
269
+
270
+ def __repr__(self) -> str:
271
+ """
272
+ String representation of the Action object.
273
+ """
274
+ import rich.pretty
275
+
276
+ return rich.pretty.pretty_repr(self)
277
+
278
+
279
+ @dataclass
280
+ class RunDetails(ToJSONMixin):
281
+ """
282
+ A class representing a run of a task. It is used to manage the run of a task and its state on the remote
283
+ Union API.
284
+ """
285
+
286
+ pb2: run_definition_pb2.RunDetails
287
+ action_details: ActionDetails = field(init=False)
288
+
289
+ def __post_init__(self):
290
+ """
291
+ Initialize the RunDetails object with the given run definition.
292
+ """
293
+ self.action_details = ActionDetails(self.pb2.action)
294
+
295
+ @syncify
296
+ @classmethod
297
+ async def get_details(cls, run_id: identifier_pb2.RunIdentifier) -> RunDetails:
298
+ """
299
+ Get the details of the run. This is a placeholder for getting the run details.
300
+ """
301
+ ensure_client()
302
+ resp = await get_client().run_service.GetRunDetails(
303
+ run_service_pb2.GetRunDetailsRequest(
304
+ run_id=run_id,
305
+ )
306
+ )
307
+ return cls(resp.details)
308
+
309
+ @syncify
310
+ @classmethod
311
+ async def get(cls, name: str | None = None) -> RunDetails:
312
+ """
313
+ Get a run by its ID or name. If both are provided, the ID will take precedence.
314
+
315
+ :param uri: The URI of the run.
316
+ :param name: The name of the run.
317
+ """
318
+ ensure_client()
319
+ cfg = get_init_config()
320
+ return await RunDetails.get_details.aio(
321
+ run_id=identifier_pb2.RunIdentifier(
322
+ org=cfg.org,
323
+ project=cfg.project,
324
+ domain=cfg.domain,
325
+ name=name,
326
+ ),
327
+ )
328
+
329
+ @property
330
+ def name(self) -> str:
331
+ """
332
+ Get the name of the action.
333
+ """
334
+ return self.action_details.run_name
335
+
336
+ @property
337
+ def task_name(self) -> str | None:
338
+ """
339
+ Get the name of the task.
340
+ """
341
+ return self.action_details.task_name
342
+
343
+ @property
344
+ def action_id(self) -> identifier_pb2.ActionIdentifier:
345
+ """
346
+ Get the action ID.
347
+ """
348
+ return self.action_details.action_id
349
+
350
+ def done(self) -> bool:
351
+ """
352
+ Check if the run is in a terminal state (completed or failed). This is a placeholder for checking the
353
+ run state.
354
+ """
355
+ return self.action_details.done()
356
+
357
+ async def inputs(self) -> ActionInputs:
358
+ """
359
+ Placeholder for inputs. This can be extended to handle inputs from the run context.
360
+ """
361
+ return await self.action_details.inputs()
362
+
363
+ async def outputs(self) -> ActionOutputs:
364
+ """
365
+ Placeholder for outputs. This can be extended to handle outputs from the run context.
366
+ """
367
+ return await self.action_details.outputs()
368
+
369
+ def __rich_repr__(self) -> rich.repr.Result:
370
+ """
371
+ Rich representation of the Run object.
372
+ """
373
+ yield "labels", str(self.pb2.run_spec.labels)
374
+ yield "annotations", str(self.pb2.run_spec.annotations)
375
+ yield "env-vars", str(self.pb2.run_spec.envs)
376
+ yield "is-interruptible", str(self.pb2.run_spec.interruptible)
377
+ yield "cache-overwrite", self.pb2.run_spec.overwrite_cache
378
+ yield from _action_details_rich_repr(self.pb2.action)
379
+
380
+ def __repr__(self) -> str:
381
+ """
382
+ String representation of the Action object.
383
+ """
384
+ import rich.pretty
385
+
386
+ return rich.pretty.pretty_repr(self)
@@ -0,0 +1,142 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import AsyncIterator, Literal, Union
5
+
6
+ import rich.repr
7
+ from flyteidl2.secret import definition_pb2, payload_pb2
8
+
9
+ from flyte._initialize import ensure_client, get_client, get_init_config
10
+ from flyte.remote._common import ToJSONMixin
11
+ from flyte.syncify import syncify
12
+
13
+ SecretTypes = Literal["regular", "image_pull"]
14
+
15
+
16
+ @dataclass
17
+ class Secret(ToJSONMixin):
18
+ pb2: definition_pb2.Secret
19
+
20
+ @syncify
21
+ @classmethod
22
+ async def create(cls, name: str, value: Union[str, bytes], type: SecretTypes = "regular"):
23
+ ensure_client()
24
+ cfg = get_init_config()
25
+ project = cfg.project
26
+ domain = cfg.domain
27
+
28
+ if type == "regular":
29
+ secret_type = definition_pb2.SecretType.SECRET_TYPE_GENERIC
30
+
31
+ else:
32
+ secret_type = definition_pb2.SecretType.SECRET_TYPE_IMAGE_PULL_SECRET
33
+ if project or domain:
34
+ raise ValueError(
35
+ f"Project `{project}` or domain `{domain}` should not be set when creating the image pull secret."
36
+ )
37
+
38
+ if isinstance(value, str):
39
+ secret = definition_pb2.SecretSpec(
40
+ type=secret_type,
41
+ string_value=value,
42
+ )
43
+ else:
44
+ secret = definition_pb2.SecretSpec(
45
+ type=secret_type,
46
+ binary_value=value,
47
+ )
48
+ await get_client().secrets_service.CreateSecret( # type: ignore
49
+ request=payload_pb2.CreateSecretRequest(
50
+ id=definition_pb2.SecretIdentifier(
51
+ organization=cfg.org,
52
+ project=project,
53
+ domain=domain,
54
+ name=name,
55
+ ),
56
+ secret_spec=secret,
57
+ ),
58
+ )
59
+
60
+ @syncify
61
+ @classmethod
62
+ async def get(cls, name: str) -> Secret:
63
+ ensure_client()
64
+ cfg = get_init_config()
65
+ resp = await get_client().secrets_service.GetSecret(
66
+ request=payload_pb2.GetSecretRequest(
67
+ id=definition_pb2.SecretIdentifier(
68
+ organization=cfg.org,
69
+ project=cfg.project,
70
+ domain=cfg.domain,
71
+ name=name,
72
+ )
73
+ )
74
+ )
75
+ return Secret(pb2=resp.secret)
76
+
77
+ @syncify
78
+ @classmethod
79
+ async def listall(cls, limit: int = 10) -> AsyncIterator[Secret]:
80
+ ensure_client()
81
+ cfg = get_init_config()
82
+ per_cluster_tokens = None
83
+ while True:
84
+ resp = await get_client().secrets_service.ListSecrets( # type: ignore
85
+ request=payload_pb2.ListSecretsRequest(
86
+ organization=cfg.org,
87
+ project=cfg.project,
88
+ domain=cfg.domain,
89
+ per_cluster_tokens=per_cluster_tokens,
90
+ limit=limit,
91
+ ),
92
+ )
93
+ per_cluster_tokens = resp.per_cluster_tokens
94
+ round_items = [v for _, v in per_cluster_tokens.items() if v]
95
+ has_next = any(round_items)
96
+ for r in resp.secrets:
97
+ yield cls(r)
98
+ if not has_next:
99
+ break
100
+
101
+ @syncify
102
+ @classmethod
103
+ async def delete(cls, name):
104
+ ensure_client()
105
+ cfg = get_init_config()
106
+ await get_client().secrets_service.DeleteSecret( # type: ignore
107
+ request=payload_pb2.DeleteSecretRequest(
108
+ id=definition_pb2.SecretIdentifier(
109
+ organization=cfg.org,
110
+ project=cfg.project,
111
+ domain=cfg.domain,
112
+ name=name,
113
+ )
114
+ )
115
+ )
116
+
117
+ @property
118
+ def name(self) -> str:
119
+ return self.pb2.id.name
120
+
121
+ @property
122
+ def type(self) -> str:
123
+ if self.pb2.secret_metadata.type == definition_pb2.SecretType.SECRET_TYPE_GENERIC:
124
+ return "regular"
125
+ elif self.pb2.secret_metadata.type == definition_pb2.SecretType.SECRET_TYPE_IMAGE_PULL_SECRET:
126
+ return "image_pull"
127
+ raise ValueError("unknown type")
128
+
129
+ def __rich_repr__(self) -> rich.repr.Result:
130
+ yield "project", self.pb2.id.project or "-"
131
+ yield "domain", self.pb2.id.domain or "-"
132
+ yield "name", self.name
133
+ yield "type", self.type
134
+ yield "created_time", self.pb2.secret_metadata.created_time.ToDatetime().isoformat()
135
+ yield "status", definition_pb2.OverallStatus.Name(self.pb2.secret_metadata.secret_status.overall_status)
136
+ yield (
137
+ "cluster_status",
138
+ {
139
+ s.cluster.name: definition_pb2.SecretPresenceStatus.Name(s.presence_status)
140
+ for s in self.pb2.secret_metadata.secret_status.cluster_status
141
+ },
142
+ )