flyte 2.0.0b13__py3-none-any.whl → 2.0.0b30__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.
- flyte/__init__.py +18 -2
- flyte/_bin/debug.py +38 -0
- flyte/_bin/runtime.py +62 -8
- flyte/_cache/cache.py +4 -2
- flyte/_cache/local_cache.py +216 -0
- flyte/_code_bundle/_ignore.py +12 -4
- flyte/_code_bundle/_packaging.py +13 -9
- flyte/_code_bundle/_utils.py +18 -10
- flyte/_code_bundle/bundle.py +17 -9
- flyte/_constants.py +1 -0
- flyte/_context.py +4 -1
- flyte/_custom_context.py +73 -0
- flyte/_debug/constants.py +38 -0
- flyte/_debug/utils.py +17 -0
- flyte/_debug/vscode.py +307 -0
- flyte/_deploy.py +235 -61
- flyte/_environment.py +20 -6
- flyte/_excepthook.py +1 -1
- flyte/_hash.py +1 -16
- flyte/_image.py +178 -81
- flyte/_initialize.py +132 -51
- flyte/_interface.py +39 -2
- flyte/_internal/controllers/__init__.py +4 -5
- flyte/_internal/controllers/_local_controller.py +70 -29
- flyte/_internal/controllers/_trace.py +1 -1
- flyte/_internal/controllers/remote/__init__.py +0 -2
- flyte/_internal/controllers/remote/_action.py +14 -16
- flyte/_internal/controllers/remote/_client.py +1 -1
- flyte/_internal/controllers/remote/_controller.py +68 -70
- flyte/_internal/controllers/remote/_core.py +127 -99
- flyte/_internal/controllers/remote/_informer.py +19 -10
- flyte/_internal/controllers/remote/_service_protocol.py +7 -7
- flyte/_internal/imagebuild/docker_builder.py +181 -69
- flyte/_internal/imagebuild/image_builder.py +0 -5
- flyte/_internal/imagebuild/remote_builder.py +155 -64
- flyte/_internal/imagebuild/utils.py +51 -2
- flyte/_internal/resolvers/_task_module.py +5 -38
- flyte/_internal/resolvers/default.py +2 -2
- flyte/_internal/runtime/convert.py +110 -21
- flyte/_internal/runtime/entrypoints.py +27 -1
- flyte/_internal/runtime/io.py +21 -8
- flyte/_internal/runtime/resources_serde.py +20 -6
- flyte/_internal/runtime/reuse.py +1 -1
- flyte/_internal/runtime/rusty.py +20 -5
- flyte/_internal/runtime/task_serde.py +34 -19
- flyte/_internal/runtime/taskrunner.py +22 -4
- flyte/_internal/runtime/trigger_serde.py +160 -0
- flyte/_internal/runtime/types_serde.py +1 -1
- flyte/_keyring/__init__.py +0 -0
- flyte/_keyring/file.py +115 -0
- flyte/_logging.py +201 -39
- flyte/_map.py +111 -14
- flyte/_module.py +70 -0
- flyte/_pod.py +4 -3
- flyte/_resources.py +213 -31
- flyte/_run.py +110 -39
- flyte/_task.py +75 -16
- flyte/_task_environment.py +105 -29
- flyte/_task_plugins.py +4 -2
- flyte/_trace.py +5 -0
- flyte/_trigger.py +1000 -0
- flyte/_utils/__init__.py +2 -1
- flyte/_utils/asyn.py +3 -1
- flyte/_utils/coro_management.py +2 -1
- flyte/_utils/docker_credentials.py +173 -0
- flyte/_utils/module_loader.py +17 -2
- flyte/_version.py +3 -3
- flyte/cli/_abort.py +3 -3
- flyte/cli/_build.py +3 -6
- flyte/cli/_common.py +78 -7
- flyte/cli/_create.py +182 -4
- flyte/cli/_delete.py +23 -1
- flyte/cli/_deploy.py +63 -16
- flyte/cli/_get.py +79 -34
- flyte/cli/_params.py +26 -10
- flyte/cli/_plugins.py +209 -0
- flyte/cli/_run.py +151 -26
- flyte/cli/_serve.py +64 -0
- flyte/cli/_update.py +37 -0
- flyte/cli/_user.py +17 -0
- flyte/cli/main.py +30 -4
- flyte/config/_config.py +10 -6
- flyte/config/_internal.py +1 -0
- flyte/config/_reader.py +29 -8
- flyte/connectors/__init__.py +11 -0
- flyte/connectors/_connector.py +270 -0
- flyte/connectors/_server.py +197 -0
- flyte/connectors/utils.py +135 -0
- flyte/errors.py +22 -2
- flyte/extend.py +8 -1
- flyte/extras/_container.py +6 -1
- flyte/git/__init__.py +3 -0
- flyte/git/_config.py +21 -0
- flyte/io/__init__.py +2 -0
- flyte/io/_dataframe/__init__.py +2 -0
- flyte/io/_dataframe/basic_dfs.py +17 -8
- flyte/io/_dataframe/dataframe.py +98 -132
- flyte/io/_dir.py +575 -113
- flyte/io/_file.py +582 -139
- flyte/io/_hashing_io.py +342 -0
- flyte/models.py +74 -15
- flyte/remote/__init__.py +6 -1
- flyte/remote/_action.py +34 -26
- flyte/remote/_client/_protocols.py +39 -4
- flyte/remote/_client/auth/_authenticators/device_code.py +4 -5
- flyte/remote/_client/auth/_authenticators/pkce.py +1 -1
- flyte/remote/_client/auth/_channel.py +10 -6
- flyte/remote/_client/controlplane.py +17 -5
- flyte/remote/_console.py +3 -2
- flyte/remote/_data.py +6 -6
- flyte/remote/_logs.py +3 -3
- flyte/remote/_run.py +64 -8
- flyte/remote/_secret.py +26 -17
- flyte/remote/_task.py +75 -33
- flyte/remote/_trigger.py +306 -0
- flyte/remote/_user.py +33 -0
- flyte/report/_report.py +1 -1
- flyte/storage/__init__.py +6 -1
- flyte/storage/_config.py +5 -1
- flyte/storage/_parallel_reader.py +274 -0
- flyte/storage/_storage.py +200 -103
- flyte/types/__init__.py +16 -0
- flyte/types/_interface.py +2 -2
- flyte/types/_pickle.py +35 -8
- flyte/types/_string_literals.py +8 -9
- flyte/types/_type_engine.py +40 -70
- flyte/types/_utils.py +1 -1
- flyte-2.0.0b30.data/scripts/debug.py +38 -0
- {flyte-2.0.0b13.data → flyte-2.0.0b30.data}/scripts/runtime.py +62 -8
- {flyte-2.0.0b13.dist-info → flyte-2.0.0b30.dist-info}/METADATA +11 -3
- flyte-2.0.0b30.dist-info/RECORD +192 -0
- {flyte-2.0.0b13.dist-info → flyte-2.0.0b30.dist-info}/entry_points.txt +3 -0
- flyte/_protos/common/authorization_pb2.py +0 -66
- flyte/_protos/common/authorization_pb2.pyi +0 -108
- flyte/_protos/common/authorization_pb2_grpc.py +0 -4
- flyte/_protos/common/identifier_pb2.py +0 -93
- flyte/_protos/common/identifier_pb2.pyi +0 -110
- flyte/_protos/common/identifier_pb2_grpc.py +0 -4
- flyte/_protos/common/identity_pb2.py +0 -48
- flyte/_protos/common/identity_pb2.pyi +0 -72
- flyte/_protos/common/identity_pb2_grpc.py +0 -4
- flyte/_protos/common/list_pb2.py +0 -36
- flyte/_protos/common/list_pb2.pyi +0 -71
- flyte/_protos/common/list_pb2_grpc.py +0 -4
- flyte/_protos/common/policy_pb2.py +0 -37
- flyte/_protos/common/policy_pb2.pyi +0 -27
- flyte/_protos/common/policy_pb2_grpc.py +0 -4
- flyte/_protos/common/role_pb2.py +0 -37
- flyte/_protos/common/role_pb2.pyi +0 -53
- flyte/_protos/common/role_pb2_grpc.py +0 -4
- flyte/_protos/common/runtime_version_pb2.py +0 -28
- flyte/_protos/common/runtime_version_pb2.pyi +0 -24
- flyte/_protos/common/runtime_version_pb2_grpc.py +0 -4
- flyte/_protos/imagebuilder/definition_pb2.py +0 -59
- flyte/_protos/imagebuilder/definition_pb2.pyi +0 -140
- flyte/_protos/imagebuilder/definition_pb2_grpc.py +0 -4
- flyte/_protos/imagebuilder/payload_pb2.py +0 -32
- flyte/_protos/imagebuilder/payload_pb2.pyi +0 -21
- flyte/_protos/imagebuilder/payload_pb2_grpc.py +0 -4
- flyte/_protos/imagebuilder/service_pb2.py +0 -29
- flyte/_protos/imagebuilder/service_pb2.pyi +0 -5
- flyte/_protos/imagebuilder/service_pb2_grpc.py +0 -66
- flyte/_protos/logs/dataplane/payload_pb2.py +0 -100
- flyte/_protos/logs/dataplane/payload_pb2.pyi +0 -177
- flyte/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/definition_pb2.py +0 -49
- flyte/_protos/secret/definition_pb2.pyi +0 -93
- flyte/_protos/secret/definition_pb2_grpc.py +0 -4
- flyte/_protos/secret/payload_pb2.py +0 -62
- flyte/_protos/secret/payload_pb2.pyi +0 -94
- flyte/_protos/secret/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/secret_pb2.py +0 -38
- flyte/_protos/secret/secret_pb2.pyi +0 -6
- flyte/_protos/secret/secret_pb2_grpc.py +0 -198
- flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
- flyte/_protos/validate/validate/validate_pb2.py +0 -76
- flyte/_protos/workflow/common_pb2.py +0 -27
- flyte/_protos/workflow/common_pb2.pyi +0 -14
- flyte/_protos/workflow/common_pb2_grpc.py +0 -4
- flyte/_protos/workflow/environment_pb2.py +0 -29
- flyte/_protos/workflow/environment_pb2.pyi +0 -12
- flyte/_protos/workflow/environment_pb2_grpc.py +0 -4
- flyte/_protos/workflow/node_execution_service_pb2.py +0 -26
- flyte/_protos/workflow/node_execution_service_pb2.pyi +0 -4
- flyte/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
- flyte/_protos/workflow/queue_service_pb2.py +0 -109
- flyte/_protos/workflow/queue_service_pb2.pyi +0 -166
- flyte/_protos/workflow/queue_service_pb2_grpc.py +0 -172
- flyte/_protos/workflow/run_definition_pb2.py +0 -121
- flyte/_protos/workflow/run_definition_pb2.pyi +0 -327
- flyte/_protos/workflow/run_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/run_logs_service_pb2.py +0 -41
- flyte/_protos/workflow/run_logs_service_pb2.pyi +0 -28
- flyte/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
- flyte/_protos/workflow/run_service_pb2.py +0 -137
- flyte/_protos/workflow/run_service_pb2.pyi +0 -185
- flyte/_protos/workflow/run_service_pb2_grpc.py +0 -446
- flyte/_protos/workflow/state_service_pb2.py +0 -67
- flyte/_protos/workflow/state_service_pb2.pyi +0 -76
- flyte/_protos/workflow/state_service_pb2_grpc.py +0 -138
- flyte/_protos/workflow/task_definition_pb2.py +0 -79
- flyte/_protos/workflow/task_definition_pb2.pyi +0 -81
- flyte/_protos/workflow/task_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/task_service_pb2.py +0 -60
- flyte/_protos/workflow/task_service_pb2.pyi +0 -59
- flyte/_protos/workflow/task_service_pb2_grpc.py +0 -138
- flyte-2.0.0b13.dist-info/RECORD +0 -239
- /flyte/{_protos → _debug}/__init__.py +0 -0
- {flyte-2.0.0b13.dist-info → flyte-2.0.0b30.dist-info}/WHEEL +0 -0
- {flyte-2.0.0b13.dist-info → flyte-2.0.0b30.dist-info}/licenses/LICENSE +0 -0
- {flyte-2.0.0b13.dist-info → flyte-2.0.0b30.dist-info}/top_level.txt +0 -0
flyte/cli/_create.py
CHANGED
|
@@ -3,6 +3,7 @@ from typing import Any, Dict, get_args
|
|
|
3
3
|
|
|
4
4
|
import rich_click as click
|
|
5
5
|
|
|
6
|
+
import flyte
|
|
6
7
|
import flyte.cli._common as common
|
|
7
8
|
from flyte.cli._option import MutuallyExclusiveOption
|
|
8
9
|
from flyte.remote import SecretTypes
|
|
@@ -23,18 +24,49 @@ def create():
|
|
|
23
24
|
prompt="Enter secret value",
|
|
24
25
|
hide_input=True,
|
|
25
26
|
cls=MutuallyExclusiveOption,
|
|
26
|
-
mutually_exclusive=["from_file"],
|
|
27
|
+
mutually_exclusive=["from_file", "from_docker_config", "registry"],
|
|
27
28
|
)
|
|
28
29
|
@click.option(
|
|
29
30
|
"--from-file",
|
|
30
31
|
type=click.Path(exists=True),
|
|
31
32
|
help="Path to the file with the binary secret.",
|
|
32
33
|
cls=MutuallyExclusiveOption,
|
|
33
|
-
mutually_exclusive=["value"],
|
|
34
|
+
mutually_exclusive=["value", "from_docker_config", "registry"],
|
|
34
35
|
)
|
|
35
36
|
@click.option(
|
|
36
37
|
"--type", type=click.Choice(get_args(SecretTypes)), default="regular", help="Type of the secret.", show_default=True
|
|
37
38
|
)
|
|
39
|
+
@click.option(
|
|
40
|
+
"--from-docker-config",
|
|
41
|
+
is_flag=True,
|
|
42
|
+
help="Create image pull secret from Docker config file (only for --type image_pull).",
|
|
43
|
+
cls=MutuallyExclusiveOption,
|
|
44
|
+
mutually_exclusive=["value", "from_file", "registry", "username", "password"],
|
|
45
|
+
)
|
|
46
|
+
@click.option(
|
|
47
|
+
"--docker-config-path",
|
|
48
|
+
type=click.Path(exists=True),
|
|
49
|
+
help="Path to Docker config file (defaults to ~/.docker/config.json or $DOCKER_CONFIG).",
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--registries",
|
|
53
|
+
help="Comma-separated list of registries to include (only with --from-docker-config).",
|
|
54
|
+
)
|
|
55
|
+
@click.option(
|
|
56
|
+
"--registry",
|
|
57
|
+
help="Registry hostname (e.g., ghcr.io, docker.io) for explicit credentials (only for --type image_pull).",
|
|
58
|
+
cls=MutuallyExclusiveOption,
|
|
59
|
+
mutually_exclusive=["value", "from_file", "from_docker_config"],
|
|
60
|
+
)
|
|
61
|
+
@click.option(
|
|
62
|
+
"--username",
|
|
63
|
+
help="Username for the registry (only with --registry).",
|
|
64
|
+
)
|
|
65
|
+
@click.option(
|
|
66
|
+
"--password",
|
|
67
|
+
help="Password for the registry (only with --registry). If not provided, will prompt.",
|
|
68
|
+
hide_input=True,
|
|
69
|
+
)
|
|
38
70
|
@click.pass_obj
|
|
39
71
|
def secret(
|
|
40
72
|
cfg: common.CLIConfig,
|
|
@@ -42,6 +74,12 @@ def secret(
|
|
|
42
74
|
value: str | bytes | None = None,
|
|
43
75
|
from_file: str | None = None,
|
|
44
76
|
type: SecretTypes = "regular",
|
|
77
|
+
from_docker_config: bool = False,
|
|
78
|
+
docker_config_path: str | None = None,
|
|
79
|
+
registries: str | None = None,
|
|
80
|
+
registry: str | None = None,
|
|
81
|
+
username: str | None = None,
|
|
82
|
+
password: str | None = None,
|
|
45
83
|
project: str | None = None,
|
|
46
84
|
domain: str | None = None,
|
|
47
85
|
):
|
|
@@ -72,16 +110,80 @@ def secret(
|
|
|
72
110
|
Other secrets should be specified as `regular`.
|
|
73
111
|
If no type is specified, `regular` is assumed.
|
|
74
112
|
|
|
113
|
+
For image pull secrets, you have several options:
|
|
114
|
+
|
|
115
|
+
1. Interactive mode (prompts for registry, username, password):
|
|
75
116
|
```bash
|
|
76
117
|
$ flyte create secret my_secret --type image_pull
|
|
77
118
|
```
|
|
119
|
+
|
|
120
|
+
2. With explicit credentials:
|
|
121
|
+
```bash
|
|
122
|
+
$ flyte create secret my_secret --type image_pull --registry ghcr.io --username myuser
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
3. Lastly, you can create a secret from your existing Docker installation (i.e., you've run `docker login` in
|
|
126
|
+
the past) and you just want to pull from those credentials. Since you may have logged in to multiple registries,
|
|
127
|
+
you can specify which registries to include. If no registries are specified, all registries are added.
|
|
128
|
+
```bash
|
|
129
|
+
$ flyte create secret my_secret --type image_pull --from-docker-config --registries ghcr.io,docker.io
|
|
130
|
+
```
|
|
78
131
|
"""
|
|
79
132
|
from flyte.remote import Secret
|
|
80
133
|
|
|
134
|
+
# todo: remove this hack when secrets creation more easily distinguishes between org and project/domain level
|
|
135
|
+
# (and domain level) secrets
|
|
136
|
+
project = "" if project is None else project
|
|
137
|
+
domain = "" if domain is None else domain
|
|
81
138
|
cfg.init(project, domain)
|
|
82
|
-
|
|
139
|
+
|
|
140
|
+
# Handle image pull secret creation
|
|
141
|
+
if type == "image_pull":
|
|
142
|
+
if project != "" or domain != "":
|
|
143
|
+
raise click.ClickException("Project and domain must not be set when creating an image pull secret.")
|
|
144
|
+
|
|
145
|
+
if from_docker_config:
|
|
146
|
+
# Mode 3: From Docker config
|
|
147
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_config
|
|
148
|
+
|
|
149
|
+
registry_list = [r.strip() for r in registries.split(",")] if registries else None
|
|
150
|
+
try:
|
|
151
|
+
value = create_dockerconfigjson_from_config(
|
|
152
|
+
registries=registry_list,
|
|
153
|
+
docker_config_path=docker_config_path,
|
|
154
|
+
)
|
|
155
|
+
except Exception as e:
|
|
156
|
+
raise click.ClickException(f"Failed to create dockerconfigjson from Docker config: {e}") from e
|
|
157
|
+
|
|
158
|
+
elif registry:
|
|
159
|
+
# Mode 2: Explicit credentials
|
|
160
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_credentials
|
|
161
|
+
|
|
162
|
+
if not username:
|
|
163
|
+
username = click.prompt("Username")
|
|
164
|
+
if not password:
|
|
165
|
+
password = click.prompt("Password", hide_input=True)
|
|
166
|
+
|
|
167
|
+
value = create_dockerconfigjson_from_credentials(registry, username, password)
|
|
168
|
+
|
|
169
|
+
else:
|
|
170
|
+
# Mode 1: Interactive prompts
|
|
171
|
+
from flyte._utils.docker_credentials import create_dockerconfigjson_from_credentials
|
|
172
|
+
|
|
173
|
+
registry = click.prompt("Registry (e.g., ghcr.io, docker.io)")
|
|
174
|
+
username = click.prompt("Username")
|
|
175
|
+
password = click.prompt("Password", hide_input=True)
|
|
176
|
+
|
|
177
|
+
value = create_dockerconfigjson_from_credentials(registry, username, password)
|
|
178
|
+
|
|
179
|
+
elif from_file:
|
|
83
180
|
with open(from_file, "rb") as f:
|
|
84
181
|
value = f.read()
|
|
182
|
+
|
|
183
|
+
# Encode string values to bytes
|
|
184
|
+
if isinstance(value, str):
|
|
185
|
+
value = value.encode("utf-8")
|
|
186
|
+
|
|
85
187
|
Secret.create(name=name, value=value, type=type)
|
|
86
188
|
|
|
87
189
|
|
|
@@ -98,7 +200,7 @@ def secret(
|
|
|
98
200
|
"-o",
|
|
99
201
|
"--output",
|
|
100
202
|
type=click.Path(exists=False, writable=True),
|
|
101
|
-
default=Path.cwd() / "config.yaml",
|
|
203
|
+
default=Path.cwd() / ".flyte" / "config.yaml",
|
|
102
204
|
help="Path to the output directory where the configuration will be saved. Defaults to current directory.",
|
|
103
205
|
show_default=True,
|
|
104
206
|
)
|
|
@@ -147,6 +249,9 @@ def config(
|
|
|
147
249
|
|
|
148
250
|
output_path = Path(output)
|
|
149
251
|
|
|
252
|
+
if not output_path.parent.exists():
|
|
253
|
+
output_path.parent.mkdir(parents=True)
|
|
254
|
+
|
|
150
255
|
if output_path.exists() and not force:
|
|
151
256
|
force = click.confirm(f"Overwrite [{output_path}]?", default=False)
|
|
152
257
|
if not force:
|
|
@@ -191,3 +296,76 @@ def config(
|
|
|
191
296
|
yaml.dump(d, f)
|
|
192
297
|
|
|
193
298
|
click.echo(f"Config file written to {output_path}")
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
@create.command(cls=common.CommandBase)
|
|
302
|
+
@click.argument("task_name", type=str, required=True)
|
|
303
|
+
@click.argument("name", type=str, required=True)
|
|
304
|
+
@click.option(
|
|
305
|
+
"--schedule",
|
|
306
|
+
type=str,
|
|
307
|
+
required=True,
|
|
308
|
+
help="Cron schedule for the trigger. Defaults to every minute.",
|
|
309
|
+
show_default=True,
|
|
310
|
+
)
|
|
311
|
+
@click.option(
|
|
312
|
+
"--description",
|
|
313
|
+
type=str,
|
|
314
|
+
default="",
|
|
315
|
+
help="Description of the trigger.",
|
|
316
|
+
show_default=True,
|
|
317
|
+
)
|
|
318
|
+
@click.option(
|
|
319
|
+
"--auto-activate",
|
|
320
|
+
is_flag=True,
|
|
321
|
+
default=True,
|
|
322
|
+
help="Whether the trigger should not be automatically activated. Defaults to True.",
|
|
323
|
+
show_default=True,
|
|
324
|
+
)
|
|
325
|
+
@click.option(
|
|
326
|
+
"--trigger-time-var",
|
|
327
|
+
type=str,
|
|
328
|
+
default="trigger_time",
|
|
329
|
+
help="Variable name for the trigger time in the task inputs. Defaults to 'trigger_time'.",
|
|
330
|
+
show_default=True,
|
|
331
|
+
)
|
|
332
|
+
@click.pass_obj
|
|
333
|
+
def trigger(
|
|
334
|
+
cfg: common.CLIConfig,
|
|
335
|
+
task_name: str,
|
|
336
|
+
name: str,
|
|
337
|
+
schedule: str,
|
|
338
|
+
trigger_time_var: str = "trigger_time",
|
|
339
|
+
auto_activate: bool = True,
|
|
340
|
+
description: str = "",
|
|
341
|
+
project: str | None = None,
|
|
342
|
+
domain: str | None = None,
|
|
343
|
+
):
|
|
344
|
+
"""
|
|
345
|
+
Create a new trigger for a task. The task name and trigger name are required.
|
|
346
|
+
|
|
347
|
+
Example:
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
$ flyte create trigger my_task my_trigger --schedule "0 0 * * *"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
This will create a trigger that runs every day at midnight.
|
|
354
|
+
"""
|
|
355
|
+
from flyte.remote import Trigger
|
|
356
|
+
|
|
357
|
+
cfg.init(project, domain)
|
|
358
|
+
console = common.get_console()
|
|
359
|
+
|
|
360
|
+
trigger = flyte.Trigger(
|
|
361
|
+
name=name,
|
|
362
|
+
automation=flyte.Cron(schedule),
|
|
363
|
+
description=description,
|
|
364
|
+
auto_activate=auto_activate,
|
|
365
|
+
inputs={trigger_time_var: flyte.TriggerTime}, # Use the trigger time variable in inputs
|
|
366
|
+
env_vars=None,
|
|
367
|
+
interruptible=None,
|
|
368
|
+
)
|
|
369
|
+
with console.status("Creating trigger..."):
|
|
370
|
+
v = Trigger.create(trigger, task_name=task_name)
|
|
371
|
+
console.print(f"[bold green]Trigger {v.name} created successfully![/bold green]")
|
flyte/cli/_delete.py
CHANGED
|
@@ -20,4 +20,26 @@ def secret(cfg: common.CLIConfig, name: str, project: str | None = None, domain:
|
|
|
20
20
|
from flyte.remote import Secret
|
|
21
21
|
|
|
22
22
|
cfg.init(project, domain)
|
|
23
|
-
|
|
23
|
+
console = common.get_console()
|
|
24
|
+
with console.status(f"Deleting secret {name}..."):
|
|
25
|
+
Secret.delete(name=name)
|
|
26
|
+
console.print(f"Successfully deleted secret {name}.")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@delete.command(cls=common.CommandBase)
|
|
30
|
+
@click.argument("name", type=str, required=True)
|
|
31
|
+
@click.argument("task-name", type=str, required=True)
|
|
32
|
+
@click.pass_obj
|
|
33
|
+
def trigger(cfg: common.CLIConfig, name: str, task_name: str, project: str | None = None, domain: str | None = None):
|
|
34
|
+
"""
|
|
35
|
+
Delete a trigger. The name of the trigger is required.
|
|
36
|
+
"""
|
|
37
|
+
from flyte.remote import Trigger
|
|
38
|
+
|
|
39
|
+
cfg.init(project, domain)
|
|
40
|
+
console = common.get_console()
|
|
41
|
+
|
|
42
|
+
with console.status(f"Deleting trigger {name}..."):
|
|
43
|
+
Trigger.delete(name=name, task_name=task_name)
|
|
44
|
+
|
|
45
|
+
console.log(f"[green]Successfully deleted trigger {name}[/green]")
|
flyte/cli/_deploy.py
CHANGED
|
@@ -4,12 +4,11 @@ from pathlib import Path
|
|
|
4
4
|
from types import ModuleType
|
|
5
5
|
from typing import Any, Dict, List, cast, get_args
|
|
6
6
|
|
|
7
|
-
import click
|
|
8
|
-
from click import Context
|
|
7
|
+
import rich_click as click
|
|
9
8
|
|
|
10
9
|
import flyte
|
|
10
|
+
from flyte._code_bundle._utils import CopyFiles
|
|
11
11
|
|
|
12
|
-
from .._code_bundle._utils import CopyFiles
|
|
13
12
|
from . import _common as common
|
|
14
13
|
from ._common import CLIConfig
|
|
15
14
|
|
|
@@ -44,6 +43,16 @@ class DeployArguments:
|
|
|
44
43
|
)
|
|
45
44
|
},
|
|
46
45
|
)
|
|
46
|
+
root_dir: str | None = field(
|
|
47
|
+
default=None,
|
|
48
|
+
metadata={
|
|
49
|
+
"click.option": click.Option(
|
|
50
|
+
["--root-dir"],
|
|
51
|
+
type=str,
|
|
52
|
+
help="Override the root source directory, helpful when working with monorepos.",
|
|
53
|
+
)
|
|
54
|
+
},
|
|
55
|
+
)
|
|
47
56
|
recursive: bool = field(
|
|
48
57
|
default=False,
|
|
49
58
|
metadata={
|
|
@@ -74,6 +83,19 @@ class DeployArguments:
|
|
|
74
83
|
)
|
|
75
84
|
},
|
|
76
85
|
)
|
|
86
|
+
no_sync_local_sys_paths: bool = field(
|
|
87
|
+
default=True,
|
|
88
|
+
metadata={
|
|
89
|
+
"click.option": click.Option(
|
|
90
|
+
["--no-sync-local-sys-paths"],
|
|
91
|
+
is_flag=True,
|
|
92
|
+
flag_value=True,
|
|
93
|
+
default=False,
|
|
94
|
+
help="Disable synchronization of local sys.path entries under the root directory "
|
|
95
|
+
"to the remote container.",
|
|
96
|
+
)
|
|
97
|
+
},
|
|
98
|
+
)
|
|
77
99
|
|
|
78
100
|
@classmethod
|
|
79
101
|
def from_dict(cls, d: Dict[str, Any]) -> "DeployArguments":
|
|
@@ -87,20 +109,23 @@ class DeployArguments:
|
|
|
87
109
|
return [common.get_option_from_metadata(f.metadata) for f in fields(cls) if f.metadata]
|
|
88
110
|
|
|
89
111
|
|
|
90
|
-
class DeployEnvCommand(click.
|
|
112
|
+
class DeployEnvCommand(click.RichCommand):
|
|
91
113
|
def __init__(self, env_name: str, env: Any, deploy_args: DeployArguments, *args, **kwargs):
|
|
92
114
|
self.env_name = env_name
|
|
93
115
|
self.env = env
|
|
94
116
|
self.deploy_args = deploy_args
|
|
95
117
|
super().__init__(*args, **kwargs)
|
|
96
118
|
|
|
97
|
-
def invoke(self, ctx: Context):
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console = Console()
|
|
119
|
+
def invoke(self, ctx: click.Context):
|
|
120
|
+
console = common.get_console()
|
|
101
121
|
console.print(f"Deploying root - environment: {self.env_name}")
|
|
102
122
|
obj: CLIConfig = ctx.obj
|
|
103
|
-
obj.init(
|
|
123
|
+
obj.init(
|
|
124
|
+
self.deploy_args.project,
|
|
125
|
+
self.deploy_args.domain,
|
|
126
|
+
root_dir=self.deploy_args.root_dir,
|
|
127
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
128
|
+
)
|
|
104
129
|
with console.status("Deploying...", spinner="dots"):
|
|
105
130
|
deployment = flyte.deploy(
|
|
106
131
|
self.env,
|
|
@@ -110,7 +135,7 @@ class DeployEnvCommand(click.Command):
|
|
|
110
135
|
)
|
|
111
136
|
|
|
112
137
|
console.print(common.format("Environments", deployment[0].env_repr(), obj.output_format))
|
|
113
|
-
console.print(common.format("Tasks", deployment[0].
|
|
138
|
+
console.print(common.format("Tasks", deployment[0].table_repr(), obj.output_format))
|
|
114
139
|
|
|
115
140
|
|
|
116
141
|
class DeployEnvRecursiveCommand(click.Command):
|
|
@@ -125,14 +150,12 @@ class DeployEnvRecursiveCommand(click.Command):
|
|
|
125
150
|
self.deploy_args = deploy_args
|
|
126
151
|
super().__init__(*args, **kwargs)
|
|
127
152
|
|
|
128
|
-
def invoke(self, ctx: Context):
|
|
129
|
-
from rich.console import Console
|
|
130
|
-
|
|
153
|
+
def invoke(self, ctx: click.Context):
|
|
131
154
|
from flyte._environment import list_loaded_environments
|
|
132
155
|
from flyte._utils import load_python_modules
|
|
133
156
|
|
|
134
|
-
console = Console()
|
|
135
157
|
obj: CLIConfig = ctx.obj
|
|
158
|
+
console = common.get_console()
|
|
136
159
|
|
|
137
160
|
# Load all python modules
|
|
138
161
|
loaded_modules, failed_paths = load_python_modules(self.path, self.deploy_args.recursive)
|
|
@@ -156,7 +179,11 @@ class DeployEnvRecursiveCommand(click.Command):
|
|
|
156
179
|
f"Failed to load {len(failed_paths)} files. Use --ignore-load-errors to ignore these errors."
|
|
157
180
|
)
|
|
158
181
|
# Now start connection and deploy all environments
|
|
159
|
-
obj.init(
|
|
182
|
+
obj.init(
|
|
183
|
+
self.deploy_args.project,
|
|
184
|
+
self.deploy_args.domain,
|
|
185
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
186
|
+
)
|
|
160
187
|
with console.status("Deploying...", spinner="dots"):
|
|
161
188
|
deployments = flyte.deploy(
|
|
162
189
|
*all_envs,
|
|
@@ -168,7 +195,7 @@ class DeployEnvRecursiveCommand(click.Command):
|
|
|
168
195
|
console.print(
|
|
169
196
|
common.format("Environments", [env for d in deployments for env in d.env_repr()], obj.output_format)
|
|
170
197
|
)
|
|
171
|
-
console.print(common.format("Tasks", [task for d in deployments for task in d.
|
|
198
|
+
console.print(common.format("Tasks", [task for d in deployments for task in d.table_repr()], obj.output_format))
|
|
172
199
|
|
|
173
200
|
|
|
174
201
|
class EnvPerFileGroup(common.ObjectsPerFileGroup):
|
|
@@ -184,6 +211,26 @@ class EnvPerFileGroup(common.ObjectsPerFileGroup):
|
|
|
184
211
|
def _filter_objects(self, module: ModuleType) -> Dict[str, Any]:
|
|
185
212
|
return {k: v for k, v in module.__dict__.items() if isinstance(v, flyte.Environment)}
|
|
186
213
|
|
|
214
|
+
def list_commands(self, ctx):
|
|
215
|
+
common.initialize_config(
|
|
216
|
+
ctx,
|
|
217
|
+
self.deploy_args.project,
|
|
218
|
+
self.deploy_args.domain,
|
|
219
|
+
self.deploy_args.root_dir,
|
|
220
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
221
|
+
)
|
|
222
|
+
return super().list_commands(ctx)
|
|
223
|
+
|
|
224
|
+
def get_command(self, ctx, obj_name):
|
|
225
|
+
common.initialize_config(
|
|
226
|
+
ctx,
|
|
227
|
+
self.deploy_args.project,
|
|
228
|
+
self.deploy_args.domain,
|
|
229
|
+
self.deploy_args.root_dir,
|
|
230
|
+
sync_local_sys_paths=not self.deploy_args.no_sync_local_sys_paths,
|
|
231
|
+
)
|
|
232
|
+
return super().get_command(ctx, obj_name)
|
|
233
|
+
|
|
187
234
|
def _get_command_for_obj(self, ctx: click.Context, obj_name: str, obj: Any) -> click.Command:
|
|
188
235
|
obj = cast(flyte.Environment, obj)
|
|
189
236
|
return DeployEnvCommand(
|
flyte/cli/_get.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
from typing import Tuple, Union
|
|
2
|
+
from typing import Tuple, Union, get_args
|
|
3
3
|
|
|
4
4
|
import rich_click as click
|
|
5
|
-
from rich.console import Console
|
|
6
5
|
from rich.pretty import pretty_repr
|
|
7
6
|
|
|
7
|
+
import flyte.remote as remote
|
|
8
|
+
|
|
8
9
|
from . import _common as common
|
|
9
10
|
|
|
10
11
|
|
|
@@ -38,20 +39,24 @@ def project(cfg: common.CLIConfig, name: str | None = None):
|
|
|
38
39
|
"""
|
|
39
40
|
Get a list of all projects, or details of a specific project by name.
|
|
40
41
|
"""
|
|
41
|
-
from flyte.remote import Project
|
|
42
|
-
|
|
43
42
|
cfg.init()
|
|
44
43
|
|
|
45
|
-
console =
|
|
44
|
+
console = common.get_console()
|
|
46
45
|
if name:
|
|
47
|
-
console.print(pretty_repr(Project.get(name)))
|
|
46
|
+
console.print(pretty_repr(remote.Project.get(name)))
|
|
48
47
|
else:
|
|
49
|
-
console.print(common.format("Projects", Project.listall(), cfg.output_format))
|
|
48
|
+
console.print(common.format("Projects", remote.Project.listall(), cfg.output_format))
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
@get.command(cls=common.CommandBase)
|
|
53
52
|
@click.argument("name", type=str, required=False)
|
|
54
53
|
@click.option("--limit", type=int, default=100, help="Limit the number of runs to fetch when listing.")
|
|
54
|
+
@click.option(
|
|
55
|
+
"--in-phase", # multiple=True, TODO support multiple phases once values in works
|
|
56
|
+
type=click.Choice(get_args(remote.Phase), case_sensitive=False),
|
|
57
|
+
help="Filter runs by their status.",
|
|
58
|
+
)
|
|
59
|
+
@click.option("--only-mine", is_flag=True, default=False, help="Show only runs created by the current user (you).")
|
|
55
60
|
@click.pass_obj
|
|
56
61
|
def run(
|
|
57
62
|
cfg: common.CLIConfig,
|
|
@@ -59,6 +64,8 @@ def run(
|
|
|
59
64
|
project: str | None = None,
|
|
60
65
|
domain: str | None = None,
|
|
61
66
|
limit: int = 100,
|
|
67
|
+
in_phase: str | Tuple[str, ...] | None = None,
|
|
68
|
+
only_mine: bool = False,
|
|
62
69
|
):
|
|
63
70
|
"""
|
|
64
71
|
Get a list of all runs, or details of a specific run by name.
|
|
@@ -67,16 +74,29 @@ def run(
|
|
|
67
74
|
|
|
68
75
|
If you want to see the actions for a run, use `get action <run_name>`.
|
|
69
76
|
"""
|
|
70
|
-
from flyte.remote import Run, RunDetails
|
|
71
77
|
|
|
72
78
|
cfg.init(project=project, domain=domain)
|
|
73
79
|
|
|
74
|
-
console =
|
|
80
|
+
console = common.get_console()
|
|
75
81
|
if name:
|
|
76
|
-
details = RunDetails.get(name=name)
|
|
82
|
+
details = remote.RunDetails.get(name=name)
|
|
77
83
|
console.print(common.format(f"Run {name}", [details], "json"))
|
|
78
84
|
else:
|
|
79
|
-
|
|
85
|
+
if in_phase and isinstance(in_phase, str):
|
|
86
|
+
in_phase = (in_phase,)
|
|
87
|
+
|
|
88
|
+
subject = None
|
|
89
|
+
if only_mine:
|
|
90
|
+
usr = remote.User.get()
|
|
91
|
+
subject = usr.subject()
|
|
92
|
+
|
|
93
|
+
console.print(
|
|
94
|
+
common.format(
|
|
95
|
+
"Runs",
|
|
96
|
+
remote.Run.listall(limit=limit, in_phase=in_phase, created_by_subject=subject),
|
|
97
|
+
cfg.output_format,
|
|
98
|
+
)
|
|
99
|
+
)
|
|
80
100
|
|
|
81
101
|
|
|
82
102
|
@get.command(cls=common.CommandBase)
|
|
@@ -97,22 +117,22 @@ def task(
|
|
|
97
117
|
|
|
98
118
|
Currently, both `name` and `version` are required to get a specific task.
|
|
99
119
|
"""
|
|
100
|
-
from flyte.remote import Task
|
|
101
|
-
|
|
102
120
|
cfg.init(project=project, domain=domain)
|
|
103
121
|
|
|
104
|
-
console =
|
|
122
|
+
console = common.get_console()
|
|
105
123
|
if name:
|
|
106
124
|
if version:
|
|
107
|
-
v = Task.get(name=name, version=version)
|
|
125
|
+
v = remote.Task.get(name=name, version=version)
|
|
108
126
|
if v is None:
|
|
109
127
|
raise click.BadParameter(f"Task {name} not found.")
|
|
110
128
|
t = v.fetch()
|
|
111
129
|
console.print(common.format(f"Task {name}", [t], "json"))
|
|
112
130
|
else:
|
|
113
|
-
console.print(
|
|
131
|
+
console.print(
|
|
132
|
+
common.format("Tasks", remote.Task.listall(by_task_name=name, limit=limit), cfg.output_format)
|
|
133
|
+
)
|
|
114
134
|
else:
|
|
115
|
-
console.print(common.format("Tasks", Task.listall(limit=limit), cfg.output_format))
|
|
135
|
+
console.print(common.format("Tasks", remote.Task.listall(limit=limit), cfg.output_format))
|
|
116
136
|
|
|
117
137
|
|
|
118
138
|
@get.command(cls=common.CommandBase)
|
|
@@ -129,11 +149,9 @@ def action(
|
|
|
129
149
|
"""
|
|
130
150
|
Get all actions for a run or details for a specific action.
|
|
131
151
|
"""
|
|
132
|
-
import flyte.remote as remote
|
|
133
|
-
|
|
134
152
|
cfg.init(project=project, domain=domain)
|
|
135
153
|
|
|
136
|
-
console =
|
|
154
|
+
console = common.get_console()
|
|
137
155
|
if action_name:
|
|
138
156
|
console.print(
|
|
139
157
|
common.format(
|
|
@@ -196,8 +214,6 @@ def logs(
|
|
|
196
214
|
$ flyte get logs my_run my_action --pretty --lines 50
|
|
197
215
|
```
|
|
198
216
|
"""
|
|
199
|
-
import flyte.remote as remote
|
|
200
|
-
|
|
201
217
|
cfg.init(project=project, domain=domain)
|
|
202
218
|
|
|
203
219
|
async def _run_log_view(_obj):
|
|
@@ -230,11 +246,13 @@ def secret(
|
|
|
230
246
|
"""
|
|
231
247
|
Get a list of all secrets, or details of a specific secret by name.
|
|
232
248
|
"""
|
|
233
|
-
|
|
234
|
-
|
|
249
|
+
if project is None:
|
|
250
|
+
project = ""
|
|
251
|
+
if domain is None:
|
|
252
|
+
domain = ""
|
|
235
253
|
cfg.init(project=project, domain=domain)
|
|
236
254
|
|
|
237
|
-
console =
|
|
255
|
+
console = common.get_console()
|
|
238
256
|
if name:
|
|
239
257
|
console.print(common.format("Secret", [remote.Secret.get(name)], "json"))
|
|
240
258
|
else:
|
|
@@ -275,26 +293,23 @@ def io(
|
|
|
275
293
|
if inputs_only and outputs_only:
|
|
276
294
|
raise click.BadParameter("Cannot use both --inputs-only and --outputs-only")
|
|
277
295
|
|
|
278
|
-
import flyte.remote as remote
|
|
279
|
-
from flyte.remote import ActionDetails, ActionInputs, ActionOutputs
|
|
280
|
-
|
|
281
296
|
cfg.init(project=project, domain=domain)
|
|
282
|
-
console =
|
|
297
|
+
console = common.get_console()
|
|
283
298
|
if action_name:
|
|
284
|
-
obj = ActionDetails.get(run_name=run_name, name=action_name)
|
|
299
|
+
obj = remote.ActionDetails.get(run_name=run_name, name=action_name)
|
|
285
300
|
else:
|
|
286
301
|
obj = remote.RunDetails.get(run_name)
|
|
287
302
|
|
|
288
303
|
async def _get_io(
|
|
289
|
-
details: Union[remote.RunDetails, ActionDetails],
|
|
290
|
-
) -> Tuple[ActionInputs | None, ActionOutputs | None | str]:
|
|
304
|
+
details: Union[remote.RunDetails, remote.ActionDetails],
|
|
305
|
+
) -> Tuple[remote.ActionInputs | None, remote.ActionOutputs | None | str]:
|
|
291
306
|
if inputs_only or outputs_only:
|
|
292
307
|
if inputs_only:
|
|
293
308
|
return await details.inputs(), None
|
|
294
309
|
elif outputs_only:
|
|
295
310
|
return None, await details.outputs()
|
|
296
311
|
inputs = await details.inputs()
|
|
297
|
-
outputs: ActionOutputs | None | str = None
|
|
312
|
+
outputs: remote.ActionOutputs | None | str = None
|
|
298
313
|
try:
|
|
299
314
|
outputs = await details.outputs()
|
|
300
315
|
except Exception:
|
|
@@ -321,5 +336,35 @@ def config(cfg: common.CLIConfig):
|
|
|
321
336
|
|
|
322
337
|
The configuration will include the endpoint, organization, and other settings that are used by the CLI.
|
|
323
338
|
"""
|
|
324
|
-
console =
|
|
339
|
+
console = common.get_console()
|
|
325
340
|
console.print(cfg)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
@get.command(cls=common.CommandBase)
|
|
344
|
+
@click.argument("task_name", type=str, required=False)
|
|
345
|
+
@click.argument("name", type=str, required=False)
|
|
346
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of triggers to fetch.")
|
|
347
|
+
@click.pass_obj
|
|
348
|
+
def trigger(
|
|
349
|
+
cfg: common.CLIConfig,
|
|
350
|
+
task_name: str | None = None,
|
|
351
|
+
name: str | None = None,
|
|
352
|
+
limit: int = 100,
|
|
353
|
+
project: str | None = None,
|
|
354
|
+
domain: str | None = None,
|
|
355
|
+
):
|
|
356
|
+
"""
|
|
357
|
+
Get a list of all triggers, or details of a specific trigger by name.
|
|
358
|
+
"""
|
|
359
|
+
if name and not task_name:
|
|
360
|
+
raise click.BadParameter("If you provide a trigger name, you must also provide the task name.")
|
|
361
|
+
|
|
362
|
+
from flyte.remote import Trigger
|
|
363
|
+
|
|
364
|
+
cfg.init(project=project, domain=domain)
|
|
365
|
+
|
|
366
|
+
console = common.get_console()
|
|
367
|
+
if name:
|
|
368
|
+
console.print(pretty_repr(Trigger.get(name=name, task_name=task_name)))
|
|
369
|
+
else:
|
|
370
|
+
console.print(common.format("Triggers", Trigger.listall(task_name=task_name, limit=limit), cfg.output_format))
|