flyte 0.2.0b1__py3-none-any.whl → 0.2.0b3__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 +3 -4
- flyte/_bin/runtime.py +21 -7
- flyte/_cache/cache.py +1 -2
- flyte/_cli/_common.py +26 -4
- flyte/_cli/_create.py +48 -0
- flyte/_cli/_deploy.py +4 -2
- flyte/_cli/_get.py +18 -7
- flyte/_cli/_run.py +1 -0
- flyte/_cli/main.py +11 -5
- flyte/_code_bundle/bundle.py +42 -11
- flyte/_context.py +1 -1
- flyte/_deploy.py +3 -1
- flyte/_group.py +1 -1
- flyte/_initialize.py +28 -247
- flyte/_internal/controllers/__init__.py +6 -6
- flyte/_internal/controllers/_local_controller.py +14 -5
- flyte/_internal/controllers/_trace.py +1 -1
- flyte/_internal/controllers/remote/__init__.py +27 -7
- flyte/_internal/controllers/remote/_action.py +1 -1
- flyte/_internal/controllers/remote/_client.py +5 -1
- flyte/_internal/controllers/remote/_controller.py +68 -24
- flyte/_internal/controllers/remote/_core.py +1 -1
- flyte/_internal/runtime/convert.py +34 -8
- flyte/_internal/runtime/entrypoints.py +1 -1
- flyte/_internal/runtime/io.py +3 -3
- flyte/_internal/runtime/task_serde.py +31 -1
- flyte/_internal/runtime/taskrunner.py +1 -1
- flyte/_internal/runtime/types_serde.py +1 -1
- flyte/_run.py +47 -28
- flyte/_task.py +2 -2
- flyte/_task_environment.py +1 -1
- flyte/_trace.py +5 -6
- flyte/_utils/__init__.py +2 -0
- flyte/_utils/async_cache.py +139 -0
- flyte/_version.py +2 -2
- flyte/config/__init__.py +26 -4
- flyte/config/_config.py +13 -4
- flyte/extras/_container.py +3 -3
- flyte/{_datastructures.py → models.py} +3 -2
- flyte/remote/_client/auth/_auth_utils.py +14 -0
- flyte/remote/_client/auth/_channel.py +28 -3
- flyte/remote/_client/auth/_token_client.py +3 -3
- flyte/remote/_client/controlplane.py +13 -13
- flyte/remote/_logs.py +1 -1
- flyte/remote/_run.py +4 -8
- flyte/remote/_task.py +2 -2
- flyte/storage/__init__.py +5 -0
- flyte/storage/_config.py +233 -0
- flyte/storage/_storage.py +23 -3
- flyte/types/_interface.py +1 -1
- flyte/types/_type_engine.py +1 -1
- {flyte-0.2.0b1.dist-info → flyte-0.2.0b3.dist-info}/METADATA +2 -2
- {flyte-0.2.0b1.dist-info → flyte-0.2.0b3.dist-info}/RECORD +56 -54
- flyte/_internal/controllers/pbhash.py +0 -39
- {flyte-0.2.0b1.dist-info → flyte-0.2.0b3.dist-info}/WHEEL +0 -0
- {flyte-0.2.0b1.dist-info → flyte-0.2.0b3.dist-info}/entry_points.txt +0 -0
- {flyte-0.2.0b1.dist-info → flyte-0.2.0b3.dist-info}/top_level.txt +0 -0
flyte/__init__.py
CHANGED
|
@@ -17,15 +17,13 @@ async def my_task():
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
__all__ = [
|
|
20
|
-
"ABFS",
|
|
21
|
-
"GCS",
|
|
22
20
|
"GPU",
|
|
23
|
-
"S3",
|
|
24
21
|
"TPU",
|
|
25
22
|
"Cache",
|
|
26
23
|
"CachePolicy",
|
|
27
24
|
"CacheRequest",
|
|
28
25
|
"Device",
|
|
26
|
+
"Environment",
|
|
29
27
|
"Image",
|
|
30
28
|
"Resources",
|
|
31
29
|
"RetryStrategy",
|
|
@@ -48,9 +46,10 @@ __all__ = [
|
|
|
48
46
|
from ._cache import Cache, CachePolicy, CacheRequest
|
|
49
47
|
from ._context import ctx
|
|
50
48
|
from ._deploy import deploy
|
|
49
|
+
from ._environment import Environment
|
|
51
50
|
from ._group import group
|
|
52
51
|
from ._image import Image
|
|
53
|
-
from ._initialize import
|
|
52
|
+
from ._initialize import init
|
|
54
53
|
from ._resources import GPU, TPU, Device, Resources
|
|
55
54
|
from ._retry import RetryStrategy
|
|
56
55
|
from ._reusable_environment import ReusePolicy
|
flyte/_bin/runtime.py
CHANGED
|
@@ -8,7 +8,7 @@ Refrain from importing any modules here. If you need to import any modules, do i
|
|
|
8
8
|
import asyncio
|
|
9
9
|
import os
|
|
10
10
|
import sys
|
|
11
|
-
from typing import List
|
|
11
|
+
from typing import Any, List
|
|
12
12
|
|
|
13
13
|
import click
|
|
14
14
|
|
|
@@ -27,6 +27,9 @@ ORG_NAME = "_U_ORG_NAME"
|
|
|
27
27
|
ENDPOINT_OVERRIDE = "_U_EP_OVERRIDE"
|
|
28
28
|
RUN_OUTPUT_BASE_DIR = "_U_RUN_BASE"
|
|
29
29
|
|
|
30
|
+
# TODO: Remove this after proper auth is implemented
|
|
31
|
+
_UNION_EAGER_API_KEY_ENV_VAR = "_UNION_EAGER_API_KEY"
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
@click.command("a0")
|
|
32
35
|
@click.option("--inputs", "-i", required=True)
|
|
@@ -74,11 +77,11 @@ def main(
|
|
|
74
77
|
sys.path.insert(0, ".")
|
|
75
78
|
|
|
76
79
|
import flyte._utils as utils
|
|
77
|
-
from flyte.
|
|
78
|
-
from flyte._initialize import S3, initialize_in_cluster
|
|
80
|
+
from flyte._initialize import initialize_in_cluster
|
|
79
81
|
from flyte._internal.controllers import create_controller
|
|
80
82
|
from flyte._internal.imagebuild.image_builder import ImageCache
|
|
81
83
|
from flyte._internal.runtime.entrypoints import load_and_run_task
|
|
84
|
+
from flyte.models import ActionID, Checkpoints, CodeBundle, RawDataPath
|
|
82
85
|
|
|
83
86
|
assert org, "Org is required for now"
|
|
84
87
|
assert project, "Project is required"
|
|
@@ -91,12 +94,23 @@ def main(
|
|
|
91
94
|
if name.startswith("{{"):
|
|
92
95
|
name = os.getenv("ACTION_NAME", "")
|
|
93
96
|
|
|
94
|
-
|
|
97
|
+
# Figure out how to connect
|
|
98
|
+
# This detection of api key is a hack for now.
|
|
99
|
+
controller_kwargs: dict[str, Any] = {"insecure": False}
|
|
100
|
+
if api_key := os.getenv(_UNION_EAGER_API_KEY_ENV_VAR):
|
|
101
|
+
from flyte._logging import logger
|
|
102
|
+
|
|
103
|
+
logger.warning(f"Using api key {api_key}")
|
|
104
|
+
controller_kwargs["api_key"] = api_key
|
|
105
|
+
else:
|
|
106
|
+
ep = os.environ.get(ENDPOINT_OVERRIDE, "host.docker.internal:8090")
|
|
107
|
+
controller_kwargs["endpoint"] = ep
|
|
108
|
+
if "localhost" in ep or "docker" in ep:
|
|
109
|
+
controller_kwargs["insecure"] = True
|
|
95
110
|
|
|
96
111
|
bundle = CodeBundle(tgz=tgz, pkl=pkl, destination=dest, computed_version=version)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
controller = create_controller(ct="remote", endpoint=ep, insecure=True)
|
|
112
|
+
initialize_in_cluster()
|
|
113
|
+
controller = create_controller(ct="remote", **controller_kwargs)
|
|
100
114
|
|
|
101
115
|
ic = ImageCache.from_transport(image_cache) if image_cache else None
|
|
102
116
|
|
flyte/_cache/cache.py
CHANGED
|
@@ -14,10 +14,9 @@ from typing import (
|
|
|
14
14
|
import rich.repr
|
|
15
15
|
from typing_extensions import Literal, ParamSpec, TypeVar, get_args
|
|
16
16
|
|
|
17
|
-
from flyte._datastructures import CodeBundle
|
|
18
|
-
|
|
19
17
|
# if TYPE_CHECKING:
|
|
20
18
|
from flyte._image import Image
|
|
19
|
+
from flyte.models import CodeBundle
|
|
21
20
|
|
|
22
21
|
P = ParamSpec("P")
|
|
23
22
|
FuncOut = TypeVar("FuncOut")
|
flyte/_cli/_common.py
CHANGED
|
@@ -11,6 +11,7 @@ from types import MappingProxyType, ModuleType
|
|
|
11
11
|
from typing import Any, Dict, Iterable, List, Optional
|
|
12
12
|
|
|
13
13
|
import rich.box
|
|
14
|
+
import rich.repr
|
|
14
15
|
import rich_click as click
|
|
15
16
|
from rich.console import Console
|
|
16
17
|
from rich.panel import Panel
|
|
@@ -28,7 +29,7 @@ PROJECT_OPTION = click.Option(
|
|
|
28
29
|
param_decls=["-p", "--project"],
|
|
29
30
|
required=False,
|
|
30
31
|
type=str,
|
|
31
|
-
default=
|
|
32
|
+
default=None,
|
|
32
33
|
help="Project to operate on",
|
|
33
34
|
show_default=True,
|
|
34
35
|
)
|
|
@@ -37,7 +38,7 @@ DOMAIN_OPTION = click.Option(
|
|
|
37
38
|
param_decls=["-d", "--domain"],
|
|
38
39
|
required=False,
|
|
39
40
|
type=str,
|
|
40
|
-
default=
|
|
41
|
+
default=None,
|
|
41
42
|
help="Domain to operate on",
|
|
42
43
|
show_default=True,
|
|
43
44
|
)
|
|
@@ -63,6 +64,7 @@ def _common_options() -> List[click.Option]:
|
|
|
63
64
|
# This is global state for the CLI, it is manipulated by the main command
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
@rich.repr.auto
|
|
66
68
|
@dataclass(frozen=True)
|
|
67
69
|
class CLIConfig:
|
|
68
70
|
"""
|
|
@@ -84,13 +86,17 @@ class CLIConfig:
|
|
|
84
86
|
def init(self, project: str | None = None, domain: str | None = None):
|
|
85
87
|
import flyte
|
|
86
88
|
|
|
89
|
+
if self.config and self.config.task:
|
|
90
|
+
# If the config is already set, we can use it to initialize flyte
|
|
91
|
+
project = project or self.config.task.project
|
|
92
|
+
domain = domain or self.config.task.domain
|
|
93
|
+
|
|
87
94
|
flyte.init(
|
|
88
95
|
endpoint=self.endpoint,
|
|
89
96
|
insecure=self.insecure,
|
|
90
97
|
org=self.org_override,
|
|
91
98
|
project=project,
|
|
92
99
|
domain=domain,
|
|
93
|
-
log_level=self.log_level,
|
|
94
100
|
config=self.config,
|
|
95
101
|
)
|
|
96
102
|
|
|
@@ -113,12 +119,26 @@ class InvokeBaseMixin:
|
|
|
113
119
|
raise click.ClickException(f"Requested object NOT FOUND. Please check your input. Error: {e.details()}")
|
|
114
120
|
if e.code() == grpc.StatusCode.ALREADY_EXISTS:
|
|
115
121
|
raise click.ClickException("Resource already exists.")
|
|
122
|
+
if e.code() == grpc.StatusCode.INTERNAL:
|
|
123
|
+
raise click.ClickException(f"Internal server error: {e.details()}")
|
|
124
|
+
if e.code() == grpc.StatusCode.UNAVAILABLE:
|
|
125
|
+
raise click.ClickException(
|
|
126
|
+
f"Service is currently unavailable. Please try again later. Error: {e.details()}"
|
|
127
|
+
)
|
|
128
|
+
if e.code() == grpc.StatusCode.PERMISSION_DENIED:
|
|
129
|
+
raise click.ClickException(f"Permission denied. Please check your access rights. Error: {e.details()}")
|
|
130
|
+
if e.code() == grpc.StatusCode.INVALID_ARGUMENT:
|
|
131
|
+
raise click.ClickException(f"Invalid argument provided. Please check your input. Error: {e.details()}")
|
|
116
132
|
raise click.ClickException(f"RPC error invoking command: {e!s}") from e
|
|
117
133
|
except flyte.errors.InitializationError:
|
|
118
134
|
raise click.ClickException("Initialize the CLI with a remote configuration. For example, pass --endpoint")
|
|
119
135
|
except click.exceptions.Exit as e:
|
|
120
136
|
# This is a normal exit, do nothing
|
|
121
137
|
raise e
|
|
138
|
+
except click.exceptions.NoArgsIsHelpError:
|
|
139
|
+
# Do not raise an error if no arguments are passed, just show the help message.
|
|
140
|
+
# https://github.com/pallets/click/pull/1489
|
|
141
|
+
return None
|
|
122
142
|
except Exception as e:
|
|
123
143
|
if ctx.obj and ctx.obj.log_level and ctx.obj.log_level <= logging.DEBUG:
|
|
124
144
|
# If the user has requested verbose output, print the full traceback
|
|
@@ -185,8 +205,10 @@ class ObjectsPerFileGroup(GroupBase):
|
|
|
185
205
|
Group that creates a command for each object in a python file.
|
|
186
206
|
"""
|
|
187
207
|
|
|
188
|
-
def __init__(self, filename: Path, *args, **kwargs):
|
|
208
|
+
def __init__(self, filename: Path | None = None, *args, **kwargs):
|
|
189
209
|
super().__init__(*args, **kwargs)
|
|
210
|
+
if filename is None:
|
|
211
|
+
raise ValueError("filename must be provided")
|
|
190
212
|
if not filename.exists():
|
|
191
213
|
raise click.ClickException(f"{filename} does not exists")
|
|
192
214
|
self.filename = filename
|
flyte/_cli/_create.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from pathlib import Path
|
|
1
2
|
from typing import get_args
|
|
2
3
|
|
|
3
4
|
import rich_click as click
|
|
@@ -40,3 +41,50 @@ def secret(
|
|
|
40
41
|
with open(from_file, "rb") as f:
|
|
41
42
|
value = f.read()
|
|
42
43
|
Secret.create(name=name, value=value, type=type)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@create.command(cls=common.CommandBase)
|
|
47
|
+
@click.option("--endpoint", type=str, help="Endpoint of the Flyte backend.")
|
|
48
|
+
@click.option("--insecure", is_flag=True, help="Use insecure connection to the Flyte backend.")
|
|
49
|
+
@click.option(
|
|
50
|
+
"--org",
|
|
51
|
+
type=str,
|
|
52
|
+
required=False,
|
|
53
|
+
help="Organization to use, this will override the organization in the config file.",
|
|
54
|
+
)
|
|
55
|
+
@click.option(
|
|
56
|
+
"-o",
|
|
57
|
+
"--output",
|
|
58
|
+
type=click.Path(),
|
|
59
|
+
default=Path.cwd(),
|
|
60
|
+
help="Path to the output dir where the config will be saved, defaults to current directory.",
|
|
61
|
+
)
|
|
62
|
+
def config(
|
|
63
|
+
output: Path,
|
|
64
|
+
endpoint: str | None = None,
|
|
65
|
+
insecure: bool = False,
|
|
66
|
+
org: str | None = None,
|
|
67
|
+
project: str | None = None,
|
|
68
|
+
domain: str | None = None,
|
|
69
|
+
):
|
|
70
|
+
"""
|
|
71
|
+
Create a new config file.
|
|
72
|
+
"""
|
|
73
|
+
import yaml
|
|
74
|
+
|
|
75
|
+
output_file = output / "config.yaml"
|
|
76
|
+
with open(output_file, "w") as f:
|
|
77
|
+
d = {
|
|
78
|
+
"admin": {
|
|
79
|
+
"endpoint": endpoint,
|
|
80
|
+
"insecure": insecure,
|
|
81
|
+
},
|
|
82
|
+
"task": {
|
|
83
|
+
"org": org,
|
|
84
|
+
"project": project,
|
|
85
|
+
"domain": domain,
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
yaml.dump(d, f)
|
|
89
|
+
|
|
90
|
+
click.echo(f"Config file created at {output_file}")
|
flyte/_cli/_deploy.py
CHANGED
|
@@ -91,15 +91,17 @@ class EnvPerFileGroup(common.ObjectsPerFileGroup):
|
|
|
91
91
|
"""
|
|
92
92
|
|
|
93
93
|
def __init__(self, filename: Path, deploy_args: DeployArguments, *args, **kwargs):
|
|
94
|
+
args = (filename, *args)
|
|
94
95
|
super().__init__(*args, **kwargs)
|
|
95
96
|
self.deploy_args = deploy_args
|
|
96
97
|
|
|
97
98
|
def _filter_objects(self, module: ModuleType) -> Dict[str, Any]:
|
|
98
|
-
return {k: v for k, v in module.__dict__.items() if isinstance(v, flyte.
|
|
99
|
+
return {k: v for k, v in module.__dict__.items() if isinstance(v, flyte.Environment)}
|
|
99
100
|
|
|
100
101
|
def _get_command_for_obj(self, ctx: click.Context, obj_name: str, obj: Any) -> click.Command:
|
|
101
|
-
obj = cast(flyte.
|
|
102
|
+
obj = cast(flyte.Environment, obj)
|
|
102
103
|
return DeployEnvCommand(
|
|
104
|
+
name=obj_name,
|
|
103
105
|
obj_name=obj_name,
|
|
104
106
|
obj=obj,
|
|
105
107
|
help=obj.description,
|
flyte/_cli/_get.py
CHANGED
|
@@ -112,17 +112,17 @@ def action(
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
@get.command(cls=common.CommandBase)
|
|
115
|
-
@click.argument("run_name", type=str, required=
|
|
115
|
+
@click.argument("run_name", type=str, required=True)
|
|
116
116
|
@click.argument("action_name", type=str, required=False)
|
|
117
|
-
@click.option("--lines", "-l", type=int, default=30, help="Number of lines to show")
|
|
117
|
+
@click.option("--lines", "-l", type=int, default=30, help="Number of lines to show, only useful for --pretty")
|
|
118
118
|
@click.option("--show-ts", is_flag=True, help="Show timestamps")
|
|
119
119
|
@click.option(
|
|
120
|
-
"--
|
|
121
|
-
"-f",
|
|
120
|
+
"--pretty",
|
|
122
121
|
is_flag=True,
|
|
123
122
|
default=False,
|
|
124
|
-
help="
|
|
123
|
+
help="Show logs in a auto scrolling box, where number of lines is limited to `--lines`",
|
|
125
124
|
)
|
|
125
|
+
@click.option("--attempt", "-a", type=int, default=None, help="Attempt number to show logs for")
|
|
126
126
|
@click.pass_obj
|
|
127
127
|
def logs(
|
|
128
128
|
cfg: common.CLIConfig,
|
|
@@ -132,7 +132,8 @@ def logs(
|
|
|
132
132
|
domain: str | None = None,
|
|
133
133
|
lines: int = 30,
|
|
134
134
|
show_ts: bool = False,
|
|
135
|
-
|
|
135
|
+
pretty: bool = True,
|
|
136
|
+
attempt: int | None = None,
|
|
136
137
|
):
|
|
137
138
|
"""
|
|
138
139
|
Get the current run.
|
|
@@ -142,7 +143,7 @@ def logs(
|
|
|
142
143
|
cfg.init(project=project, domain=domain)
|
|
143
144
|
|
|
144
145
|
async def _run_log_view(_obj):
|
|
145
|
-
task = asyncio.create_task(_obj.show_logs(max_lines=lines, show_ts=show_ts, raw=not
|
|
146
|
+
task = asyncio.create_task(_obj.show_logs(max_lines=lines, show_ts=show_ts, raw=not pretty, attempt=attempt))
|
|
146
147
|
try:
|
|
147
148
|
await task
|
|
148
149
|
except KeyboardInterrupt:
|
|
@@ -233,3 +234,13 @@ def io(
|
|
|
233
234
|
f"[green bold]Inputs[/green bold]\n{inputs}\n\n[blue bold]Outputs[/blue bold]\n{outputs}",
|
|
234
235
|
)
|
|
235
236
|
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@get.command(cls=click.RichCommand)
|
|
240
|
+
@click.pass_obj
|
|
241
|
+
def config(cfg: common.CLIConfig):
|
|
242
|
+
"""
|
|
243
|
+
Shows the automatically detected configuration to connect with remote Flyte services.
|
|
244
|
+
"""
|
|
245
|
+
console = Console()
|
|
246
|
+
console.print(cfg)
|
flyte/_cli/_run.py
CHANGED
|
@@ -73,6 +73,7 @@ class RunTaskCommand(click.Command):
|
|
|
73
73
|
|
|
74
74
|
def invoke(self, ctx: Context):
|
|
75
75
|
obj: CLIConfig = ctx.obj or CLIConfig()
|
|
76
|
+
assert obj.endpoint, "CLI Config should have an endpoint"
|
|
76
77
|
obj.init(self.run_args.project, self.run_args.domain)
|
|
77
78
|
|
|
78
79
|
r = flyte.with_runcontext(
|
flyte/_cli/main.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import rich_click as click
|
|
2
2
|
|
|
3
|
+
from flyte._logging import initialize_logger, logger
|
|
4
|
+
|
|
3
5
|
from ..config import Config
|
|
4
6
|
from ._common import CLIConfig
|
|
5
7
|
from ._create import create
|
|
@@ -41,7 +43,7 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
41
43
|
required=False,
|
|
42
44
|
help="insecure",
|
|
43
45
|
type=bool,
|
|
44
|
-
default=
|
|
46
|
+
default=None,
|
|
45
47
|
)
|
|
46
48
|
@click.option(
|
|
47
49
|
"-v",
|
|
@@ -53,10 +55,10 @@ def _verbosity_to_loglevel(verbosity: int) -> int | None:
|
|
|
53
55
|
type=int,
|
|
54
56
|
)
|
|
55
57
|
@click.option(
|
|
56
|
-
"--org
|
|
58
|
+
"--org",
|
|
57
59
|
type=str,
|
|
58
60
|
required=False,
|
|
59
|
-
help="
|
|
61
|
+
help="Organization to use",
|
|
60
62
|
)
|
|
61
63
|
@click.option(
|
|
62
64
|
"-c",
|
|
@@ -73,23 +75,27 @@ def main(
|
|
|
73
75
|
endpoint: str | None,
|
|
74
76
|
insecure: bool,
|
|
75
77
|
verbose: int,
|
|
76
|
-
|
|
78
|
+
org: str | None,
|
|
77
79
|
config_file: str | None,
|
|
78
80
|
):
|
|
79
81
|
"""
|
|
80
82
|
v2 cli. Root command, please use one of the subcommands.
|
|
81
83
|
"""
|
|
82
84
|
log_level = _verbosity_to_loglevel(verbose)
|
|
85
|
+
if log_level is not None:
|
|
86
|
+
initialize_logger(log_level)
|
|
83
87
|
|
|
84
88
|
config = Config.auto(config_file=config_file)
|
|
89
|
+
logger.debug(f"Using config file discovered at location {config.source}")
|
|
85
90
|
|
|
86
91
|
ctx.obj = CLIConfig(
|
|
87
92
|
log_level=log_level,
|
|
88
93
|
endpoint=endpoint or config.platform.endpoint,
|
|
89
94
|
insecure=insecure or config.platform.insecure,
|
|
90
|
-
org_override=
|
|
95
|
+
org_override=org or config.task.org,
|
|
91
96
|
config=config,
|
|
92
97
|
)
|
|
98
|
+
logger.debug(f"Final materialized Cli config: {ctx.obj}")
|
|
93
99
|
|
|
94
100
|
|
|
95
101
|
main.add_command(run)
|
flyte/_code_bundle/bundle.py
CHANGED
|
@@ -5,13 +5,13 @@ import os
|
|
|
5
5
|
import pathlib
|
|
6
6
|
import tempfile
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Type
|
|
8
|
+
from typing import ClassVar, Type
|
|
9
9
|
|
|
10
10
|
from flyteidl.core.tasks_pb2 import TaskTemplate
|
|
11
11
|
|
|
12
|
-
import flyte.storage as storage
|
|
13
|
-
from flyte._datastructures import CodeBundle
|
|
14
12
|
from flyte._logging import log, logger
|
|
13
|
+
from flyte._utils import AsyncLRUCache
|
|
14
|
+
from flyte.models import CodeBundle
|
|
15
15
|
|
|
16
16
|
from ._ignore import GitIgnore, Ignore, StandardIgnore
|
|
17
17
|
from ._packaging import create_bundle, list_files_to_bundle, print_ls_tree
|
|
@@ -21,10 +21,34 @@ _pickled_file_extension = ".pkl.gz"
|
|
|
21
21
|
_tar_file_extension = ".tar.gz"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
class _PklCache:
|
|
25
|
+
_pkl_cache: ClassVar[AsyncLRUCache[str, str]] = AsyncLRUCache[str, str](maxsize=100)
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
async def put(cls, digest: str, upload_to_path: str, from_path: pathlib.Path) -> str:
|
|
29
|
+
"""
|
|
30
|
+
Get the pickled code bundle from the cache or build it if not present.
|
|
31
|
+
|
|
32
|
+
:param digest: The hash digest of the task template.
|
|
33
|
+
:param upload_to_path: The path to upload the pickled file to.
|
|
34
|
+
:param from_path: The path to read the pickled file from.
|
|
35
|
+
:return: CodeBundle object containing the pickled file path and the computed version.
|
|
36
|
+
"""
|
|
37
|
+
import flyte.storage as storage
|
|
38
|
+
|
|
39
|
+
async def put_data() -> str:
|
|
40
|
+
return await storage.put(str(from_path), to_path=str(upload_to_path))
|
|
41
|
+
|
|
42
|
+
return await cls._pkl_cache.get(
|
|
43
|
+
key=digest,
|
|
44
|
+
value_func=put_data,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
24
48
|
async def build_pkl_bundle(
|
|
25
49
|
o: TaskTemplate,
|
|
26
50
|
upload_to_controlplane: bool = True,
|
|
27
|
-
|
|
51
|
+
upload_from_dataplane_base_path: str | None = None,
|
|
28
52
|
copy_bundle_to: pathlib.Path | None = None,
|
|
29
53
|
) -> CodeBundle:
|
|
30
54
|
"""
|
|
@@ -36,16 +60,14 @@ async def build_pkl_bundle(
|
|
|
36
60
|
|
|
37
61
|
:param o: Object to be pickled. This is the task template.
|
|
38
62
|
:param upload_to_controlplane: Whether to upload the pickled file to the control plane or not
|
|
39
|
-
:param
|
|
63
|
+
:param upload_from_dataplane_base_path: If we are on the dataplane, this is the path where the
|
|
40
64
|
pickled file should be uploaded to. upload_to_controlplane has to be False in this case.
|
|
41
65
|
:param copy_bundle_to: If set, the bundle will be copied to this path. This is used for testing purposes.
|
|
42
66
|
:return: CodeBundle object containing the pickled file path and the computed version.
|
|
43
67
|
"""
|
|
44
68
|
import cloudpickle
|
|
45
69
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if upload_to_controlplane and upload_from_dataplane_path:
|
|
70
|
+
if upload_to_controlplane and upload_from_dataplane_base_path:
|
|
49
71
|
raise ValueError("Cannot upload to control plane and upload from dataplane path at the same time.")
|
|
50
72
|
|
|
51
73
|
logger.debug("Building pickled code bundle.")
|
|
@@ -61,10 +83,17 @@ async def build_pkl_bundle(
|
|
|
61
83
|
hash_digest, remote_path = await upload_file(dest)
|
|
62
84
|
return CodeBundle(pkl=remote_path, computed_version=hash_digest)
|
|
63
85
|
|
|
64
|
-
elif
|
|
65
|
-
|
|
86
|
+
elif upload_from_dataplane_base_path:
|
|
87
|
+
from flyte._internal.runtime import io
|
|
88
|
+
|
|
66
89
|
_, str_digest, _ = hash_file(file_path=dest)
|
|
67
|
-
|
|
90
|
+
upload_path = io.pkl_path(upload_from_dataplane_base_path, str_digest)
|
|
91
|
+
logger.debug(f"Uploading pickled code bundle to dataplane path {upload_path}.")
|
|
92
|
+
final_path = await _PklCache.put(
|
|
93
|
+
digest=str_digest,
|
|
94
|
+
upload_to_path=upload_path,
|
|
95
|
+
from_path=dest,
|
|
96
|
+
)
|
|
68
97
|
return CodeBundle(pkl=final_path, computed_version=str_digest)
|
|
69
98
|
|
|
70
99
|
else:
|
|
@@ -138,6 +167,8 @@ async def download_bundle(bundle: CodeBundle) -> pathlib.Path:
|
|
|
138
167
|
|
|
139
168
|
:return: The path to the downloaded code bundle.
|
|
140
169
|
"""
|
|
170
|
+
import flyte.storage as storage
|
|
171
|
+
|
|
141
172
|
dest = pathlib.Path(bundle.destination)
|
|
142
173
|
if not dest.is_dir():
|
|
143
174
|
raise ValueError(f"Destination path should be a directory, found {dest}, {dest.stat()}")
|
flyte/_context.py
CHANGED
|
@@ -4,7 +4,7 @@ import contextvars
|
|
|
4
4
|
from dataclasses import dataclass, replace
|
|
5
5
|
from typing import TYPE_CHECKING, Awaitable, Callable, Optional, ParamSpec, TypeVar
|
|
6
6
|
|
|
7
|
-
from flyte.
|
|
7
|
+
from flyte.models import GroupData, RawDataPath, TaskContext
|
|
8
8
|
|
|
9
9
|
if TYPE_CHECKING:
|
|
10
10
|
from flyte.report import Report
|
flyte/_deploy.py
CHANGED
|
@@ -6,8 +6,9 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
|
|
6
6
|
|
|
7
7
|
import rich.repr
|
|
8
8
|
|
|
9
|
+
from flyte.models import SerializationContext
|
|
10
|
+
|
|
9
11
|
from ._api_commons import syncer
|
|
10
|
-
from ._datastructures import SerializationContext
|
|
11
12
|
from ._environment import Environment
|
|
12
13
|
from ._image import Image
|
|
13
14
|
from ._initialize import get_client, get_common_config, requires_client, requires_initialization
|
|
@@ -141,6 +142,7 @@ async def apply(deployment: DeploymentPlan, copy_style: CopyFiles, dryrun: bool
|
|
|
141
142
|
tasks = []
|
|
142
143
|
for env_name, env in deployment.envs.items():
|
|
143
144
|
logger.info(f"Deploying environment {env_name}")
|
|
145
|
+
# TODO Make this pluggable based on the environment type
|
|
144
146
|
if isinstance(env, TaskEnvironment):
|
|
145
147
|
for task in env.tasks.values():
|
|
146
148
|
tasks.append(_deploy_task(task, dryrun=dryrun, serialization_context=sc))
|