flyte 0.2.0b7__py3-none-any.whl → 0.2.0b9__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 +2 -0
- flyte/_context.py +7 -1
- flyte/_environment.py +42 -1
- flyte/_group.py +1 -0
- flyte/_image.py +1 -2
- flyte/_internal/controllers/__init__.py +14 -1
- flyte/_internal/controllers/_local_controller.py +66 -1
- flyte/_internal/controllers/remote/_controller.py +48 -0
- flyte/_internal/controllers/remote/_informer.py +3 -3
- flyte/_internal/runtime/taskrunner.py +2 -1
- flyte/_map.py +215 -0
- flyte/_run.py +26 -26
- flyte/_task.py +101 -13
- flyte/_task_environment.py +48 -66
- flyte/_utils/coro_management.py +0 -2
- flyte/_utils/helpers.py +15 -0
- flyte/_version.py +2 -2
- flyte/cli/__init__.py +0 -7
- flyte/cli/_abort.py +1 -1
- flyte/cli/_common.py +4 -3
- flyte/cli/_create.py +69 -23
- flyte/cli/_delete.py +2 -2
- flyte/cli/_deploy.py +7 -4
- flyte/cli/_gen.py +163 -0
- flyte/cli/_get.py +62 -8
- flyte/cli/_run.py +22 -2
- flyte/cli/main.py +63 -13
- flyte/extras/_container.py +1 -1
- flyte/models.py +10 -1
- flyte/remote/_run.py +1 -0
- flyte/syncify/__init__.py +51 -0
- flyte/syncify/_api.py +48 -21
- {flyte-0.2.0b7.dist-info → flyte-0.2.0b9.dist-info}/METADATA +30 -4
- {flyte-0.2.0b7.dist-info → flyte-0.2.0b9.dist-info}/RECORD +37 -35
- {flyte-0.2.0b7.dist-info → flyte-0.2.0b9.dist-info}/WHEEL +0 -0
- {flyte-0.2.0b7.dist-info → flyte-0.2.0b9.dist-info}/entry_points.txt +0 -0
- {flyte-0.2.0b7.dist-info → flyte-0.2.0b9.dist-info}/top_level.txt +0 -0
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
CHANGED
|
@@ -11,7 +11,23 @@ from . import _common as common
|
|
|
11
11
|
@click.group(name="get")
|
|
12
12
|
def get():
|
|
13
13
|
"""
|
|
14
|
-
|
|
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 specifiying aproject), 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`.
|
|
15
31
|
"""
|
|
16
32
|
|
|
17
33
|
|
|
@@ -20,7 +36,7 @@ def get():
|
|
|
20
36
|
@click.pass_obj
|
|
21
37
|
def project(cfg: common.CLIConfig, name: str | None = None):
|
|
22
38
|
"""
|
|
23
|
-
Get
|
|
39
|
+
Get a list of all projects, or details of a specific project by name.
|
|
24
40
|
"""
|
|
25
41
|
from flyte.remote import Project
|
|
26
42
|
|
|
@@ -39,7 +55,11 @@ def project(cfg: common.CLIConfig, name: str | None = None):
|
|
|
39
55
|
@click.pass_obj
|
|
40
56
|
def run(cfg: common.CLIConfig, name: str | None = None, project: str | None = None, domain: str | None = None):
|
|
41
57
|
"""
|
|
42
|
-
Get
|
|
58
|
+
Get a list of all runs, or details of a specific run by name.
|
|
59
|
+
|
|
60
|
+
The run details will include information about the run, its status, but only the root action will be shown.
|
|
61
|
+
|
|
62
|
+
If you want to see the actions for a run, use `get action <run_name>`.
|
|
43
63
|
"""
|
|
44
64
|
from flyte.remote import Run, RunDetails
|
|
45
65
|
|
|
@@ -65,7 +85,9 @@ def task(
|
|
|
65
85
|
domain: str | None = None,
|
|
66
86
|
):
|
|
67
87
|
"""
|
|
68
|
-
|
|
88
|
+
Retrieve a list of all tasks, or details of a specific task by name and version.
|
|
89
|
+
|
|
90
|
+
Currently, both `name` and `version` are required to get a specific task.
|
|
69
91
|
"""
|
|
70
92
|
from flyte.remote import Task
|
|
71
93
|
|
|
@@ -140,8 +162,25 @@ def logs(
|
|
|
140
162
|
filter_system: bool = False,
|
|
141
163
|
):
|
|
142
164
|
"""
|
|
143
|
-
Stream logs for the provided run or action.
|
|
144
|
-
streamed
|
|
165
|
+
Stream logs for the provided run or action.
|
|
166
|
+
If only the run is provided, only the logs for the parent action will be streamed:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
$ flyte get logs my_run
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
If you want to see the logs for a specific action, you can provide the action name as well:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
$ flyte get logs my_run my_action
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
By default, logs will be shown in the raw format and will scroll the terminal.
|
|
179
|
+
If automatic scrolling and only tailing `--lines` number of lines is desired, use the `--pretty` flag:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
$ flyte get logs my_run my_action --pretty --lines 50
|
|
183
|
+
```
|
|
145
184
|
"""
|
|
146
185
|
import flyte.remote as remote
|
|
147
186
|
|
|
@@ -175,7 +214,7 @@ def secret(
|
|
|
175
214
|
domain: str | None = None,
|
|
176
215
|
):
|
|
177
216
|
"""
|
|
178
|
-
Get
|
|
217
|
+
Get a list of all secrets, or details of a specific secret by name.
|
|
179
218
|
"""
|
|
180
219
|
import flyte.remote as remote
|
|
181
220
|
|
|
@@ -205,6 +244,19 @@ def io(
|
|
|
205
244
|
):
|
|
206
245
|
"""
|
|
207
246
|
Get the inputs and outputs of a run or action.
|
|
247
|
+
If only the run name is provided, it will show the inputs and outputs of the root action of that run.
|
|
248
|
+
If an action name is provided, it will show the inputs and outputs for that action.
|
|
249
|
+
If `--inputs-only` or `--outputs-only` is specified, it will only show the inputs or outputs respectively.
|
|
250
|
+
|
|
251
|
+
Examples:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
$ flyte get io my_run
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
$ flyte get io my_run my_action
|
|
259
|
+
```
|
|
208
260
|
"""
|
|
209
261
|
if inputs_only and outputs_only:
|
|
210
262
|
raise click.BadParameter("Cannot use both --inputs-only and --outputs-only")
|
|
@@ -249,7 +301,9 @@ def io(
|
|
|
249
301
|
@click.pass_obj
|
|
250
302
|
def config(cfg: common.CLIConfig):
|
|
251
303
|
"""
|
|
252
|
-
Shows the automatically detected configuration to connect with remote
|
|
304
|
+
Shows the automatically detected configuration to connect with the remote backend.
|
|
305
|
+
|
|
306
|
+
The configuration will include the endpoint, organization, and other settings that are used by the CLI.
|
|
253
307
|
"""
|
|
254
308
|
console = Console()
|
|
255
309
|
console.print(cfg)
|
flyte/cli/_run.py
CHANGED
|
@@ -204,11 +204,31 @@ class TaskFiles(common.FileGroup):
|
|
|
204
204
|
filename=Path(filename),
|
|
205
205
|
run_args=run_args,
|
|
206
206
|
name=filename,
|
|
207
|
-
help=f"Run, functions decorated `env.task` {filename}",
|
|
207
|
+
help=f"Run, functions decorated with `env.task` in {filename}",
|
|
208
208
|
)
|
|
209
209
|
|
|
210
210
|
|
|
211
211
|
run = TaskFiles(
|
|
212
212
|
name="run",
|
|
213
|
-
help="
|
|
213
|
+
help="""
|
|
214
|
+
Run a task from a python file.
|
|
215
|
+
|
|
216
|
+
Example usage:
|
|
217
|
+
```bash
|
|
218
|
+
flyte run --name examples/basics/hello.py my_task --arg1 value1 --arg2 value2
|
|
219
|
+
```
|
|
220
|
+
Note: all arguments for the run command are provided right after the `run` command and before the file name.
|
|
221
|
+
|
|
222
|
+
You can also specify the project and domain using the `--project` and `--domain` options, respectively. These
|
|
223
|
+
options can be set in the config file or passed as command line arguments.
|
|
224
|
+
|
|
225
|
+
Note: The arguments for the task are provided after the task name and can be retrieved using `--help`
|
|
226
|
+
Example:
|
|
227
|
+
```bash
|
|
228
|
+
flyte run --name examples/basics/hello.py my_task --help
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
To run a task locally, use the `--local` flag. This will run the task in the local environment instead of the remote
|
|
232
|
+
Flyte environment.
|
|
233
|
+
""",
|
|
214
234
|
)
|
flyte/cli/main.py
CHANGED
|
@@ -6,9 +6,32 @@ from ._abort import abort
|
|
|
6
6
|
from ._common import CLIConfig
|
|
7
7
|
from ._create import create
|
|
8
8
|
from ._deploy import deploy
|
|
9
|
+
from ._gen import gen
|
|
9
10
|
from ._get import get
|
|
10
11
|
from ._run import run
|
|
11
12
|
|
|
13
|
+
click.rich_click.COMMAND_GROUPS = {
|
|
14
|
+
"flyte": [
|
|
15
|
+
{
|
|
16
|
+
"name": "Running workflows",
|
|
17
|
+
"commands": ["run", "abort"],
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Management",
|
|
21
|
+
"commands": ["create", "deploy", "get"],
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "Documentation generation",
|
|
25
|
+
"commands": ["gen"],
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
help_config = click.RichHelpConfiguration(
|
|
31
|
+
use_markdown=True,
|
|
32
|
+
use_markdown_emoji=True,
|
|
33
|
+
)
|
|
34
|
+
|
|
12
35
|
|
|
13
36
|
def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
14
37
|
"""
|
|
@@ -35,13 +58,13 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
35
58
|
"--endpoint",
|
|
36
59
|
type=str,
|
|
37
60
|
required=False,
|
|
38
|
-
help="The endpoint to connect to
|
|
61
|
+
help="The endpoint to connect to. This will override any configuration file and simply use `pkce` to connect.",
|
|
39
62
|
)
|
|
40
63
|
@click.option(
|
|
41
|
-
"--insecure
|
|
64
|
+
"--insecure",
|
|
42
65
|
is_flag=True,
|
|
43
66
|
required=False,
|
|
44
|
-
help="Use insecure connection to the endpoint. If
|
|
67
|
+
help="Use an insecure connection to the endpoint. If not specified, the CLI will use TLS.",
|
|
45
68
|
type=bool,
|
|
46
69
|
default=None,
|
|
47
70
|
show_default=True,
|
|
@@ -50,7 +73,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
50
73
|
"-v",
|
|
51
74
|
"--verbose",
|
|
52
75
|
required=False,
|
|
53
|
-
help="Show verbose messages and exception traces",
|
|
76
|
+
help="Show verbose messages and exception traces. Repeating multiple times increases the verbosity (e.g., -vvv).",
|
|
54
77
|
count=True,
|
|
55
78
|
default=0,
|
|
56
79
|
type=int,
|
|
@@ -59,7 +82,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
59
82
|
"--org",
|
|
60
83
|
type=str,
|
|
61
84
|
required=False,
|
|
62
|
-
help="
|
|
85
|
+
help="The organization to which the command applies.",
|
|
63
86
|
)
|
|
64
87
|
@click.option(
|
|
65
88
|
"-c",
|
|
@@ -67,9 +90,9 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
67
90
|
"config_file",
|
|
68
91
|
required=False,
|
|
69
92
|
type=click.Path(exists=True),
|
|
70
|
-
help="Path to
|
|
71
|
-
" the default config file will be used.",
|
|
93
|
+
help="Path to the configuration file to use. If not specified, the default configuration file is used."
|
|
72
94
|
)
|
|
95
|
+
@click.rich_config(help_config=help_config)
|
|
73
96
|
@click.pass_context
|
|
74
97
|
def main(
|
|
75
98
|
ctx: click.Context,
|
|
@@ -80,14 +103,39 @@ def main(
|
|
|
80
103
|
config_file: str | None,
|
|
81
104
|
):
|
|
82
105
|
"""
|
|
106
|
+
The Flyte CLI is the the command line interface for working with the Flyte SDK and backend.
|
|
107
|
+
|
|
108
|
+
It follows a simple verb/noun structure,
|
|
109
|
+
where the top-level commands are verbs that describe the action to be taken,
|
|
110
|
+
and the subcommands are nouns that describe the object of the action.
|
|
111
|
+
|
|
112
|
+
The root command can be used to configure the CLI for persistent settings,
|
|
113
|
+
such as the endpoint, organization, and verbosity level.
|
|
114
|
+
|
|
115
|
+
Set endpoint and organization:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
$ flyte --endpoint <endpoint> --org <org> get project <project_name>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Increase verbosity level (This is useful for debugging,
|
|
122
|
+
this will show more logs and exception traces):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
$ flyte -vvv get logs <run-name>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Override the default config file:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
$ flyte --config /path/to/config.yaml run ...
|
|
132
|
+
```
|
|
83
133
|
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
|
|
87
|
-
(
|
|
134
|
+
* [Documentation](https://www.union.ai/docs/flyte/user-guide/)
|
|
135
|
+
* [GitHub](https://github.com/flyteorg/flyte): Please leave a star if you like Flyte!
|
|
136
|
+
* [Slack](https://slack.flyte.org): Join the community and ask questions.
|
|
137
|
+
* [Issues](https://github.com/flyteorg/flyte/issues)
|
|
88
138
|
|
|
89
|
-
The flyte cli follows a simple verb based structure, where the top-level commands are verbs that describe the action
|
|
90
|
-
to be taken, and the subcommands are nouns that describe the object of the action.
|
|
91
139
|
"""
|
|
92
140
|
import flyte.config as config
|
|
93
141
|
|
|
@@ -108,6 +156,7 @@ to be taken, and the subcommands are nouns that describe the object of the actio
|
|
|
108
156
|
insecure=final_insecure,
|
|
109
157
|
org_override=org or cfg.task.org,
|
|
110
158
|
config=cfg,
|
|
159
|
+
ctx=ctx,
|
|
111
160
|
)
|
|
112
161
|
logger.debug(f"Final materialized Cli config: {ctx.obj}")
|
|
113
162
|
|
|
@@ -117,3 +166,4 @@ main.add_command(deploy)
|
|
|
117
166
|
main.add_command(get) # type: ignore
|
|
118
167
|
main.add_command(create) # type: ignore
|
|
119
168
|
main.add_command(abort) # type: ignore
|
|
169
|
+
main.add_command(gen) # type: ignore
|
flyte/extras/_container.py
CHANGED
|
@@ -215,7 +215,7 @@ class ContainerTask(TaskTemplate):
|
|
|
215
215
|
output_dict[k] = self._convert_output_val_to_correct_type(output_val, output_type)
|
|
216
216
|
return output_dict
|
|
217
217
|
|
|
218
|
-
def execute(self, **kwargs) -> Any:
|
|
218
|
+
async def execute(self, **kwargs) -> Any:
|
|
219
219
|
try:
|
|
220
220
|
import docker
|
|
221
221
|
except ImportError:
|
flyte/models.py
CHANGED
|
@@ -5,7 +5,9 @@ import os
|
|
|
5
5
|
import pathlib
|
|
6
6
|
import tempfile
|
|
7
7
|
from dataclasses import dataclass, field, replace
|
|
8
|
-
from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Tuple, Type
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Literal, Optional, Tuple, Type
|
|
9
|
+
|
|
10
|
+
import rich.repr
|
|
9
11
|
|
|
10
12
|
from flyte._docstring import Docstring
|
|
11
13
|
from flyte._interface import extract_return_annotation
|
|
@@ -27,6 +29,7 @@ def generate_random_name() -> str:
|
|
|
27
29
|
return str(uuid4()) # Placeholder for actual random name generation logic
|
|
28
30
|
|
|
29
31
|
|
|
32
|
+
@rich.repr.auto
|
|
30
33
|
@dataclass(frozen=True, kw_only=True)
|
|
31
34
|
class ActionID:
|
|
32
35
|
"""
|
|
@@ -68,6 +71,7 @@ class ActionID:
|
|
|
68
71
|
return self.new_sub_action(new_name)
|
|
69
72
|
|
|
70
73
|
|
|
74
|
+
@rich.repr.auto
|
|
71
75
|
@dataclass(frozen=True, kw_only=True)
|
|
72
76
|
class RawDataPath:
|
|
73
77
|
"""
|
|
@@ -133,11 +137,13 @@ class RawDataPath:
|
|
|
133
137
|
return remote_path
|
|
134
138
|
|
|
135
139
|
|
|
140
|
+
@rich.repr.auto
|
|
136
141
|
@dataclass(frozen=True)
|
|
137
142
|
class GroupData:
|
|
138
143
|
name: str
|
|
139
144
|
|
|
140
145
|
|
|
146
|
+
@rich.repr.auto
|
|
141
147
|
@dataclass(frozen=True, kw_only=True)
|
|
142
148
|
class TaskContext:
|
|
143
149
|
"""
|
|
@@ -160,6 +166,7 @@ class TaskContext:
|
|
|
160
166
|
code_bundle: CodeBundle | None = None
|
|
161
167
|
compiled_image_cache: ImageCache | None = None
|
|
162
168
|
data: Dict[str, Any] = field(default_factory=dict)
|
|
169
|
+
mode: Literal["local", "remote", "hybrid"] = "remote"
|
|
163
170
|
|
|
164
171
|
def replace(self, **kwargs) -> TaskContext:
|
|
165
172
|
if "data" in kwargs:
|
|
@@ -177,6 +184,7 @@ class TaskContext:
|
|
|
177
184
|
return self.data.get(key)
|
|
178
185
|
|
|
179
186
|
|
|
187
|
+
@rich.repr.auto
|
|
180
188
|
@dataclass(frozen=True, kw_only=True)
|
|
181
189
|
class CodeBundle:
|
|
182
190
|
"""
|
|
@@ -211,6 +219,7 @@ class CodeBundle:
|
|
|
211
219
|
return replace(self, downloaded_path=path)
|
|
212
220
|
|
|
213
221
|
|
|
222
|
+
@rich.repr.auto
|
|
214
223
|
@dataclass(frozen=True)
|
|
215
224
|
class Checkpoints:
|
|
216
225
|
"""
|
flyte/remote/_run.py
CHANGED
|
@@ -50,6 +50,7 @@ def _action_rich_repr(action: run_definition_pb2.Action) -> rich.repr.Result:
|
|
|
50
50
|
"""
|
|
51
51
|
Rich representation of the action.
|
|
52
52
|
"""
|
|
53
|
+
yield "run", action.id.run.name
|
|
53
54
|
if action.metadata.HasField("task"):
|
|
54
55
|
yield "task", action.metadata.task.id.name
|
|
55
56
|
yield "type", "task"
|
flyte/syncify/__init__.py
CHANGED
|
@@ -1,3 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# Syncify Module
|
|
3
|
+
This module provides the `syncify` decorator and the `Syncify` class.
|
|
4
|
+
The decorator can be used to convert asynchronous functions or methods into synchronous ones.
|
|
5
|
+
This is useful for integrating async code into synchronous contexts.
|
|
6
|
+
|
|
7
|
+
Every asynchronous function or method wrapped with `syncify` can be called synchronously using the
|
|
8
|
+
parenthesis `()` operator, or asynchronously using the `.aio()` method.
|
|
9
|
+
|
|
10
|
+
Example::
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from flyte.syncify import syncify
|
|
14
|
+
|
|
15
|
+
@syncify
|
|
16
|
+
async def async_function(x: str) -> str:
|
|
17
|
+
return f"Hello, Async World {x}!"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# now you can call it synchronously
|
|
21
|
+
result = async_function("Async World") # Note: no .aio() needed for sync calls
|
|
22
|
+
print(result)
|
|
23
|
+
# Output: Hello, Async World Async World!
|
|
24
|
+
|
|
25
|
+
# or call it asynchronously
|
|
26
|
+
async def main():
|
|
27
|
+
result = await async_function.aio("World") # Note the use of .aio() for async calls
|
|
28
|
+
print(result)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Creating a Syncify Instance
|
|
32
|
+
```python
|
|
33
|
+
from flyte.syncify. import Syncify
|
|
34
|
+
|
|
35
|
+
syncer = Syncify("my_syncer")
|
|
36
|
+
|
|
37
|
+
# Now you can use `syncer` to decorate your async functions or methods
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## How does it work?
|
|
42
|
+
The Syncify class wraps asynchronous functions, classmethods, instance methods, and static methods to
|
|
43
|
+
provide a synchronous interface. The wrapped methods are always executed in the context of a background loop,
|
|
44
|
+
whether they are called synchronously or asynchronously. This allows for seamless integration of async code, as
|
|
45
|
+
certain async libraries capture the event loop. An example is grpc.aio, which captures the event loop.
|
|
46
|
+
In such a case, the Syncify class ensures that the async function is executed in the context of the background loop.
|
|
47
|
+
|
|
48
|
+
To use it correctly with grpc.aio, you should wrap every grpc.aio channel creation, and client invocation
|
|
49
|
+
with the same `Syncify` instance. This ensures that the async code runs in the correct event loop context.
|
|
50
|
+
"""
|
|
51
|
+
|
|
1
52
|
from flyte.syncify._api import Syncify
|
|
2
53
|
|
|
3
54
|
syncify = Syncify()
|