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/cli/_common.py ADDED
@@ -0,0 +1,468 @@
1
+ from __future__ import annotations
2
+
3
+ import importlib.util
4
+ import json
5
+ import logging
6
+ import os
7
+ import pathlib
8
+ import sys
9
+ from abc import abstractmethod
10
+ from dataclasses import dataclass, replace
11
+ from functools import lru_cache
12
+ from pathlib import Path
13
+ from types import MappingProxyType, ModuleType
14
+ from typing import Any, Dict, Iterable, List, Literal, Optional
15
+
16
+ import rich.box
17
+ import rich.repr
18
+ import rich_click as click
19
+ from rich.console import Console
20
+ from rich.panel import Panel
21
+ from rich.pretty import pretty_repr
22
+ from rich.table import Table
23
+ from rich.traceback import Traceback
24
+
25
+ import flyte.config
26
+ import flyte.errors
27
+ from flyte._logging import LogFormat
28
+ from flyte.config import Config
29
+
30
+ OutputFormat = Literal["table", "json", "table-simple", "json-raw"]
31
+
32
+ PREFERRED_BORDER_COLOR = "dim cyan"
33
+ PREFERRED_ACCENT_COLOR = "bold #FFD700"
34
+ HEADER_STYLE = f"{PREFERRED_ACCENT_COLOR} on black"
35
+
36
+ PROJECT_OPTION = click.Option(
37
+ param_decls=["-p", "--project"],
38
+ required=False,
39
+ type=str,
40
+ default=None,
41
+ help="Project to which this command applies.",
42
+ show_default=True,
43
+ )
44
+
45
+ DOMAIN_OPTION = click.Option(
46
+ param_decls=["-d", "--domain"],
47
+ required=False,
48
+ type=str,
49
+ default=None,
50
+ help="Domain to which this command applies.",
51
+ show_default=True,
52
+ )
53
+
54
+ DRY_RUN_OPTION = click.Option(
55
+ param_decls=["--dry-run", "--dryrun"],
56
+ required=False,
57
+ type=bool,
58
+ is_flag=True,
59
+ default=False,
60
+ help="Dry run. Do not actually call the backend service.",
61
+ show_default=True,
62
+ )
63
+
64
+
65
+ def _common_options() -> List[click.Option]:
66
+ """
67
+ Common options that will be added to all commands and groups that inherit from CommandBase or GroupBase.
68
+ """
69
+ return [PROJECT_OPTION, DOMAIN_OPTION]
70
+
71
+
72
+ # This is global state for the CLI, it is manipulated by the main command
73
+ _client_secret_options = ["client-secret", "client_secret", "clientsecret", "app-credential", "app_credential"]
74
+ _device_flow_options = ["headless", "device-flow", "device_flow"]
75
+ _pkce_options = ["pkce"]
76
+ _external_command_options = ["external-command", "external_command", "externalcommand", "command", "custom"]
77
+ ALL_AUTH_OPTIONS = _client_secret_options + _device_flow_options + _pkce_options + _external_command_options
78
+
79
+
80
+ def sanitize_auth_type(auth_type: str | None) -> str:
81
+ """
82
+ Convert the auth type to the mode that is used by the Flyte backend.
83
+ """
84
+ if auth_type is None:
85
+ return "pkce"
86
+ if auth_type.lower() in _pkce_options:
87
+ return "Pkce"
88
+ if auth_type.lower() in _device_flow_options:
89
+ return "DeviceFlow"
90
+ if auth_type.lower() in _client_secret_options:
91
+ return "ClientSecret"
92
+ if auth_type.lower() in _external_command_options:
93
+ return "ExternalCommand"
94
+ raise ValueError(f"Unknown auth type: {auth_type}. Supported types are: {ALL_AUTH_OPTIONS}.")
95
+
96
+
97
+ @rich.repr.auto
98
+ @dataclass(frozen=True)
99
+ class CLIConfig:
100
+ """
101
+ This is the global state for the CLI. It is manipulated by the main command.
102
+ """
103
+
104
+ config: Config
105
+ ctx: click.Context
106
+ log_level: int | None = logging.ERROR
107
+ log_format: LogFormat = "console"
108
+ endpoint: str | None = None
109
+ insecure: bool = False
110
+ org: str | None = None
111
+ auth_type: str | None = None
112
+ output_format: OutputFormat = "table"
113
+
114
+ def replace(self, **kwargs) -> CLIConfig:
115
+ """
116
+ Replace the global state with a new one.
117
+ """
118
+ return replace(self, **kwargs)
119
+
120
+ def init(
121
+ self,
122
+ project: str | None = None,
123
+ domain: str | None = None,
124
+ root_dir: str | None = None,
125
+ images: tuple[str, ...] | None = None,
126
+ sync_local_sys_paths: bool = True,
127
+ ):
128
+ from flyte.config._config import TaskConfig
129
+
130
+ task_cfg = TaskConfig(
131
+ org=self.org or self.config.task.org,
132
+ project=project if project is not None else self.config.task.project,
133
+ domain=domain if domain is not None else self.config.task.domain,
134
+ )
135
+
136
+ kwargs: Dict[str, Any] = {}
137
+ if self.endpoint:
138
+ kwargs["endpoint"] = self.endpoint
139
+ if self.insecure is not None:
140
+ kwargs["insecure"] = self.insecure
141
+ if self.auth_type:
142
+ kwargs["auth_mode"] = sanitize_auth_type(self.auth_type)
143
+ platform_cfg = self.config.platform.replace(**kwargs)
144
+
145
+ updated_config = self.config.with_params(platform_cfg, task_cfg)
146
+
147
+ flyte.init_from_config(
148
+ updated_config,
149
+ log_level=self.log_level,
150
+ log_format=self.log_format,
151
+ root_dir=pathlib.Path(root_dir) if root_dir else None,
152
+ images=images,
153
+ sync_local_sys_paths=sync_local_sys_paths,
154
+ )
155
+
156
+
157
+ class InvokeBaseMixin:
158
+ """
159
+ Mixin to catch grpc.RpcError, flyte.RpcError, other errors and other exceptions
160
+ and raise them as gclick.ClickException.
161
+ """
162
+
163
+ def invoke(self, ctx):
164
+ import grpc
165
+
166
+ try:
167
+ return super().invoke(ctx) # type: ignore
168
+ except grpc.aio.AioRpcError as e:
169
+ if e.code() == grpc.StatusCode.UNAUTHENTICATED:
170
+ raise click.ClickException(f"Authentication failed. Please check your credentials. {e.details()}")
171
+ if e.code() == grpc.StatusCode.NOT_FOUND:
172
+ raise click.ClickException(f"Requested object NOT FOUND. Please check your input. Error: {e.details()}")
173
+ if e.code() == grpc.StatusCode.ALREADY_EXISTS:
174
+ raise click.ClickException("Resource already exists.")
175
+ if e.code() == grpc.StatusCode.INTERNAL:
176
+ raise click.ClickException(f"Internal server error: {e.details()}")
177
+ if e.code() == grpc.StatusCode.UNAVAILABLE:
178
+ raise click.ClickException(
179
+ f"Service is currently unavailable. Please try again later. Error: {e.details()}"
180
+ )
181
+ if e.code() == grpc.StatusCode.PERMISSION_DENIED:
182
+ raise click.ClickException(f"Permission denied. Please check your access rights. Error: {e.details()}")
183
+ if e.code() == grpc.StatusCode.INVALID_ARGUMENT:
184
+ raise click.ClickException(f"Invalid argument provided. Please check your input. Error: {e.details()}")
185
+ raise click.ClickException(f"RPC error invoking command: {e!s}") from e
186
+ except flyte.errors.InitializationError as e:
187
+ raise click.ClickException(f"Initialization failed. Pass remote config for CLI. (Reason: {e})")
188
+ except flyte.errors.BaseRuntimeError as e:
189
+ raise click.ClickException(f"{e.kind} failure, {e.code}. {e}") from e
190
+ except click.exceptions.Exit as e:
191
+ # This is a normal exit, do nothing
192
+ raise e
193
+ except click.exceptions.NoArgsIsHelpError:
194
+ # Do not raise an error if no arguments are passed, just show the help message.
195
+ # https://github.com/pallets/click/pull/1489
196
+ return None
197
+ except Exception as e:
198
+ if ctx.obj and ctx.obj.log_level and ctx.obj.log_level <= logging.DEBUG:
199
+ # If the user has requested verbose output, print the full traceback
200
+ console = get_console()
201
+ console.print(Traceback.from_exception(type(e), e, e.__traceback__))
202
+ exit(1)
203
+ else:
204
+ raise click.ClickException(f"Error invoking command: {e}") from e
205
+
206
+
207
+ class CommandBase(InvokeBaseMixin, click.RichCommand):
208
+ """
209
+ Base class for all commands, that adds common options to all commands if enabled.
210
+ """
211
+
212
+ common_options_enabled = True
213
+
214
+ def __init__(self, *args, **kwargs):
215
+ if "params" not in kwargs:
216
+ kwargs["params"] = []
217
+ if self.common_options_enabled:
218
+ kwargs["params"].extend(_common_options())
219
+ super().__init__(*args, **kwargs)
220
+
221
+
222
+ class GroupBase(InvokeBaseMixin, click.RichGroup):
223
+ """
224
+ Base class for all commands, that adds common options to all commands if enabled.
225
+ """
226
+
227
+ common_options_enabled = True
228
+
229
+ def __init__(self, *args, **kwargs):
230
+ if "params" not in kwargs:
231
+ kwargs["params"] = []
232
+ if self.common_options_enabled:
233
+ kwargs["params"].extend(_common_options())
234
+ super().__init__(*args, **kwargs)
235
+
236
+
237
+ class GroupBaseNoOptions(GroupBase):
238
+ common_options_enabled = False
239
+
240
+
241
+ def get_option_from_metadata(metadata: MappingProxyType) -> click.Option:
242
+ return metadata["click.option"]
243
+
244
+
245
+ def key_value_callback(_: Any, param: str, values: List[str]) -> Optional[Dict[str, str]]:
246
+ """
247
+ Callback for click to parse key-value pairs.
248
+ """
249
+ if not values:
250
+ return None
251
+ result = {}
252
+ for v in values:
253
+ if "=" not in v:
254
+ raise click.BadParameter(f"Expected key-value pair of the form key=value, got {v}")
255
+ k, v_ = v.split("=", 1)
256
+ result[k.strip()] = v_.strip()
257
+ return result
258
+
259
+
260
+ class ObjectsPerFileGroup(GroupBase):
261
+ """
262
+ Group that creates a command for each object in a python file.
263
+ """
264
+
265
+ def __init__(self, filename: Path | None = None, *args, **kwargs):
266
+ super().__init__(*args, **kwargs)
267
+ if filename is None:
268
+ raise ValueError("filename must be provided")
269
+ if not filename.exists():
270
+ raise click.ClickException(f"{filename} does not exists")
271
+ self.filename = filename
272
+ self._objs: Dict[str, Any] | None = None
273
+
274
+ @abstractmethod
275
+ def _filter_objects(self, module: ModuleType) -> Dict[str, Any]:
276
+ """
277
+ Filter the objects in the module to only include the ones we want to expose.
278
+ """
279
+ raise NotImplementedError
280
+
281
+ @property
282
+ def objs(self) -> Dict[str, Any]:
283
+ if self._objs is not None:
284
+ return self._objs
285
+
286
+ module_name = os.path.splitext(os.path.basename(self.filename))[0]
287
+ module_path = os.path.dirname(os.path.abspath(self.filename))
288
+
289
+ spec = importlib.util.spec_from_file_location(module_name, self.filename)
290
+ if spec is None or spec.loader is None:
291
+ raise click.ClickException(f"Could not load module {module_name} from path [{self.filename}]")
292
+
293
+ module = importlib.util.module_from_spec(spec)
294
+ sys.modules[module_name] = module
295
+
296
+ sys.path.append(module_path)
297
+ spec.loader.exec_module(module)
298
+
299
+ self._objs = self._filter_objects(module)
300
+ if not self._objs:
301
+ raise click.ClickException(f"No objects found in {self.filename}")
302
+ return self._objs
303
+
304
+ def list_commands(self, ctx):
305
+ m = list(self.objs.keys())
306
+ return sorted(m)
307
+
308
+ @abstractmethod
309
+ def _get_command_for_obj(self, ctx: click.Context, obj_name: str, obj: Any) -> click.Command: ...
310
+
311
+ def get_command(self, ctx, obj_name):
312
+ obj = self.objs[obj_name]
313
+ return self._get_command_for_obj(ctx, obj_name, obj)
314
+
315
+
316
+ class FileGroup(GroupBase):
317
+ """
318
+ Group that creates a command for each file in the current directory that is not __init__.py.
319
+ """
320
+
321
+ common_options_enabled = False
322
+
323
+ def __init__(
324
+ self,
325
+ *args,
326
+ directory: Path | None = None,
327
+ **kwargs,
328
+ ):
329
+ if "params" not in kwargs:
330
+ kwargs["params"] = []
331
+ super().__init__(*args, **kwargs)
332
+ self._files = None
333
+ self._dir = directory
334
+
335
+ @property
336
+ def files(self):
337
+ if self._files is None:
338
+ directory = self._dir or Path(".").absolute()
339
+ # add python files
340
+ _files = [os.fspath(p) for p in directory.glob("*.py") if p.name != "__init__.py"]
341
+
342
+ # add directories
343
+ _files.extend(
344
+ [
345
+ os.fspath(directory / p.name)
346
+ for p in directory.iterdir()
347
+ if not p.name.startswith(("_", ".")) and p.is_dir()
348
+ ]
349
+ )
350
+
351
+ # files that are in the current directory or subdirectories of the
352
+ # current directory should be displayed as relative paths
353
+ self._files = [
354
+ str(Path(f).relative_to(Path.cwd())) if Path(f).is_relative_to(Path.cwd()) else f for f in _files
355
+ ]
356
+ return self._files
357
+
358
+ def list_commands(self, ctx):
359
+ return self.files
360
+
361
+ def get_command(self, ctx, filename):
362
+ raise NotImplementedError
363
+
364
+
365
+ def _table_format(table: Table, vals: Iterable[Any]) -> Table:
366
+ headers = None
367
+ has_rich_repr = False
368
+ for p in vals:
369
+ if hasattr(p, "__rich_repr__"):
370
+ has_rich_repr = True
371
+ elif not isinstance(p, (list, tuple)):
372
+ raise ValueError("Expected a list or tuple of values, or an object with __rich_repr__ method.")
373
+ o = list(p.__rich_repr__()) if has_rich_repr else p
374
+ if headers is None:
375
+ headers = [k for k, _ in o]
376
+ for h in headers:
377
+ table.add_column(h.capitalize(), no_wrap=True if "name" in h.casefold() else False)
378
+ table.add_row(*[str(v) for _, v in o])
379
+ return table
380
+
381
+
382
+ def format(title: str, vals: Iterable[Any], of: OutputFormat = "table") -> Table | Any:
383
+ """
384
+ Get a table from a list of values.
385
+ """
386
+ match of:
387
+ case "table-simple":
388
+ return _table_format(Table(title, box=None), vals)
389
+ case "table":
390
+ return _table_format(
391
+ Table(
392
+ title=title,
393
+ box=rich.box.SQUARE_DOUBLE_HEAD,
394
+ header_style=HEADER_STYLE,
395
+ show_header=True,
396
+ border_style=PREFERRED_BORDER_COLOR,
397
+ expand=True,
398
+ ),
399
+ vals,
400
+ )
401
+ case "json":
402
+ if not vals:
403
+ return pretty_repr([])
404
+ return pretty_repr([v.to_dict() for v in vals])
405
+ case "json-raw":
406
+ if not vals:
407
+ return []
408
+ return json.dumps([v.to_dict() for v in vals])
409
+
410
+ raise click.ClickException("Unknown output format. Supported formats are: table, table-simple, json.")
411
+
412
+
413
+ def get_panel(title: str, renderable: Any, of: OutputFormat = "table") -> Panel:
414
+ """
415
+ Get a panel from a list of values.
416
+ """
417
+ if of in ["table-simple", "json"]:
418
+ return renderable
419
+ return Panel.fit(
420
+ renderable,
421
+ title=f"[{PREFERRED_ACCENT_COLOR}]{title}[/{PREFERRED_ACCENT_COLOR}]",
422
+ border_style=PREFERRED_BORDER_COLOR,
423
+ )
424
+
425
+
426
+ def get_console() -> Console:
427
+ """
428
+ Get a console that is configured to use colors if the terminal supports it.
429
+ """
430
+ return Console(color_system="auto", force_terminal=True, width=120)
431
+
432
+
433
+ def parse_images(cfg: Config, values: tuple[str, ...] | None) -> None:
434
+ """
435
+ Parse image values and update the config.
436
+
437
+ Args:
438
+ cfg: The Config object to write images to
439
+ values: List of image strings in format "imagename=imageuri" or just "imageuri"
440
+ """
441
+ if values is None:
442
+ return
443
+ for value in values:
444
+ if "=" in value:
445
+ image_name, image_uri = value.split("=", 1)
446
+ cfg.image.image_refs[image_name] = image_uri
447
+ else:
448
+ # If no name specified, use "default" as the name
449
+ cfg.image.image_refs["default"] = value
450
+
451
+
452
+ @lru_cache()
453
+ def initialize_config(
454
+ ctx: click.Context,
455
+ project: str,
456
+ domain: str,
457
+ root_dir: str | None = None,
458
+ images: tuple[str, ...] | None = None,
459
+ sync_local_sys_paths: bool = True,
460
+ ):
461
+ obj: CLIConfig | None = ctx.obj
462
+ if obj is None:
463
+ import flyte.config
464
+
465
+ obj = CLIConfig(flyte.config.auto(), ctx)
466
+
467
+ obj.init(project, domain, root_dir, images, sync_local_sys_paths)
468
+ return obj