flyte 0.1.0__py3-none-any.whl → 0.2.0a0__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.
- flyte/__init__.py +78 -2
- flyte/_bin/__init__.py +0 -0
- flyte/_bin/runtime.py +152 -0
- flyte/_build.py +26 -0
- flyte/_cache/__init__.py +12 -0
- flyte/_cache/cache.py +145 -0
- flyte/_cache/defaults.py +9 -0
- flyte/_cache/policy_function_body.py +42 -0
- flyte/_code_bundle/__init__.py +8 -0
- flyte/_code_bundle/_ignore.py +113 -0
- flyte/_code_bundle/_packaging.py +187 -0
- flyte/_code_bundle/_utils.py +323 -0
- flyte/_code_bundle/bundle.py +209 -0
- flyte/_context.py +152 -0
- flyte/_deploy.py +243 -0
- flyte/_doc.py +29 -0
- flyte/_docstring.py +32 -0
- flyte/_environment.py +84 -0
- flyte/_excepthook.py +37 -0
- flyte/_group.py +32 -0
- flyte/_hash.py +23 -0
- flyte/_image.py +762 -0
- flyte/_initialize.py +492 -0
- flyte/_interface.py +84 -0
- flyte/_internal/__init__.py +3 -0
- flyte/_internal/controllers/__init__.py +128 -0
- flyte/_internal/controllers/_local_controller.py +193 -0
- flyte/_internal/controllers/_trace.py +41 -0
- flyte/_internal/controllers/remote/__init__.py +60 -0
- flyte/_internal/controllers/remote/_action.py +146 -0
- flyte/_internal/controllers/remote/_client.py +47 -0
- flyte/_internal/controllers/remote/_controller.py +494 -0
- flyte/_internal/controllers/remote/_core.py +410 -0
- flyte/_internal/controllers/remote/_informer.py +361 -0
- flyte/_internal/controllers/remote/_service_protocol.py +50 -0
- flyte/_internal/imagebuild/__init__.py +11 -0
- flyte/_internal/imagebuild/docker_builder.py +427 -0
- flyte/_internal/imagebuild/image_builder.py +246 -0
- flyte/_internal/imagebuild/remote_builder.py +0 -0
- flyte/_internal/resolvers/__init__.py +0 -0
- flyte/_internal/resolvers/_task_module.py +54 -0
- flyte/_internal/resolvers/common.py +31 -0
- flyte/_internal/resolvers/default.py +28 -0
- flyte/_internal/runtime/__init__.py +0 -0
- flyte/_internal/runtime/convert.py +342 -0
- flyte/_internal/runtime/entrypoints.py +135 -0
- flyte/_internal/runtime/io.py +136 -0
- flyte/_internal/runtime/resources_serde.py +138 -0
- flyte/_internal/runtime/task_serde.py +330 -0
- flyte/_internal/runtime/taskrunner.py +191 -0
- flyte/_internal/runtime/types_serde.py +54 -0
- flyte/_logging.py +135 -0
- flyte/_map.py +215 -0
- flyte/_pod.py +19 -0
- flyte/_protos/__init__.py +0 -0
- flyte/_protos/common/authorization_pb2.py +66 -0
- flyte/_protos/common/authorization_pb2.pyi +108 -0
- flyte/_protos/common/authorization_pb2_grpc.py +4 -0
- flyte/_protos/common/identifier_pb2.py +71 -0
- flyte/_protos/common/identifier_pb2.pyi +82 -0
- flyte/_protos/common/identifier_pb2_grpc.py +4 -0
- flyte/_protos/common/identity_pb2.py +48 -0
- flyte/_protos/common/identity_pb2.pyi +72 -0
- flyte/_protos/common/identity_pb2_grpc.py +4 -0
- flyte/_protos/common/list_pb2.py +36 -0
- flyte/_protos/common/list_pb2.pyi +71 -0
- flyte/_protos/common/list_pb2_grpc.py +4 -0
- flyte/_protos/common/policy_pb2.py +37 -0
- flyte/_protos/common/policy_pb2.pyi +27 -0
- flyte/_protos/common/policy_pb2_grpc.py +4 -0
- flyte/_protos/common/role_pb2.py +37 -0
- flyte/_protos/common/role_pb2.pyi +53 -0
- flyte/_protos/common/role_pb2_grpc.py +4 -0
- flyte/_protos/common/runtime_version_pb2.py +28 -0
- flyte/_protos/common/runtime_version_pb2.pyi +24 -0
- flyte/_protos/common/runtime_version_pb2_grpc.py +4 -0
- flyte/_protos/logs/dataplane/payload_pb2.py +100 -0
- flyte/_protos/logs/dataplane/payload_pb2.pyi +177 -0
- flyte/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
- flyte/_protos/secret/definition_pb2.py +49 -0
- flyte/_protos/secret/definition_pb2.pyi +93 -0
- flyte/_protos/secret/definition_pb2_grpc.py +4 -0
- flyte/_protos/secret/payload_pb2.py +62 -0
- flyte/_protos/secret/payload_pb2.pyi +94 -0
- flyte/_protos/secret/payload_pb2_grpc.py +4 -0
- flyte/_protos/secret/secret_pb2.py +38 -0
- flyte/_protos/secret/secret_pb2.pyi +6 -0
- flyte/_protos/secret/secret_pb2_grpc.py +198 -0
- flyte/_protos/secret/secret_pb2_grpc_grpc.py +198 -0
- flyte/_protos/validate/validate/validate_pb2.py +76 -0
- flyte/_protos/workflow/common_pb2.py +27 -0
- flyte/_protos/workflow/common_pb2.pyi +14 -0
- flyte/_protos/workflow/common_pb2_grpc.py +4 -0
- flyte/_protos/workflow/environment_pb2.py +29 -0
- flyte/_protos/workflow/environment_pb2.pyi +12 -0
- flyte/_protos/workflow/environment_pb2_grpc.py +4 -0
- flyte/_protos/workflow/node_execution_service_pb2.py +26 -0
- flyte/_protos/workflow/node_execution_service_pb2.pyi +4 -0
- flyte/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
- flyte/_protos/workflow/queue_service_pb2.py +105 -0
- flyte/_protos/workflow/queue_service_pb2.pyi +146 -0
- flyte/_protos/workflow/queue_service_pb2_grpc.py +172 -0
- flyte/_protos/workflow/run_definition_pb2.py +128 -0
- flyte/_protos/workflow/run_definition_pb2.pyi +314 -0
- flyte/_protos/workflow/run_definition_pb2_grpc.py +4 -0
- flyte/_protos/workflow/run_logs_service_pb2.py +41 -0
- flyte/_protos/workflow/run_logs_service_pb2.pyi +28 -0
- flyte/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
- flyte/_protos/workflow/run_service_pb2.py +129 -0
- flyte/_protos/workflow/run_service_pb2.pyi +171 -0
- flyte/_protos/workflow/run_service_pb2_grpc.py +412 -0
- flyte/_protos/workflow/state_service_pb2.py +66 -0
- flyte/_protos/workflow/state_service_pb2.pyi +75 -0
- flyte/_protos/workflow/state_service_pb2_grpc.py +138 -0
- flyte/_protos/workflow/task_definition_pb2.py +79 -0
- flyte/_protos/workflow/task_definition_pb2.pyi +81 -0
- flyte/_protos/workflow/task_definition_pb2_grpc.py +4 -0
- flyte/_protos/workflow/task_service_pb2.py +60 -0
- flyte/_protos/workflow/task_service_pb2.pyi +59 -0
- flyte/_protos/workflow/task_service_pb2_grpc.py +138 -0
- flyte/_resources.py +226 -0
- flyte/_retry.py +32 -0
- flyte/_reusable_environment.py +25 -0
- flyte/_run.py +482 -0
- flyte/_secret.py +61 -0
- flyte/_task.py +449 -0
- flyte/_task_environment.py +183 -0
- flyte/_timeout.py +47 -0
- flyte/_tools.py +27 -0
- flyte/_trace.py +120 -0
- flyte/_utils/__init__.py +26 -0
- flyte/_utils/asyn.py +119 -0
- flyte/_utils/async_cache.py +139 -0
- flyte/_utils/coro_management.py +23 -0
- flyte/_utils/file_handling.py +72 -0
- flyte/_utils/helpers.py +134 -0
- flyte/_utils/lazy_module.py +54 -0
- flyte/_utils/org_discovery.py +57 -0
- flyte/_utils/uv_script_parser.py +49 -0
- flyte/_version.py +21 -0
- flyte/cli/__init__.py +3 -0
- flyte/cli/_abort.py +28 -0
- flyte/cli/_common.py +337 -0
- flyte/cli/_create.py +145 -0
- flyte/cli/_delete.py +23 -0
- flyte/cli/_deploy.py +152 -0
- flyte/cli/_gen.py +163 -0
- flyte/cli/_get.py +310 -0
- flyte/cli/_params.py +538 -0
- flyte/cli/_run.py +231 -0
- flyte/cli/main.py +166 -0
- flyte/config/__init__.py +3 -0
- flyte/config/_config.py +216 -0
- flyte/config/_internal.py +64 -0
- flyte/config/_reader.py +207 -0
- flyte/connectors/__init__.py +0 -0
- flyte/errors.py +172 -0
- flyte/extras/__init__.py +5 -0
- flyte/extras/_container.py +263 -0
- flyte/io/__init__.py +27 -0
- flyte/io/_dir.py +448 -0
- flyte/io/_file.py +467 -0
- flyte/io/_structured_dataset/__init__.py +129 -0
- flyte/io/_structured_dataset/basic_dfs.py +219 -0
- flyte/io/_structured_dataset/structured_dataset.py +1061 -0
- flyte/models.py +391 -0
- flyte/remote/__init__.py +26 -0
- flyte/remote/_client/__init__.py +0 -0
- flyte/remote/_client/_protocols.py +133 -0
- flyte/remote/_client/auth/__init__.py +12 -0
- flyte/remote/_client/auth/_auth_utils.py +14 -0
- flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
- flyte/remote/_client/auth/_authenticators/base.py +397 -0
- flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
- flyte/remote/_client/auth/_authenticators/device_code.py +118 -0
- flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
- flyte/remote/_client/auth/_authenticators/factory.py +200 -0
- flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
- flyte/remote/_client/auth/_channel.py +215 -0
- flyte/remote/_client/auth/_client_config.py +83 -0
- flyte/remote/_client/auth/_default_html.py +32 -0
- flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
- flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
- flyte/remote/_client/auth/_keyring.py +143 -0
- flyte/remote/_client/auth/_token_client.py +260 -0
- flyte/remote/_client/auth/errors.py +16 -0
- flyte/remote/_client/controlplane.py +95 -0
- flyte/remote/_console.py +18 -0
- flyte/remote/_data.py +159 -0
- flyte/remote/_logs.py +176 -0
- flyte/remote/_project.py +85 -0
- flyte/remote/_run.py +970 -0
- flyte/remote/_secret.py +132 -0
- flyte/remote/_task.py +391 -0
- flyte/report/__init__.py +3 -0
- flyte/report/_report.py +178 -0
- flyte/report/_template.html +124 -0
- flyte/storage/__init__.py +29 -0
- flyte/storage/_config.py +233 -0
- flyte/storage/_remote_fs.py +34 -0
- flyte/storage/_storage.py +271 -0
- flyte/storage/_utils.py +5 -0
- flyte/syncify/__init__.py +56 -0
- flyte/syncify/_api.py +371 -0
- flyte/types/__init__.py +36 -0
- flyte/types/_interface.py +40 -0
- flyte/types/_pickle.py +118 -0
- flyte/types/_renderer.py +162 -0
- flyte/types/_string_literals.py +120 -0
- flyte/types/_type_engine.py +2287 -0
- flyte/types/_utils.py +80 -0
- flyte-0.2.0a0.dist-info/METADATA +249 -0
- flyte-0.2.0a0.dist-info/RECORD +218 -0
- {flyte-0.1.0.dist-info → flyte-0.2.0a0.dist-info}/WHEEL +2 -1
- flyte-0.2.0a0.dist-info/entry_points.txt +3 -0
- flyte-0.2.0a0.dist-info/top_level.txt +1 -0
- flyte-0.1.0.dist-info/METADATA +0 -6
- flyte-0.1.0.dist-info/RECORD +0 -5
flyte/cli/_delete.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import rich_click as click
|
|
2
|
+
|
|
3
|
+
import flyte.cli._common as common
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@click.group(name="delete")
|
|
7
|
+
def delete():
|
|
8
|
+
"""
|
|
9
|
+
Remove resources from a Flyte deployment.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@delete.command(cls=common.CommandBase)
|
|
14
|
+
@click.argument("name", type=str, required=True)
|
|
15
|
+
@click.pass_obj
|
|
16
|
+
def secret(cfg: common.CLIConfig, name: str, project: str | None = None, domain: str | None = None):
|
|
17
|
+
"""
|
|
18
|
+
Delete a secret. The name of the secret is required.
|
|
19
|
+
"""
|
|
20
|
+
from flyte.remote import Secret
|
|
21
|
+
|
|
22
|
+
cfg.init(project, domain)
|
|
23
|
+
Secret.delete(name=name)
|
flyte/cli/_deploy.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from dataclasses import dataclass, field, fields
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from types import ModuleType
|
|
4
|
+
from typing import Any, Dict, List, cast, get_args
|
|
5
|
+
|
|
6
|
+
import click
|
|
7
|
+
from click import Context
|
|
8
|
+
|
|
9
|
+
import flyte
|
|
10
|
+
|
|
11
|
+
from .._code_bundle._utils import CopyFiles
|
|
12
|
+
from . import _common as common
|
|
13
|
+
from ._common import CLIConfig
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class DeployArguments:
|
|
18
|
+
project: str = field(
|
|
19
|
+
default=cast(str, common.PROJECT_OPTION.default), metadata={"click.option": common.PROJECT_OPTION}
|
|
20
|
+
)
|
|
21
|
+
domain: str = field(
|
|
22
|
+
default=cast(str, common.DOMAIN_OPTION.default), metadata={"click.option": common.DOMAIN_OPTION}
|
|
23
|
+
)
|
|
24
|
+
version: str = field(
|
|
25
|
+
default="",
|
|
26
|
+
metadata={
|
|
27
|
+
"click.option": click.Option(
|
|
28
|
+
["--version"],
|
|
29
|
+
type=str,
|
|
30
|
+
help="Version of the environment to deploy",
|
|
31
|
+
)
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
dry_run: bool = field(default=False, metadata={"click.option": common.DRY_RUN_OPTION})
|
|
35
|
+
local: bool = field(
|
|
36
|
+
default=False,
|
|
37
|
+
metadata={
|
|
38
|
+
"click.option": click.Option(
|
|
39
|
+
["--local"],
|
|
40
|
+
is_flag=True,
|
|
41
|
+
help="Run the task locally",
|
|
42
|
+
)
|
|
43
|
+
},
|
|
44
|
+
)
|
|
45
|
+
copy_style: CopyFiles = field(
|
|
46
|
+
default="loaded_modules",
|
|
47
|
+
metadata={
|
|
48
|
+
"click.option": click.Option(
|
|
49
|
+
["--copy-style"],
|
|
50
|
+
type=click.Choice(get_args(CopyFiles)),
|
|
51
|
+
default="loaded_modules",
|
|
52
|
+
help="Copy style to use when running the task",
|
|
53
|
+
)
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_dict(cls, d: Dict[str, Any]) -> "DeployArguments":
|
|
59
|
+
return cls(**d)
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def options(cls) -> List[click.Option]:
|
|
63
|
+
"""
|
|
64
|
+
Return the set of base parameters added to every flyte run workflow subcommand.
|
|
65
|
+
"""
|
|
66
|
+
return [common.get_option_from_metadata(f.metadata) for f in fields(cls) if f.metadata]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class DeployEnvCommand(click.Command):
|
|
70
|
+
def __init__(self, obj_name: str, obj: Any, deploy_args: DeployArguments, *args, **kwargs):
|
|
71
|
+
self.obj_name = obj_name
|
|
72
|
+
self.obj = obj
|
|
73
|
+
self.deploy_args = deploy_args
|
|
74
|
+
super().__init__(*args, **kwargs)
|
|
75
|
+
|
|
76
|
+
def invoke(self, ctx: Context):
|
|
77
|
+
from rich.console import Console
|
|
78
|
+
|
|
79
|
+
console = Console()
|
|
80
|
+
console.print(f"Deploying root - environment: {self.obj_name}")
|
|
81
|
+
obj: CLIConfig = ctx.obj
|
|
82
|
+
obj.init(self.deploy_args.project, self.deploy_args.domain)
|
|
83
|
+
with console.status("Deploying...", spinner="dots"):
|
|
84
|
+
deployment = flyte.deploy(
|
|
85
|
+
self.obj,
|
|
86
|
+
dryrun=self.deploy_args.dry_run,
|
|
87
|
+
copy_style=self.deploy_args.copy_style,
|
|
88
|
+
version=self.deploy_args.version,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
console.print(common.get_table("Environments", deployment.env_repr()))
|
|
92
|
+
console.print(common.get_table("Tasks", deployment.task_repr()))
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class EnvPerFileGroup(common.ObjectsPerFileGroup):
|
|
96
|
+
"""
|
|
97
|
+
Group that creates a command for each task in the current directory that is not `__init__.py`.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
def __init__(self, filename: Path, deploy_args: DeployArguments, *args, **kwargs):
|
|
101
|
+
args = (filename, *args)
|
|
102
|
+
super().__init__(*args, **kwargs)
|
|
103
|
+
self.deploy_args = deploy_args
|
|
104
|
+
|
|
105
|
+
def _filter_objects(self, module: ModuleType) -> Dict[str, Any]:
|
|
106
|
+
return {k: v for k, v in module.__dict__.items() if isinstance(v, flyte.Environment)}
|
|
107
|
+
|
|
108
|
+
def _get_command_for_obj(self, ctx: click.Context, obj_name: str, obj: Any) -> click.Command:
|
|
109
|
+
obj = cast(flyte.Environment, obj)
|
|
110
|
+
return DeployEnvCommand(
|
|
111
|
+
name=obj_name,
|
|
112
|
+
obj_name=obj_name,
|
|
113
|
+
obj=obj,
|
|
114
|
+
help=f"{obj.name}" + (f": {obj.description}" if obj.description else ""),
|
|
115
|
+
deploy_args=self.deploy_args,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class EnvFiles(common.FileGroup):
|
|
120
|
+
"""
|
|
121
|
+
Group that creates a command for each file in the current directory that is not `__init__.py`.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
common_options_enabled = False
|
|
125
|
+
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
*args,
|
|
129
|
+
**kwargs,
|
|
130
|
+
):
|
|
131
|
+
if "params" not in kwargs:
|
|
132
|
+
kwargs["params"] = []
|
|
133
|
+
kwargs["params"].extend(DeployArguments.options())
|
|
134
|
+
super().__init__(*args, **kwargs)
|
|
135
|
+
|
|
136
|
+
def get_command(self, ctx, filename):
|
|
137
|
+
deploy_args = DeployArguments.from_dict(ctx.params)
|
|
138
|
+
return EnvPerFileGroup(
|
|
139
|
+
filename=Path(filename),
|
|
140
|
+
deploy_args=deploy_args,
|
|
141
|
+
name=filename,
|
|
142
|
+
help=f"Run, functions decorated `env.task` or instances of Tasks in {filename}",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
deploy = EnvFiles(
|
|
147
|
+
name="deploy",
|
|
148
|
+
help="""
|
|
149
|
+
Deploy one or more environments from a python file.
|
|
150
|
+
This command will create or update environments in the Flyte system.
|
|
151
|
+
""",
|
|
152
|
+
)
|
flyte/cli/_gen.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import textwrap
|
|
2
|
+
from os import getcwd
|
|
3
|
+
from typing import Generator, Tuple
|
|
4
|
+
|
|
5
|
+
import rich_click as click
|
|
6
|
+
|
|
7
|
+
import flyte.cli._common as common
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@click.group(name="gen")
|
|
11
|
+
def gen():
|
|
12
|
+
"""
|
|
13
|
+
Generate documentation.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@gen.command(cls=common.CommandBase)
|
|
18
|
+
@click.option("--type", "doc_type", type=str, required=True, help="Type of documentation (valid: markdown)")
|
|
19
|
+
@click.pass_obj
|
|
20
|
+
def docs(cfg: common.CLIConfig, doc_type: str, project: str | None = None, domain: str | None = None):
|
|
21
|
+
"""
|
|
22
|
+
Generate documentation.
|
|
23
|
+
"""
|
|
24
|
+
if doc_type == "markdown":
|
|
25
|
+
markdown(cfg)
|
|
26
|
+
else:
|
|
27
|
+
raise click.ClickException("Invalid documentation type: {}".format(doc_type))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def walk_commands(ctx: click.Context) -> Generator[Tuple[str, click.Command], None, None]:
|
|
31
|
+
"""
|
|
32
|
+
Recursively walk a Click command tree, starting from the given context.
|
|
33
|
+
|
|
34
|
+
Yields:
|
|
35
|
+
(full_command_path, command_object)
|
|
36
|
+
"""
|
|
37
|
+
command = ctx.command
|
|
38
|
+
|
|
39
|
+
if not isinstance(command, click.Group):
|
|
40
|
+
yield ctx.command_path, command
|
|
41
|
+
else:
|
|
42
|
+
for name in command.list_commands(ctx):
|
|
43
|
+
subcommand = command.get_command(ctx, name)
|
|
44
|
+
if subcommand is None:
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
full_name = f"{ctx.command_path} {name}".strip()
|
|
48
|
+
yield full_name, subcommand
|
|
49
|
+
|
|
50
|
+
# Recurse if subcommand is a MultiCommand (i.e., has its own subcommands)
|
|
51
|
+
if isinstance(subcommand, click.Group):
|
|
52
|
+
sub_ctx = click.Context(subcommand, info_name=name, parent=ctx)
|
|
53
|
+
yield from walk_commands(sub_ctx)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def markdown(cfg: common.CLIConfig):
|
|
57
|
+
"""
|
|
58
|
+
Generate documentation in Markdown format
|
|
59
|
+
"""
|
|
60
|
+
ctx = cfg.ctx
|
|
61
|
+
|
|
62
|
+
output = []
|
|
63
|
+
output_verb_groups: dict[str, list[str]] = {}
|
|
64
|
+
output_noun_groups: dict[str, list[str]] = {}
|
|
65
|
+
|
|
66
|
+
commands = [*[("flyte", ctx.command)], *walk_commands(ctx)]
|
|
67
|
+
for cmd_path, cmd in commands:
|
|
68
|
+
output.append("")
|
|
69
|
+
|
|
70
|
+
cmd_path_parts = cmd_path.split(" ")
|
|
71
|
+
|
|
72
|
+
if len(cmd_path_parts) > 1:
|
|
73
|
+
if cmd_path_parts[1] not in output_verb_groups:
|
|
74
|
+
output_verb_groups[cmd_path_parts[1]] = []
|
|
75
|
+
if len(cmd_path_parts) > 2:
|
|
76
|
+
output_verb_groups[cmd_path_parts[1]].append(cmd_path_parts[2])
|
|
77
|
+
|
|
78
|
+
if len(cmd_path_parts) == 3:
|
|
79
|
+
if cmd_path_parts[2] not in output_noun_groups:
|
|
80
|
+
output_noun_groups[cmd_path_parts[2]] = []
|
|
81
|
+
output_noun_groups[cmd_path_parts[2]].append(cmd_path_parts[1])
|
|
82
|
+
|
|
83
|
+
output.append(f"{'#' * (len(cmd_path_parts) + 1)} {cmd_path}")
|
|
84
|
+
if cmd.help:
|
|
85
|
+
output.append("")
|
|
86
|
+
output.append(f"{dedent(cmd.help)}")
|
|
87
|
+
|
|
88
|
+
if not cmd.params:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
params = cmd.get_params(click.Context(cmd))
|
|
92
|
+
|
|
93
|
+
# Collect all data first to calculate column widths
|
|
94
|
+
table_data = []
|
|
95
|
+
for param in params:
|
|
96
|
+
if isinstance(param, click.Option):
|
|
97
|
+
# Format each option with backticks before joining
|
|
98
|
+
all_opts = param.opts + param.secondary_opts
|
|
99
|
+
if len(all_opts) == 1:
|
|
100
|
+
opts = f"`{all_opts[0]}`"
|
|
101
|
+
else:
|
|
102
|
+
opts = "".join(
|
|
103
|
+
[
|
|
104
|
+
"{{< multiline >}}",
|
|
105
|
+
"\n".join([f"`{opt}`" for opt in all_opts]),
|
|
106
|
+
"{{< /multiline >}}",
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
default_value = ""
|
|
110
|
+
if param.default is not None:
|
|
111
|
+
default_value = f"`{param.default}`"
|
|
112
|
+
default_value = default_value.replace(f"{getcwd()}/", "")
|
|
113
|
+
help_text = dedent(param.help) if param.help else ""
|
|
114
|
+
table_data.append([opts, f"`{param.type.name}`", default_value, help_text])
|
|
115
|
+
|
|
116
|
+
if not table_data:
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
# Add table header with proper alignment
|
|
120
|
+
output.append("")
|
|
121
|
+
output.append("| Option | Type | Default | Description |")
|
|
122
|
+
output.append("|--------|------|---------|-------------|")
|
|
123
|
+
|
|
124
|
+
# Add table rows with proper alignment
|
|
125
|
+
for row in table_data:
|
|
126
|
+
output.append(f"| {row[0]} | {row[1]} | {row[2]} | {row[3]} |")
|
|
127
|
+
|
|
128
|
+
output_verb_index = []
|
|
129
|
+
|
|
130
|
+
if len(output_verb_groups) > 0:
|
|
131
|
+
output_verb_index.append("| Action | On |")
|
|
132
|
+
output_verb_index.append("| ------ | -- |")
|
|
133
|
+
for verb, nouns in output_verb_groups.items():
|
|
134
|
+
entries = [f"[`{noun}`](#flyte-{verb}-{noun})" for noun in nouns]
|
|
135
|
+
output_verb_index.append(f"| `{verb}` | {', '.join(entries)} |")
|
|
136
|
+
|
|
137
|
+
output_noun_index = []
|
|
138
|
+
|
|
139
|
+
if len(output_noun_groups) > 0:
|
|
140
|
+
output_noun_index.append("| Object | Action |")
|
|
141
|
+
output_noun_index.append("| ------ | -- |")
|
|
142
|
+
for obj, actions in output_noun_groups.items():
|
|
143
|
+
entries = [f"[`{action}`](#flyte-{action}-{obj})" for action in actions]
|
|
144
|
+
output_noun_index.append(f"| `{obj}` | {', '.join(entries)} |")
|
|
145
|
+
|
|
146
|
+
print()
|
|
147
|
+
print("{{< grid >}}")
|
|
148
|
+
print("{{< markdown >}}")
|
|
149
|
+
print("\n".join(output_noun_index))
|
|
150
|
+
print("{{< /markdown >}}")
|
|
151
|
+
print("{{< markdown >}}")
|
|
152
|
+
print("\n".join(output_verb_index))
|
|
153
|
+
print("{{< /markdown >}}")
|
|
154
|
+
print("{{< /grid >}}")
|
|
155
|
+
print()
|
|
156
|
+
print("\n".join(output))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def dedent(text: str) -> str:
|
|
160
|
+
"""
|
|
161
|
+
Remove leading whitespace from a string.
|
|
162
|
+
"""
|
|
163
|
+
return textwrap.dedent(text).strip("\n")
|
flyte/cli/_get.py
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from typing import Tuple, Union
|
|
3
|
+
|
|
4
|
+
import rich_click as click
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.pretty import pretty_repr
|
|
7
|
+
|
|
8
|
+
from . import _common as common
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group(name="get")
|
|
12
|
+
def get():
|
|
13
|
+
"""
|
|
14
|
+
Retrieve resources from a Flyte deployment.
|
|
15
|
+
|
|
16
|
+
You can get information about projects, runs, tasks, actions, secrets, logs and input/output values.
|
|
17
|
+
|
|
18
|
+
Each command supports optional parameters to filter or specify the resource you want to retrieve.
|
|
19
|
+
|
|
20
|
+
Using a `get` subcommand without any arguments will retrieve a list of available resources to get.
|
|
21
|
+
For example:
|
|
22
|
+
|
|
23
|
+
* `get project` (without specifying a project), will list all projects.
|
|
24
|
+
* `get project my_project` will return the details of the project named `my_project`.
|
|
25
|
+
|
|
26
|
+
In some cases, a partially specified command will act as a filter and return available further parameters.
|
|
27
|
+
For example:
|
|
28
|
+
|
|
29
|
+
* `get action my_run` will return all actions for the run named `my_run`.
|
|
30
|
+
* `get action my_run my_action` will return the details of the action named `my_action` for the run `my_run`.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@get.command()
|
|
35
|
+
@click.argument("name", type=str, required=False)
|
|
36
|
+
@click.pass_obj
|
|
37
|
+
def project(cfg: common.CLIConfig, name: str | None = None):
|
|
38
|
+
"""
|
|
39
|
+
Get a list of all projects, or details of a specific project by name.
|
|
40
|
+
"""
|
|
41
|
+
from flyte.remote import Project
|
|
42
|
+
|
|
43
|
+
cfg.init()
|
|
44
|
+
|
|
45
|
+
console = Console()
|
|
46
|
+
if name:
|
|
47
|
+
console.print(pretty_repr(Project.get(name)))
|
|
48
|
+
else:
|
|
49
|
+
console.print(common.get_table("Projects", Project.listall()))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@get.command(cls=common.CommandBase)
|
|
53
|
+
@click.argument("name", type=str, required=False)
|
|
54
|
+
@click.pass_obj
|
|
55
|
+
def run(cfg: common.CLIConfig, name: str | None = None, project: str | None = None, domain: str | None = None):
|
|
56
|
+
"""
|
|
57
|
+
Get a list of all runs, or details of a specific run by name.
|
|
58
|
+
|
|
59
|
+
The run details will include information about the run, its status, but only the root action will be shown.
|
|
60
|
+
|
|
61
|
+
If you want to see the actions for a run, use `get action <run_name>`.
|
|
62
|
+
"""
|
|
63
|
+
from flyte.remote import Run, RunDetails
|
|
64
|
+
|
|
65
|
+
cfg.init(project=project, domain=domain)
|
|
66
|
+
|
|
67
|
+
console = Console()
|
|
68
|
+
if name:
|
|
69
|
+
details = RunDetails.get(name=name)
|
|
70
|
+
console.print(pretty_repr(details))
|
|
71
|
+
else:
|
|
72
|
+
console.print(common.get_table("Runs", Run.listall()))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@get.command(cls=common.CommandBase)
|
|
76
|
+
@click.argument("name", type=str, required=False)
|
|
77
|
+
@click.argument("version", type=str, required=False)
|
|
78
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of tasks to show.")
|
|
79
|
+
@click.pass_obj
|
|
80
|
+
def task(
|
|
81
|
+
cfg: common.CLIConfig,
|
|
82
|
+
name: str | None = None,
|
|
83
|
+
limit: int = 100,
|
|
84
|
+
version: str | None = None,
|
|
85
|
+
project: str | None = None,
|
|
86
|
+
domain: str | None = None,
|
|
87
|
+
):
|
|
88
|
+
"""
|
|
89
|
+
Retrieve a list of all tasks, or details of a specific task by name and version.
|
|
90
|
+
|
|
91
|
+
Currently, both `name` and `version` are required to get a specific task.
|
|
92
|
+
"""
|
|
93
|
+
from flyte.remote import Task
|
|
94
|
+
|
|
95
|
+
cfg.init(project=project, domain=domain)
|
|
96
|
+
|
|
97
|
+
console = Console()
|
|
98
|
+
if name:
|
|
99
|
+
if version:
|
|
100
|
+
v = Task.get(name=name, version=version)
|
|
101
|
+
if v is None:
|
|
102
|
+
raise click.BadParameter(f"Task {name} not found.")
|
|
103
|
+
t = v.fetch()
|
|
104
|
+
console.print(pretty_repr(t))
|
|
105
|
+
else:
|
|
106
|
+
console.print(common.get_table("Tasks", Task.listall(by_task_name=name, limit=limit)))
|
|
107
|
+
else:
|
|
108
|
+
console.print(common.get_table("Tasks", Task.listall(limit=limit)))
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@get.command(cls=common.CommandBase)
|
|
112
|
+
@click.argument("run_name", type=str, required=True)
|
|
113
|
+
@click.argument("action_name", type=str, required=False)
|
|
114
|
+
@click.pass_obj
|
|
115
|
+
def action(
|
|
116
|
+
cfg: common.CLIConfig,
|
|
117
|
+
run_name: str,
|
|
118
|
+
action_name: str | None = None,
|
|
119
|
+
project: str | None = None,
|
|
120
|
+
domain: str | None = None,
|
|
121
|
+
):
|
|
122
|
+
"""
|
|
123
|
+
Get all actions for a run or details for a specific action.
|
|
124
|
+
"""
|
|
125
|
+
import flyte.remote as remote
|
|
126
|
+
|
|
127
|
+
cfg.init(project=project, domain=domain)
|
|
128
|
+
|
|
129
|
+
console = Console()
|
|
130
|
+
if action_name:
|
|
131
|
+
console.print(pretty_repr(remote.Action.get(run_name=run_name, name=action_name)))
|
|
132
|
+
else:
|
|
133
|
+
# List all actions for the run
|
|
134
|
+
console.print(common.get_table(f"Actions for {run_name}", remote.Action.listall(for_run_name=run_name)))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@get.command(cls=common.CommandBase)
|
|
138
|
+
@click.argument("run_name", type=str, required=True)
|
|
139
|
+
@click.argument("action_name", type=str, required=False)
|
|
140
|
+
@click.option("--lines", "-l", type=int, default=30, help="Number of lines to show, only useful for --pretty")
|
|
141
|
+
@click.option("--show-ts", is_flag=True, help="Show timestamps")
|
|
142
|
+
@click.option(
|
|
143
|
+
"--pretty",
|
|
144
|
+
is_flag=True,
|
|
145
|
+
default=False,
|
|
146
|
+
help="Show logs in an auto-scrolling box, where number of lines is limited to `--lines`",
|
|
147
|
+
)
|
|
148
|
+
@click.option(
|
|
149
|
+
"--attempt", "-a", type=int, default=None, help="Attempt number to show logs for, defaults to the latest attempt."
|
|
150
|
+
)
|
|
151
|
+
@click.option("--filter-system", is_flag=True, default=False, help="Filter all system logs from the output.")
|
|
152
|
+
@click.pass_obj
|
|
153
|
+
def logs(
|
|
154
|
+
cfg: common.CLIConfig,
|
|
155
|
+
run_name: str,
|
|
156
|
+
action_name: str | None = None,
|
|
157
|
+
project: str | None = None,
|
|
158
|
+
domain: str | None = None,
|
|
159
|
+
lines: int = 30,
|
|
160
|
+
show_ts: bool = False,
|
|
161
|
+
pretty: bool = True,
|
|
162
|
+
attempt: int | None = None,
|
|
163
|
+
filter_system: bool = False,
|
|
164
|
+
):
|
|
165
|
+
"""
|
|
166
|
+
Stream logs for the provided run or action.
|
|
167
|
+
If only the run is provided, only the logs for the parent action will be streamed:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
$ flyte get logs my_run
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
If you want to see the logs for a specific action, you can provide the action name as well:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
$ flyte get logs my_run my_action
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
By default, logs will be shown in the raw format and will scroll the terminal.
|
|
180
|
+
If automatic scrolling and only tailing `--lines` number of lines is desired, use the `--pretty` flag:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
$ flyte get logs my_run my_action --pretty --lines 50
|
|
184
|
+
```
|
|
185
|
+
"""
|
|
186
|
+
import flyte.remote as remote
|
|
187
|
+
|
|
188
|
+
cfg.init(project=project, domain=domain)
|
|
189
|
+
|
|
190
|
+
async def _run_log_view(_obj):
|
|
191
|
+
task = asyncio.create_task(
|
|
192
|
+
_obj.show_logs(
|
|
193
|
+
max_lines=lines, show_ts=show_ts, raw=not pretty, attempt=attempt, filter_system=filter_system
|
|
194
|
+
)
|
|
195
|
+
)
|
|
196
|
+
try:
|
|
197
|
+
await task
|
|
198
|
+
except KeyboardInterrupt:
|
|
199
|
+
task.cancel()
|
|
200
|
+
|
|
201
|
+
if action_name:
|
|
202
|
+
obj = remote.Action.get(run_name=run_name, name=action_name)
|
|
203
|
+
else:
|
|
204
|
+
obj = remote.Run.get(run_name)
|
|
205
|
+
asyncio.run(_run_log_view(obj))
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@get.command(cls=common.CommandBase)
|
|
209
|
+
@click.argument("name", type=str, required=False)
|
|
210
|
+
@click.pass_obj
|
|
211
|
+
def secret(
|
|
212
|
+
cfg: common.CLIConfig,
|
|
213
|
+
name: str | None = None,
|
|
214
|
+
project: str | None = None,
|
|
215
|
+
domain: str | None = None,
|
|
216
|
+
):
|
|
217
|
+
"""
|
|
218
|
+
Get a list of all secrets, or details of a specific secret by name.
|
|
219
|
+
"""
|
|
220
|
+
import flyte.remote as remote
|
|
221
|
+
|
|
222
|
+
cfg.init(project=project, domain=domain)
|
|
223
|
+
|
|
224
|
+
console = Console()
|
|
225
|
+
if name:
|
|
226
|
+
console.print(pretty_repr(remote.Secret.get(name)))
|
|
227
|
+
else:
|
|
228
|
+
console.print(common.get_table("Secrets", remote.Secret.listall()))
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@get.command(cls=common.CommandBase)
|
|
232
|
+
@click.argument("run_name", type=str, required=True)
|
|
233
|
+
@click.argument("action_name", type=str, required=False)
|
|
234
|
+
@click.option("--inputs-only", "-i", is_flag=True, help="Show only inputs")
|
|
235
|
+
@click.option("--outputs-only", "-o", is_flag=True, help="Show only outputs")
|
|
236
|
+
@click.pass_obj
|
|
237
|
+
def io(
|
|
238
|
+
cfg: common.CLIConfig,
|
|
239
|
+
run_name: str,
|
|
240
|
+
action_name: str | None = None,
|
|
241
|
+
project: str | None = None,
|
|
242
|
+
domain: str | None = None,
|
|
243
|
+
inputs_only: bool = False,
|
|
244
|
+
outputs_only: bool = False,
|
|
245
|
+
):
|
|
246
|
+
"""
|
|
247
|
+
Get the inputs and outputs of a run or action.
|
|
248
|
+
If only the run name is provided, it will show the inputs and outputs of the root action of that run.
|
|
249
|
+
If an action name is provided, it will show the inputs and outputs for that action.
|
|
250
|
+
If `--inputs-only` or `--outputs-only` is specified, it will only show the inputs or outputs respectively.
|
|
251
|
+
|
|
252
|
+
Examples:
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
$ flyte get io my_run
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
$ flyte get io my_run my_action
|
|
260
|
+
```
|
|
261
|
+
"""
|
|
262
|
+
if inputs_only and outputs_only:
|
|
263
|
+
raise click.BadParameter("Cannot use both --inputs-only and --outputs-only")
|
|
264
|
+
|
|
265
|
+
import flyte.remote as remote
|
|
266
|
+
|
|
267
|
+
cfg.init(project=project, domain=domain)
|
|
268
|
+
console = Console()
|
|
269
|
+
if action_name:
|
|
270
|
+
obj = remote.ActionDetails.get(run_name=run_name, name=action_name)
|
|
271
|
+
else:
|
|
272
|
+
obj = remote.RunDetails.get(run_name)
|
|
273
|
+
|
|
274
|
+
async def _get_io(
|
|
275
|
+
details: Union[remote.RunDetails, remote.ActionDetails],
|
|
276
|
+
) -> Tuple[remote.ActionInputs | None, remote.ActionOutputs | None | str]:
|
|
277
|
+
if inputs_only or outputs_only:
|
|
278
|
+
if inputs_only:
|
|
279
|
+
return await details.inputs(), None
|
|
280
|
+
elif outputs_only:
|
|
281
|
+
return None, await details.outputs()
|
|
282
|
+
inputs = await details.inputs()
|
|
283
|
+
outputs: remote.ActionOutputs | None | str = None
|
|
284
|
+
try:
|
|
285
|
+
outputs = await details.outputs()
|
|
286
|
+
except Exception:
|
|
287
|
+
# If the outputs are not available, we can still show the inputs
|
|
288
|
+
outputs = "[red]not yet available[/red]"
|
|
289
|
+
return inputs, outputs
|
|
290
|
+
|
|
291
|
+
inputs, outputs = asyncio.run(_get_io(obj))
|
|
292
|
+
# Show inputs and outputs side by side
|
|
293
|
+
console.print(
|
|
294
|
+
common.get_panel(
|
|
295
|
+
"Inputs & Outputs",
|
|
296
|
+
f"[green bold]Inputs[/green bold]\n{inputs}\n\n[blue bold]Outputs[/blue bold]\n{outputs}",
|
|
297
|
+
)
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@get.command(cls=click.RichCommand)
|
|
302
|
+
@click.pass_obj
|
|
303
|
+
def config(cfg: common.CLIConfig):
|
|
304
|
+
"""
|
|
305
|
+
Shows the automatically detected configuration to connect with the remote backend.
|
|
306
|
+
|
|
307
|
+
The configuration will include the endpoint, organization, and other settings that are used by the CLI.
|
|
308
|
+
"""
|
|
309
|
+
console = Console()
|
|
310
|
+
console.print(cfg)
|