flyte 2.0.0b20__py3-none-any.whl → 2.0.0b21__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/_bin/runtime.py +2 -2
- flyte/_code_bundle/_ignore.py +11 -3
- flyte/_code_bundle/_packaging.py +9 -5
- flyte/_code_bundle/_utils.py +2 -2
- flyte/_initialize.py +14 -7
- flyte/_interface.py +35 -2
- flyte/_internal/imagebuild/docker_builder.py +58 -8
- flyte/_internal/imagebuild/remote_builder.py +9 -26
- flyte/_keyring/__init__.py +0 -0
- flyte/_keyring/file.py +85 -0
- flyte/_logging.py +19 -8
- flyte/_utils/coro_management.py +2 -1
- flyte/_version.py +3 -3
- flyte/config/_config.py +6 -4
- flyte/config/_reader.py +19 -4
- flyte/git/_config.py +2 -0
- flyte/io/_dataframe/dataframe.py +3 -2
- flyte/io/_dir.py +72 -72
- flyte/models.py +6 -2
- flyte/remote/_client/auth/_authenticators/device_code.py +3 -4
- flyte/remote/_data.py +2 -3
- flyte/remote/_run.py +17 -1
- flyte/storage/_config.py +5 -1
- flyte/types/_type_engine.py +7 -0
- {flyte-2.0.0b20.data → flyte-2.0.0b21.data}/scripts/runtime.py +2 -2
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/METADATA +1 -1
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/RECORD +32 -30
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/entry_points.txt +3 -0
- {flyte-2.0.0b20.data → flyte-2.0.0b21.data}/scripts/debug.py +0 -0
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/WHEEL +0 -0
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/licenses/LICENSE +0 -0
- {flyte-2.0.0b20.dist-info → flyte-2.0.0b21.dist-info}/top_level.txt +0 -0
flyte/_bin/runtime.py
CHANGED
|
@@ -21,8 +21,8 @@ import click
|
|
|
21
21
|
|
|
22
22
|
ACTION_NAME = "ACTION_NAME"
|
|
23
23
|
RUN_NAME = "RUN_NAME"
|
|
24
|
-
PROJECT_NAME = "
|
|
25
|
-
DOMAIN_NAME = "
|
|
24
|
+
PROJECT_NAME = "FLYTE_INTERNAL_EXECUTION_PROJECT"
|
|
25
|
+
DOMAIN_NAME = "FLYTE_INTERNAL_EXECUTION_DOMAIN"
|
|
26
26
|
ORG_NAME = "_U_ORG_NAME"
|
|
27
27
|
ENDPOINT_OVERRIDE = "_U_EP_OVERRIDE"
|
|
28
28
|
RUN_OUTPUT_BASE_DIR = "_U_RUN_BASE"
|
flyte/_code_bundle/_ignore.py
CHANGED
|
@@ -83,8 +83,15 @@ class StandardIgnore(Ignore):
|
|
|
83
83
|
self.patterns = patterns if patterns else STANDARD_IGNORE_PATTERNS
|
|
84
84
|
|
|
85
85
|
def _is_ignored(self, path: pathlib.Path) -> bool:
|
|
86
|
+
# Convert to relative path for pattern matching
|
|
87
|
+
try:
|
|
88
|
+
rel_path = path.relative_to(self.root)
|
|
89
|
+
except ValueError:
|
|
90
|
+
# If path is not under root, don't ignore it
|
|
91
|
+
return False
|
|
92
|
+
|
|
86
93
|
for pattern in self.patterns:
|
|
87
|
-
if fnmatch(str(
|
|
94
|
+
if fnmatch(str(rel_path), pattern):
|
|
88
95
|
return True
|
|
89
96
|
return False
|
|
90
97
|
|
|
@@ -105,9 +112,10 @@ class IgnoreGroup(Ignore):
|
|
|
105
112
|
|
|
106
113
|
def list_ignored(self) -> List[str]:
|
|
107
114
|
ignored = []
|
|
108
|
-
for dir, _, files in self.root
|
|
115
|
+
for dir, _, files in os.walk(self.root):
|
|
116
|
+
dir_path = Path(dir)
|
|
109
117
|
for file in files:
|
|
110
|
-
abs_path =
|
|
118
|
+
abs_path = dir_path / file
|
|
111
119
|
if self.is_ignored(abs_path):
|
|
112
120
|
ignored.append(str(abs_path.relative_to(self.root)))
|
|
113
121
|
return ignored
|
flyte/_code_bundle/_packaging.py
CHANGED
|
@@ -14,10 +14,9 @@ import typing
|
|
|
14
14
|
from typing import List, Optional, Tuple, Union
|
|
15
15
|
|
|
16
16
|
import click
|
|
17
|
-
from rich import print as rich_print
|
|
18
17
|
from rich.tree import Tree
|
|
19
18
|
|
|
20
|
-
from flyte._logging import logger
|
|
19
|
+
from flyte._logging import _get_console, logger
|
|
21
20
|
|
|
22
21
|
from ._ignore import Ignore, IgnoreGroup
|
|
23
22
|
from ._utils import CopyFiles, _filehash_update, _pathhash_update, ls_files, tar_strip_file_attributes
|
|
@@ -27,10 +26,10 @@ FAST_FILEENDING = ".tar.gz"
|
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
def print_ls_tree(source: os.PathLike, ls: typing.List[str]):
|
|
30
|
-
|
|
29
|
+
logger.info("Files to be copied for fast registration...")
|
|
31
30
|
|
|
32
31
|
tree_root = Tree(
|
|
33
|
-
f":open_file_folder:
|
|
32
|
+
f"File structure:\n:open_file_folder: {source}",
|
|
34
33
|
guide_style="bold bright_blue",
|
|
35
34
|
)
|
|
36
35
|
trees = {pathlib.Path(source): tree_root}
|
|
@@ -49,7 +48,12 @@ def print_ls_tree(source: os.PathLike, ls: typing.List[str]):
|
|
|
49
48
|
else:
|
|
50
49
|
current = trees[current_path]
|
|
51
50
|
trees[fpp.parent].add(f"{fpp.name}", guide_style="bold bright_blue")
|
|
52
|
-
|
|
51
|
+
|
|
52
|
+
console = _get_console()
|
|
53
|
+
with console.capture() as capture:
|
|
54
|
+
console.print(tree_root, overflow="ignore", no_wrap=True, crop=False)
|
|
55
|
+
logger.info(f"Root directory: [link=file://{source}]{source}[/link]")
|
|
56
|
+
logger.info(capture.get(), extra={"console": console})
|
|
53
57
|
|
|
54
58
|
|
|
55
59
|
def _compress_tarball(source: pathlib.Path, output: pathlib.Path) -> None:
|
flyte/_code_bundle/_utils.py
CHANGED
|
@@ -156,7 +156,7 @@ def list_all_files(source_path: pathlib.Path, deref_symlinks, ignore_group: Opti
|
|
|
156
156
|
|
|
157
157
|
# This is needed to prevent infinite recursion when walking with followlinks
|
|
158
158
|
visited_inodes = set()
|
|
159
|
-
for root, dirnames, files in
|
|
159
|
+
for root, dirnames, files in os.walk(source_path, topdown=True, followlinks=deref_symlinks):
|
|
160
160
|
dirnames[:] = [d for d in dirnames if d not in EXCLUDE_DIRS]
|
|
161
161
|
if deref_symlinks:
|
|
162
162
|
inode = os.stat(root).st_ino
|
|
@@ -167,7 +167,7 @@ def list_all_files(source_path: pathlib.Path, deref_symlinks, ignore_group: Opti
|
|
|
167
167
|
ff = []
|
|
168
168
|
files.sort()
|
|
169
169
|
for fname in files:
|
|
170
|
-
abspath = (root / fname).absolute()
|
|
170
|
+
abspath = (pathlib.Path(root) / fname).absolute()
|
|
171
171
|
# Only consider files that exist (e.g. disregard symlinks that point to non-existent files)
|
|
172
172
|
if not os.path.exists(abspath):
|
|
173
173
|
logger.info(f"Skipping non-existent file {abspath}")
|
flyte/_initialize.py
CHANGED
|
@@ -110,6 +110,12 @@ async def _initialize_client(
|
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
|
|
113
|
+
def _initialize_logger(log_level: int | None = None):
|
|
114
|
+
initialize_logger(enable_rich=True)
|
|
115
|
+
if log_level:
|
|
116
|
+
initialize_logger(log_level=log_level, enable_rich=True)
|
|
117
|
+
|
|
118
|
+
|
|
113
119
|
@syncify
|
|
114
120
|
async def init(
|
|
115
121
|
org: str | None = None,
|
|
@@ -172,14 +178,9 @@ async def init(
|
|
|
172
178
|
|
|
173
179
|
:return: None
|
|
174
180
|
"""
|
|
175
|
-
from flyte._tools import ipython_check
|
|
176
181
|
from flyte._utils import get_cwd_editable_install, org_from_endpoint, sanitize_endpoint
|
|
177
182
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
initialize_logger(enable_rich=interactive_mode)
|
|
181
|
-
if log_level:
|
|
182
|
-
initialize_logger(log_level=log_level, enable_rich=interactive_mode)
|
|
183
|
+
_initialize_logger(log_level=log_level)
|
|
183
184
|
|
|
184
185
|
global _init_config # noqa: PLW0603
|
|
185
186
|
|
|
@@ -231,6 +232,7 @@ async def init_from_config(
|
|
|
231
232
|
path_or_config: str | Path | Config | None = None,
|
|
232
233
|
root_dir: Path | None = None,
|
|
233
234
|
log_level: int | None = None,
|
|
235
|
+
storage: Storage | None = None,
|
|
234
236
|
) -> None:
|
|
235
237
|
"""
|
|
236
238
|
Initialize the Flyte system using a configuration file or Config object. This method should be called before any
|
|
@@ -245,6 +247,8 @@ async def init_from_config(
|
|
|
245
247
|
default is set using the default initialization policies
|
|
246
248
|
:return: None
|
|
247
249
|
"""
|
|
250
|
+
from rich.highlighter import ReprHighlighter
|
|
251
|
+
|
|
248
252
|
import flyte.config as config
|
|
249
253
|
|
|
250
254
|
cfg: config.Config
|
|
@@ -266,7 +270,9 @@ async def init_from_config(
|
|
|
266
270
|
else:
|
|
267
271
|
cfg = path_or_config
|
|
268
272
|
|
|
269
|
-
|
|
273
|
+
_initialize_logger(log_level=log_level)
|
|
274
|
+
|
|
275
|
+
logger.info(f"Flyte config initialized as {cfg}", extra={"highlighter": ReprHighlighter()})
|
|
270
276
|
await init.aio(
|
|
271
277
|
org=cfg.task.org,
|
|
272
278
|
project=cfg.task.project,
|
|
@@ -283,6 +289,7 @@ async def init_from_config(
|
|
|
283
289
|
root_dir=root_dir,
|
|
284
290
|
log_level=log_level,
|
|
285
291
|
image_builder=cfg.image.builder,
|
|
292
|
+
storage=storage,
|
|
286
293
|
)
|
|
287
294
|
|
|
288
295
|
|
flyte/_interface.py
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import inspect
|
|
4
|
-
|
|
4
|
+
import typing
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Dict, Generator, Literal, Tuple, Type, TypeVar, Union, cast, get_args, get_origin, get_type_hints
|
|
7
|
+
|
|
8
|
+
from flyte._logging import logger
|
|
5
9
|
|
|
6
10
|
|
|
7
11
|
def default_output_name(index: int = 0) -> str:
|
|
@@ -69,7 +73,15 @@ def extract_return_annotation(return_annotation: Union[Type, Tuple, None]) -> Di
|
|
|
69
73
|
if len(return_annotation.__args__) == 1: # type: ignore
|
|
70
74
|
raise TypeError("Tuples should be used to indicate multiple return values, found only one return variable.")
|
|
71
75
|
ra = get_args(return_annotation)
|
|
72
|
-
|
|
76
|
+
annotations = {}
|
|
77
|
+
for i, r in enumerate(ra):
|
|
78
|
+
if r is Ellipsis:
|
|
79
|
+
raise TypeError("Variable length tuples are not supported as return types.")
|
|
80
|
+
if get_origin(r) is Literal:
|
|
81
|
+
annotations[default_output_name(i)] = literal_to_enum(cast(Type, r))
|
|
82
|
+
else:
|
|
83
|
+
annotations[default_output_name(i)] = r
|
|
84
|
+
return annotations
|
|
73
85
|
|
|
74
86
|
elif isinstance(return_annotation, tuple):
|
|
75
87
|
if len(return_annotation) == 1:
|
|
@@ -79,4 +91,25 @@ def extract_return_annotation(return_annotation: Union[Type, Tuple, None]) -> Di
|
|
|
79
91
|
else:
|
|
80
92
|
# Handle all other single return types
|
|
81
93
|
# Task returns unnamed native tuple
|
|
94
|
+
if get_origin(return_annotation) is Literal:
|
|
95
|
+
return {default_output_name(): literal_to_enum(cast(Type, return_annotation))}
|
|
82
96
|
return {default_output_name(): cast(Type, return_annotation)}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def literal_to_enum(literal_type: Type) -> Type[Enum | typing.Any]:
|
|
100
|
+
"""Convert a Literal[...] into Union[str, Enum]."""
|
|
101
|
+
|
|
102
|
+
if get_origin(literal_type) is not Literal:
|
|
103
|
+
raise TypeError(f"{literal_type} is not a Literal")
|
|
104
|
+
|
|
105
|
+
values = get_args(literal_type)
|
|
106
|
+
if not all(isinstance(v, str) for v in values):
|
|
107
|
+
logger.warning(f"Literal type {literal_type} contains non-string values, using Any instead of Enum")
|
|
108
|
+
return typing.Any
|
|
109
|
+
# Deduplicate & keep order
|
|
110
|
+
enum_dict = {str(v).upper(): v for v in values}
|
|
111
|
+
|
|
112
|
+
# Dynamically create an Enum
|
|
113
|
+
literal_enum = Enum("LiteralEnum", enum_dict) # type: ignore
|
|
114
|
+
|
|
115
|
+
return literal_enum # type: ignore
|
|
@@ -6,7 +6,7 @@ import tempfile
|
|
|
6
6
|
import typing
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from string import Template
|
|
9
|
-
from typing import ClassVar, Optional, Protocol, cast
|
|
9
|
+
from typing import ClassVar, List, Optional, Protocol, cast
|
|
10
10
|
|
|
11
11
|
import aiofiles
|
|
12
12
|
import click
|
|
@@ -263,7 +263,37 @@ class DockerIgnoreHandler:
|
|
|
263
263
|
|
|
264
264
|
class CopyConfigHandler:
|
|
265
265
|
@staticmethod
|
|
266
|
-
|
|
266
|
+
def list_dockerignore(root_path: Optional[Path], docker_ignore_file_path: Optional[Path]) -> List[str]:
|
|
267
|
+
patterns: List[str] = []
|
|
268
|
+
dockerignore_path: Optional[Path] = None
|
|
269
|
+
if root_path:
|
|
270
|
+
dockerignore_path = root_path / ".dockerignore"
|
|
271
|
+
# DockerIgnore layer should be first priority
|
|
272
|
+
if docker_ignore_file_path:
|
|
273
|
+
dockerignore_path = docker_ignore_file_path
|
|
274
|
+
|
|
275
|
+
# Return empty list if no .dockerignore file found
|
|
276
|
+
if not dockerignore_path or not dockerignore_path.exists() or not dockerignore_path.is_file():
|
|
277
|
+
logger.info(f".dockerignore file not found at path: {dockerignore_path}")
|
|
278
|
+
return patterns
|
|
279
|
+
|
|
280
|
+
try:
|
|
281
|
+
with open(dockerignore_path, "r", encoding="utf-8") as f:
|
|
282
|
+
for line in f:
|
|
283
|
+
stripped_line = line.strip()
|
|
284
|
+
# Skip empty lines, whitespace-only lines, and comments
|
|
285
|
+
if not stripped_line or stripped_line.startswith("#"):
|
|
286
|
+
continue
|
|
287
|
+
patterns.append(stripped_line)
|
|
288
|
+
except Exception as e:
|
|
289
|
+
logger.error(f"Failed to read .dockerignore file at {dockerignore_path}: {e}")
|
|
290
|
+
return []
|
|
291
|
+
return patterns
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
async def handle(
|
|
295
|
+
layer: CopyConfig, context_path: Path, dockerfile: str, docker_ignore_file_path: Optional[Path]
|
|
296
|
+
) -> str:
|
|
267
297
|
# Copy the source config file or directory to the context path
|
|
268
298
|
if layer.src.is_absolute() or ".." in str(layer.src):
|
|
269
299
|
dst_path = context_path / str(layer.src.absolute()).replace("/", "./_flyte_abs_context/", 1)
|
|
@@ -272,18 +302,26 @@ class CopyConfigHandler:
|
|
|
272
302
|
|
|
273
303
|
dst_path.parent.mkdir(parents=True, exist_ok=True)
|
|
274
304
|
abs_path = layer.src.absolute()
|
|
305
|
+
|
|
275
306
|
if layer.src.is_file():
|
|
276
307
|
# Copy the file
|
|
277
308
|
shutil.copy(abs_path, dst_path)
|
|
278
309
|
elif layer.src.is_dir():
|
|
279
310
|
# Copy the entire directory
|
|
280
|
-
|
|
311
|
+
from flyte._initialize import _get_init_config
|
|
312
|
+
|
|
313
|
+
init_config = _get_init_config()
|
|
314
|
+
root_path = init_config.root_dir if init_config else None
|
|
315
|
+
docker_ignore_patterns = CopyConfigHandler.list_dockerignore(root_path, docker_ignore_file_path)
|
|
316
|
+
shutil.copytree(
|
|
317
|
+
abs_path, dst_path, dirs_exist_ok=True, ignore=shutil.ignore_patterns(*docker_ignore_patterns)
|
|
318
|
+
)
|
|
281
319
|
else:
|
|
282
|
-
|
|
320
|
+
logger.error(f"Source path not exists: {layer.src}")
|
|
321
|
+
return dockerfile
|
|
283
322
|
|
|
284
323
|
# Add a copy command to the dockerfile
|
|
285
324
|
dockerfile += f"\nCOPY {dst_path.relative_to(context_path)} {layer.dst}\n"
|
|
286
|
-
|
|
287
325
|
return dockerfile
|
|
288
326
|
|
|
289
327
|
|
|
@@ -349,7 +387,9 @@ def _get_secret_mounts_layer(secrets: typing.Tuple[str | Secret, ...] | None) ->
|
|
|
349
387
|
return secret_mounts_layer
|
|
350
388
|
|
|
351
389
|
|
|
352
|
-
async def _process_layer(
|
|
390
|
+
async def _process_layer(
|
|
391
|
+
layer: Layer, context_path: Path, dockerfile: str, docker_ignore_file_path: Optional[Path]
|
|
392
|
+
) -> str:
|
|
353
393
|
match layer:
|
|
354
394
|
case PythonWheels():
|
|
355
395
|
# Handle Python wheels
|
|
@@ -385,7 +425,7 @@ async def _process_layer(layer: Layer, context_path: Path, dockerfile: str) -> s
|
|
|
385
425
|
|
|
386
426
|
case CopyConfig():
|
|
387
427
|
# Handle local files and folders
|
|
388
|
-
dockerfile = await CopyConfigHandler.handle(layer, context_path, dockerfile)
|
|
428
|
+
dockerfile = await CopyConfigHandler.handle(layer, context_path, dockerfile, docker_ignore_file_path)
|
|
389
429
|
|
|
390
430
|
case Commands():
|
|
391
431
|
# Handle commands
|
|
@@ -512,6 +552,15 @@ class DockerImageBuilder(ImageBuilder):
|
|
|
512
552
|
else:
|
|
513
553
|
logger.info("Buildx builder already exists.")
|
|
514
554
|
|
|
555
|
+
def get_docker_ignore(self, image: Image) -> Optional[Path]:
|
|
556
|
+
"""Get the .dockerignore file path from the image layers."""
|
|
557
|
+
# Look for DockerIgnore layer in the image layers
|
|
558
|
+
for layer in image._layers:
|
|
559
|
+
if isinstance(layer, DockerIgnore) and layer.path.strip():
|
|
560
|
+
return Path(layer.path)
|
|
561
|
+
|
|
562
|
+
return None
|
|
563
|
+
|
|
515
564
|
async def _build_image(self, image: Image, *, push: bool = True, dry_run: bool = False) -> str:
|
|
516
565
|
"""
|
|
517
566
|
if default image (only base image and locked), raise an error, don't have a dockerfile
|
|
@@ -541,8 +590,9 @@ class DockerImageBuilder(ImageBuilder):
|
|
|
541
590
|
PYTHON_VERSION=f"{image.python_version[0]}.{image.python_version[1]}",
|
|
542
591
|
)
|
|
543
592
|
|
|
593
|
+
docker_ignore_file_path = self.get_docker_ignore(image)
|
|
544
594
|
for layer in image._layers:
|
|
545
|
-
dockerfile = await _process_layer(layer, tmp_path, dockerfile)
|
|
595
|
+
dockerfile = await _process_layer(layer, tmp_path, dockerfile, docker_ignore_file_path)
|
|
546
596
|
|
|
547
597
|
dockerfile += DOCKER_FILE_BASE_FOOTER.substitute(F_IMG_ID=image.uri)
|
|
548
598
|
|
|
@@ -10,7 +10,6 @@ from typing import TYPE_CHECKING, Optional, Tuple, cast
|
|
|
10
10
|
from uuid import uuid4
|
|
11
11
|
|
|
12
12
|
import aiofiles
|
|
13
|
-
import click
|
|
14
13
|
|
|
15
14
|
import flyte
|
|
16
15
|
import flyte.errors
|
|
@@ -42,7 +41,6 @@ if TYPE_CHECKING:
|
|
|
42
41
|
from flyte._protos.imagebuilder import definition_pb2 as image_definition_pb2
|
|
43
42
|
|
|
44
43
|
IMAGE_TASK_NAME = "build-image"
|
|
45
|
-
OPTIMIZE_TASK_NAME = "optimize-task"
|
|
46
44
|
IMAGE_TASK_PROJECT = "system"
|
|
47
45
|
IMAGE_TASK_DOMAIN = "production"
|
|
48
46
|
|
|
@@ -85,10 +83,10 @@ class RemoteImageChecker(ImageChecker):
|
|
|
85
83
|
raise ValueError("remote client should not be None")
|
|
86
84
|
cls._images_client = image_service_pb2_grpc.ImageServiceStub(cfg.client._channel)
|
|
87
85
|
resp = await cls._images_client.GetImage(req)
|
|
88
|
-
logger.warning(
|
|
86
|
+
logger.warning(f"[blue]Image {resp.image.fqin} found. Skip building.[/blue]")
|
|
89
87
|
return resp.image.fqin
|
|
90
88
|
except Exception:
|
|
91
|
-
logger.warning(
|
|
89
|
+
logger.warning(f"[blue]Image {image_name} was not found or has expired.[/blue]", extra={"highlight": False})
|
|
92
90
|
return None
|
|
93
91
|
|
|
94
92
|
|
|
@@ -110,37 +108,25 @@ class RemoteImageBuilder(ImageBuilder):
|
|
|
110
108
|
domain=IMAGE_TASK_DOMAIN,
|
|
111
109
|
auto_version="latest",
|
|
112
110
|
).override.aio(secrets=_get_build_secrets_from_image(image))
|
|
111
|
+
|
|
112
|
+
logger.warning("[bold blue]🐳 Submitting a new build...[/bold blue]")
|
|
113
113
|
run = cast(
|
|
114
114
|
Run,
|
|
115
115
|
await flyte.with_runcontext(project=IMAGE_TASK_PROJECT, domain=IMAGE_TASK_DOMAIN).run.aio(
|
|
116
116
|
entity, spec=spec, context=context, target_image=image_name
|
|
117
117
|
),
|
|
118
118
|
)
|
|
119
|
-
logger.warning(
|
|
119
|
+
logger.warning(f"⏳ Waiting for build to finish at: [bold cyan link={run.url}]{run.url}[/bold cyan link]")
|
|
120
120
|
|
|
121
|
-
logger.warning(click.style("⏳ Waiting for build to finish at: " + click.style(run.url, fg="cyan"), bold=True))
|
|
122
121
|
await run.wait.aio(quiet=True)
|
|
123
122
|
run_details = await run.details.aio()
|
|
124
123
|
|
|
125
124
|
elapsed = str(datetime.now(timezone.utc) - start).split(".")[0]
|
|
126
125
|
|
|
127
126
|
if run_details.action_details.raw_phase == run_definition_pb2.PHASE_SUCCEEDED:
|
|
128
|
-
logger.warning(
|
|
129
|
-
try:
|
|
130
|
-
entity = remote.Task.get(
|
|
131
|
-
name=OPTIMIZE_TASK_NAME,
|
|
132
|
-
project=IMAGE_TASK_PROJECT,
|
|
133
|
-
domain=IMAGE_TASK_DOMAIN,
|
|
134
|
-
auto_version="latest",
|
|
135
|
-
)
|
|
136
|
-
await flyte.with_runcontext(project=IMAGE_TASK_PROJECT, domain=IMAGE_TASK_DOMAIN).run.aio(
|
|
137
|
-
entity, target_image=image_name
|
|
138
|
-
)
|
|
139
|
-
except Exception as e:
|
|
140
|
-
# Ignore the error if optimize is not enabled in the backend.
|
|
141
|
-
logger.warning(f"Failed to run optimize task with error: {e}")
|
|
127
|
+
logger.warning(f"[bold green]✅ Build completed in {elapsed}![/bold green]")
|
|
142
128
|
else:
|
|
143
|
-
raise flyte.errors.ImageBuildError(f"❌ Build failed in {elapsed} at {
|
|
129
|
+
raise flyte.errors.ImageBuildError(f"❌ Build failed in {elapsed} at [cyan]{run.url}[/cyan]")
|
|
144
130
|
|
|
145
131
|
outputs = await run_details.outputs()
|
|
146
132
|
return _get_fully_qualified_image_name(outputs)
|
|
@@ -183,11 +169,8 @@ async def _validate_configuration(image: Image) -> Tuple[str, Optional[str]]:
|
|
|
183
169
|
context_size = tar_path.stat().st_size
|
|
184
170
|
if context_size > 5 * 1024 * 1024:
|
|
185
171
|
logger.warning(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
"Upload and build speed will be impacted.",
|
|
189
|
-
fg="yellow",
|
|
190
|
-
)
|
|
172
|
+
f"[yellow]Context size is {context_size / (1024 * 1024):.2f} MB, which is larger than 5 MB. "
|
|
173
|
+
"Upload and build speed will be impacted.[/yellow]",
|
|
191
174
|
)
|
|
192
175
|
_, context_url = await remote.upload_file.aio(context_dst)
|
|
193
176
|
else:
|
|
File without changes
|
flyte/_keyring/file.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from base64 import decodebytes, encodebytes
|
|
2
|
+
from configparser import ConfigParser, NoOptionError, NoSectionError
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from keyring.backend import KeyringBackend
|
|
7
|
+
from keyring.errors import PasswordDeleteError
|
|
8
|
+
|
|
9
|
+
_FLYTE_KEYRING_PATH: Path = Path.home() / ".flyte" / "keyring.cfg"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SimplePlainTextKeyring(KeyringBackend):
|
|
13
|
+
"""Simple plain text keyring"""
|
|
14
|
+
|
|
15
|
+
priority = 0.5
|
|
16
|
+
|
|
17
|
+
def get_password(self, service: str, username: str) -> Optional[str]:
|
|
18
|
+
"""Get password."""
|
|
19
|
+
if not self.file_path.exists():
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
config = ConfigParser(interpolation=None)
|
|
23
|
+
config.read(self.file_path, encoding="utf-8")
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
password_base64 = config.get(service, username).encode("utf-8")
|
|
27
|
+
return decodebytes(password_base64).decode("utf-8")
|
|
28
|
+
except (NoOptionError, NoSectionError):
|
|
29
|
+
return None
|
|
30
|
+
|
|
31
|
+
def delete_password(self, service: str, username: str) -> None:
|
|
32
|
+
"""Delete password."""
|
|
33
|
+
if not self.file_path.exists():
|
|
34
|
+
raise PasswordDeleteError("Config file does not exist")
|
|
35
|
+
|
|
36
|
+
config = ConfigParser(interpolation=None)
|
|
37
|
+
config.read(self.file_path, encoding="utf-8")
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
if not config.remove_option(service, username):
|
|
41
|
+
raise PasswordDeleteError("Password not found")
|
|
42
|
+
except NoSectionError:
|
|
43
|
+
raise PasswordDeleteError("Password not found")
|
|
44
|
+
|
|
45
|
+
with self.file_path.open("w", encoding="utf-8") as config_file:
|
|
46
|
+
config.write(config_file)
|
|
47
|
+
|
|
48
|
+
def set_password(self, service: str, username: str, password: str) -> None:
|
|
49
|
+
"""Set password."""
|
|
50
|
+
if not username:
|
|
51
|
+
raise ValueError("Username must be provided")
|
|
52
|
+
|
|
53
|
+
file_path = self._ensure_file_path()
|
|
54
|
+
value = encodebytes(password.encode("utf-8")).decode("utf-8")
|
|
55
|
+
|
|
56
|
+
config = ConfigParser(interpolation=None)
|
|
57
|
+
config.read(file_path, encoding="utf-8")
|
|
58
|
+
|
|
59
|
+
if not config.has_section(service):
|
|
60
|
+
config.add_section(service)
|
|
61
|
+
|
|
62
|
+
config.set(service, username, value)
|
|
63
|
+
|
|
64
|
+
with file_path.open("w", encoding="utf-8") as config_file:
|
|
65
|
+
config.write(config_file)
|
|
66
|
+
|
|
67
|
+
def _ensure_file_path(self):
|
|
68
|
+
self.file_path.parent.mkdir(exist_ok=True, parents=True)
|
|
69
|
+
if not self.file_path.is_file():
|
|
70
|
+
self.file_path.touch(0o600)
|
|
71
|
+
return self.file_path
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def file_path(self) -> Path:
|
|
75
|
+
from flyte.config._reader import resolve_config_path
|
|
76
|
+
|
|
77
|
+
config_path = resolve_config_path()
|
|
78
|
+
if config_path and str(config_path.parent) == ".flyte":
|
|
79
|
+
# if the config is in a .flyte directory, use that as the path
|
|
80
|
+
return config_path.parent / "keyring.cfg"
|
|
81
|
+
# otherwise use the default path
|
|
82
|
+
return _FLYTE_KEYRING_PATH
|
|
83
|
+
|
|
84
|
+
def __repr__(self):
|
|
85
|
+
return f"<{self.__class__.__name__}> at {self.file_path}>"
|
flyte/_logging.py
CHANGED
|
@@ -40,6 +40,21 @@ def log_format_from_env() -> str:
|
|
|
40
40
|
return os.environ.get("LOG_FORMAT", "json")
|
|
41
41
|
|
|
42
42
|
|
|
43
|
+
def _get_console():
|
|
44
|
+
"""
|
|
45
|
+
Get the console.
|
|
46
|
+
"""
|
|
47
|
+
from rich.console import Console
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
width = os.get_terminal_size().columns
|
|
51
|
+
except Exception as e:
|
|
52
|
+
logger.debug(f"Failed to get terminal size: {e}")
|
|
53
|
+
width = 160
|
|
54
|
+
|
|
55
|
+
return Console(width=width)
|
|
56
|
+
|
|
57
|
+
|
|
43
58
|
def get_rich_handler(log_level: int) -> Optional[logging.Handler]:
|
|
44
59
|
"""
|
|
45
60
|
Upgrades the global loggers to use Rich logging.
|
|
@@ -51,23 +66,19 @@ def get_rich_handler(log_level: int) -> Optional[logging.Handler]:
|
|
|
51
66
|
return None
|
|
52
67
|
|
|
53
68
|
import click
|
|
54
|
-
from rich.
|
|
69
|
+
from rich.highlighter import NullHighlighter
|
|
55
70
|
from rich.logging import RichHandler
|
|
56
71
|
|
|
57
|
-
try:
|
|
58
|
-
width = os.get_terminal_size().columns
|
|
59
|
-
except Exception as e:
|
|
60
|
-
logger.debug(f"Failed to get terminal size: {e}")
|
|
61
|
-
width = 160
|
|
62
|
-
|
|
63
72
|
handler = RichHandler(
|
|
64
73
|
tracebacks_suppress=[click],
|
|
65
74
|
rich_tracebacks=True,
|
|
66
75
|
omit_repeated_times=False,
|
|
67
76
|
show_path=False,
|
|
68
77
|
log_time_format="%H:%M:%S.%f",
|
|
69
|
-
console=
|
|
78
|
+
console=_get_console(),
|
|
70
79
|
level=log_level,
|
|
80
|
+
highlighter=NullHighlighter(),
|
|
81
|
+
markup=True,
|
|
71
82
|
)
|
|
72
83
|
|
|
73
84
|
formatter = logging.Formatter(fmt="%(filename)s:%(lineno)d - %(message)s")
|
flyte/_utils/coro_management.py
CHANGED
|
@@ -11,7 +11,8 @@ async def run_coros(*coros: typing.Coroutine, return_when: str = asyncio.FIRST_C
|
|
|
11
11
|
:param return_when:
|
|
12
12
|
:return:
|
|
13
13
|
"""
|
|
14
|
-
tasks: typing.List[asyncio.Task[typing.Never]] = [asyncio.create_task(c) for c in coros]
|
|
14
|
+
# tasks: typing.List[asyncio.Task[typing.Never]] = [asyncio.create_task(c) for c in coros] # Python 3.11+
|
|
15
|
+
tasks: typing.List[asyncio.Task] = [asyncio.create_task(c) for c in coros]
|
|
15
16
|
done, pending = await asyncio.wait(tasks, return_when=return_when)
|
|
16
17
|
# TODO we might want to handle asyncio.CancelledError here, for cases when the `action` is cancelled
|
|
17
18
|
# and we want to propagate it to all tasks. Though the backend will handle it anyway,
|
flyte/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '2.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 0, 0, '
|
|
31
|
+
__version__ = version = '2.0.0b21'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 0, 0, 'b21')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g7f82f6ddd'
|
flyte/config/_config.py
CHANGED
|
@@ -231,10 +231,12 @@ def auto(config_file: typing.Union[str, pathlib.Path, ConfigFile, None] = None)
|
|
|
231
231
|
1. If specified, read the config from the provided file path.
|
|
232
232
|
2. If not specified, the config file is searched in the default locations.
|
|
233
233
|
a. ./config.yaml if it exists (current working directory)
|
|
234
|
-
b.
|
|
235
|
-
c.
|
|
236
|
-
d.
|
|
237
|
-
e.
|
|
234
|
+
b. ./.flyte/config.yaml if it exists (current working directory)
|
|
235
|
+
c. <git_root>/.flyte/config.yaml if it exists
|
|
236
|
+
d. `UCTL_CONFIG` environment variable
|
|
237
|
+
e. `FLYTECTL_CONFIG` environment variable
|
|
238
|
+
f. ~/.union/config.yaml if it exists
|
|
239
|
+
g. ~/.flyte/config.yaml if it exists
|
|
238
240
|
3. If any value is not found in the config file, the default value is used.
|
|
239
241
|
4. For any value there are environment variables that match the config variable names, those will override
|
|
240
242
|
|
flyte/config/_reader.py
CHANGED
|
@@ -135,15 +135,25 @@ class ConfigFile(object):
|
|
|
135
135
|
return self._yaml_config
|
|
136
136
|
|
|
137
137
|
|
|
138
|
+
def _config_path_from_git_root() -> pathlib.Path | None:
|
|
139
|
+
from flyte.git import config_from_root
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
return config_from_root().source
|
|
143
|
+
except RuntimeError:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
|
|
138
147
|
def resolve_config_path() -> pathlib.Path | None:
|
|
139
148
|
"""
|
|
140
149
|
Config is read from the following locations in order of precedence:
|
|
141
150
|
1. ./config.yaml if it exists
|
|
142
151
|
2. ./.flyte/config.yaml if it exists
|
|
143
|
-
3.
|
|
144
|
-
4. `
|
|
145
|
-
5.
|
|
146
|
-
6. ~/.
|
|
152
|
+
3. <git_root>/.flyte/config.yaml if it exists
|
|
153
|
+
4. `UCTL_CONFIG` environment variable
|
|
154
|
+
5. `FLYTECTL_CONFIG` environment variable
|
|
155
|
+
6. ~/.union/config.yaml if it exists
|
|
156
|
+
7. ~/.flyte/config.yaml if it exists
|
|
147
157
|
"""
|
|
148
158
|
current_location_config = Path("config.yaml")
|
|
149
159
|
if current_location_config.exists():
|
|
@@ -155,6 +165,11 @@ def resolve_config_path() -> pathlib.Path | None:
|
|
|
155
165
|
return dot_flyte_config
|
|
156
166
|
logger.debug("No ./.flyte/config.yaml found")
|
|
157
167
|
|
|
168
|
+
git_root_config = _config_path_from_git_root()
|
|
169
|
+
if git_root_config:
|
|
170
|
+
return git_root_config
|
|
171
|
+
logger.debug("No .flyte/config.yaml found in git repo root")
|
|
172
|
+
|
|
158
173
|
uctl_path_from_env = getenv(UCTL_CONFIG_ENV_VAR, None)
|
|
159
174
|
if uctl_path_from_env:
|
|
160
175
|
return pathlib.Path(uctl_path_from_env)
|
flyte/git/_config.py
CHANGED
|
@@ -14,4 +14,6 @@ def config_from_root(path: pathlib.Path | str = ".flyte/config.yaml") -> flyte.c
|
|
|
14
14
|
if result.returncode != 0:
|
|
15
15
|
raise RuntimeError(f"Failed to get git root directory: {result.stderr}")
|
|
16
16
|
root = pathlib.Path(result.stdout.strip())
|
|
17
|
+
if not (root / path).exists():
|
|
18
|
+
raise RuntimeError(f"Config file {root / path} does not exist")
|
|
17
19
|
return flyte.config.auto(root / path)
|
flyte/io/_dataframe/dataframe.py
CHANGED
|
@@ -904,7 +904,8 @@ class DataFrameTransformerEngine(TypeTransformer[DataFrame]):
|
|
|
904
904
|
# t1(input_a: DataFrame) # or
|
|
905
905
|
# t1(input_a: Annotated[DataFrame, my_cols])
|
|
906
906
|
if issubclass(expected_python_type, DataFrame):
|
|
907
|
-
fdf = DataFrame(format=metad.structured_dataset_type.format)
|
|
907
|
+
fdf = DataFrame(format=metad.structured_dataset_type.format, uri=lv.scalar.structured_dataset.uri)
|
|
908
|
+
fdf._already_uploaded = True
|
|
908
909
|
fdf._literal_sd = lv.scalar.structured_dataset
|
|
909
910
|
fdf._metadata = metad
|
|
910
911
|
return fdf
|
|
@@ -1012,7 +1013,7 @@ class DataFrameTransformerEngine(TypeTransformer[DataFrame]):
|
|
|
1012
1013
|
def guess_python_type(self, literal_type: types_pb2.LiteralType) -> Type[DataFrame]:
|
|
1013
1014
|
# todo: technically we should return the dataframe type specified in the constructor, but to do that,
|
|
1014
1015
|
# we'd have to store that, which we don't do today. See possibly #1363
|
|
1015
|
-
if literal_type.HasField("
|
|
1016
|
+
if literal_type.HasField("structured_dataset_type"):
|
|
1016
1017
|
return DataFrame
|
|
1017
1018
|
raise ValueError(f"DataFrameTransformerEngine cannot reverse {literal_type}")
|
|
1018
1019
|
|
flyte/io/_dir.py
CHANGED
|
@@ -27,21 +27,21 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
27
27
|
The generic type T represents the format of the files in the directory.
|
|
28
28
|
|
|
29
29
|
Example:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
```python
|
|
31
|
+
# Async usage
|
|
32
|
+
from pandas import DataFrame
|
|
33
|
+
data_dir = Dir[DataFrame](path="s3://my-bucket/data/")
|
|
34
|
+
|
|
35
|
+
# Walk through files
|
|
36
|
+
async for file in data_dir.walk():
|
|
37
|
+
async with file.open() as f:
|
|
38
|
+
content = await f.read()
|
|
39
|
+
|
|
40
|
+
# Sync alternative
|
|
41
|
+
for file in data_dir.walk_sync():
|
|
42
|
+
with file.open_sync() as f:
|
|
43
|
+
content = f.read()
|
|
44
|
+
```
|
|
45
45
|
"""
|
|
46
46
|
|
|
47
47
|
# Represents either a local or remote path.
|
|
@@ -94,11 +94,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
94
94
|
File objects for each file found in the directory
|
|
95
95
|
|
|
96
96
|
Example:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
```python
|
|
98
|
+
async for file in directory.walk():
|
|
99
|
+
local_path = await file.download()
|
|
100
|
+
# Process the file
|
|
101
|
+
```
|
|
102
102
|
"""
|
|
103
103
|
fs = storage.get_underlying_filesystem(path=self.path)
|
|
104
104
|
if recursive is False:
|
|
@@ -134,11 +134,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
134
134
|
File objects for each file found in the directory
|
|
135
135
|
|
|
136
136
|
Example:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
```python
|
|
138
|
+
for file in directory.walk_sync():
|
|
139
|
+
local_path = file.download_sync()
|
|
140
|
+
# Process the file
|
|
141
|
+
```
|
|
142
142
|
"""
|
|
143
143
|
fs = storage.get_underlying_filesystem(path=self.path)
|
|
144
144
|
for parent, _, files in fs.walk(self.path, maxdepth=max_depth):
|
|
@@ -157,11 +157,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
157
157
|
A list of File objects
|
|
158
158
|
|
|
159
159
|
Example:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
160
|
+
```python
|
|
161
|
+
files = await directory.list_files()
|
|
162
|
+
for file in files:
|
|
163
|
+
# Process the file
|
|
164
|
+
```
|
|
165
165
|
"""
|
|
166
166
|
# todo: this should probably also just defer to fsspec.find()
|
|
167
167
|
files = []
|
|
@@ -177,11 +177,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
177
177
|
A list of File objects
|
|
178
178
|
|
|
179
179
|
Example:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
```python
|
|
181
|
+
files = directory.list_files_sync()
|
|
182
|
+
for file in files:
|
|
183
|
+
# Process the file
|
|
184
|
+
```
|
|
185
185
|
"""
|
|
186
186
|
return list(self.walk_sync(recursive=False))
|
|
187
187
|
|
|
@@ -197,9 +197,9 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
197
197
|
The path to the downloaded directory
|
|
198
198
|
|
|
199
199
|
Example:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
```python
|
|
201
|
+
local_dir = await directory.download('/tmp/my_data/')
|
|
202
|
+
```
|
|
203
203
|
"""
|
|
204
204
|
local_dest = str(local_path) if local_path else str(storage.get_random_local_path())
|
|
205
205
|
if not storage.is_remote(self.path):
|
|
@@ -230,9 +230,9 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
230
230
|
The path to the downloaded directory
|
|
231
231
|
|
|
232
232
|
Example:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
```python
|
|
234
|
+
local_dir = directory.download_sync('/tmp/my_data/')
|
|
235
|
+
```
|
|
236
236
|
"""
|
|
237
237
|
local_dest = str(local_path) if local_path else str(storage.get_random_local_path())
|
|
238
238
|
if not storage.is_remote(self.path):
|
|
@@ -268,11 +268,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
268
268
|
A new Dir instance pointing to the uploaded directory
|
|
269
269
|
|
|
270
270
|
Example:
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
271
|
+
```python
|
|
272
|
+
remote_dir = await Dir[DataFrame].from_local('/tmp/data_dir/', 's3://bucket/data/')
|
|
273
|
+
# With a known hash value you want to use for cache key calculation
|
|
274
|
+
remote_dir = await Dir[DataFrame].from_local('/tmp/data_dir/', 's3://bucket/data/', dir_cache_key='abc123')
|
|
275
|
+
```
|
|
276
276
|
"""
|
|
277
277
|
local_path_str = str(local_path)
|
|
278
278
|
dirname = os.path.basename(os.path.normpath(local_path_str))
|
|
@@ -291,11 +291,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
291
291
|
the cache key will be computed based on this object's attributes.
|
|
292
292
|
|
|
293
293
|
Example:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
294
|
+
```python
|
|
295
|
+
remote_dir = Dir.from_existing_remote("s3://bucket/data/")
|
|
296
|
+
# With a known hash
|
|
297
|
+
remote_dir = Dir.from_existing_remote("s3://bucket/data/", dir_cache_key="abc123")
|
|
298
|
+
```
|
|
299
299
|
"""
|
|
300
300
|
return cls(path=remote_path, hash=dir_cache_key)
|
|
301
301
|
|
|
@@ -312,9 +312,9 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
312
312
|
A new Dir instance pointing to the uploaded directory
|
|
313
313
|
|
|
314
314
|
Example:
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
315
|
+
```python
|
|
316
|
+
remote_dir = Dir[DataFrame].from_local_sync('/tmp/data_dir/', 's3://bucket/data/')
|
|
317
|
+
```
|
|
318
318
|
"""
|
|
319
319
|
# Implement this after we figure out the final sync story
|
|
320
320
|
raise NotImplementedError("Sync upload is not implemented for remote paths")
|
|
@@ -327,10 +327,10 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
327
327
|
True if the directory exists, False otherwise
|
|
328
328
|
|
|
329
329
|
Example:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
330
|
+
```python
|
|
331
|
+
if await directory.exists():
|
|
332
|
+
# Process the directory
|
|
333
|
+
```
|
|
334
334
|
"""
|
|
335
335
|
fs = storage.get_underlying_filesystem(path=self.path)
|
|
336
336
|
if isinstance(fs, AsyncFileSystem):
|
|
@@ -346,10 +346,10 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
346
346
|
True if the directory exists, False otherwise
|
|
347
347
|
|
|
348
348
|
Example:
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
349
|
+
```python
|
|
350
|
+
if directory.exists_sync():
|
|
351
|
+
# Process the directory
|
|
352
|
+
```
|
|
353
353
|
"""
|
|
354
354
|
fs = storage.get_underlying_filesystem(path=self.path)
|
|
355
355
|
return fs.exists(self.path)
|
|
@@ -365,11 +365,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
365
365
|
A File instance if the file exists, None otherwise
|
|
366
366
|
|
|
367
367
|
Example:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
368
|
+
```python
|
|
369
|
+
file = await directory.get_file("data.csv")
|
|
370
|
+
if file:
|
|
371
|
+
# Process the file
|
|
372
|
+
```
|
|
373
373
|
"""
|
|
374
374
|
fs = storage.get_underlying_filesystem(path=self.path)
|
|
375
375
|
file_path = fs.sep.join([self.path, file_name])
|
|
@@ -390,11 +390,11 @@ class Dir(BaseModel, Generic[T], SerializableType):
|
|
|
390
390
|
A File instance if the file exists, None otherwise
|
|
391
391
|
|
|
392
392
|
Example:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
```python
|
|
394
|
+
file = directory.get_file_sync("data.csv")
|
|
395
|
+
if file:
|
|
396
|
+
# Process the file
|
|
397
|
+
```
|
|
398
398
|
"""
|
|
399
399
|
file_path = os.path.join(self.path, file_name)
|
|
400
400
|
file = File[T](path=file_path)
|
flyte/models.py
CHANGED
|
@@ -3,13 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
import inspect
|
|
4
4
|
import os
|
|
5
5
|
import pathlib
|
|
6
|
+
import typing
|
|
6
7
|
from dataclasses import dataclass, field, replace
|
|
7
8
|
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, List, Literal, Optional, Tuple, Type
|
|
8
9
|
|
|
9
10
|
import rich.repr
|
|
10
11
|
|
|
11
12
|
from flyte._docstring import Docstring
|
|
12
|
-
from flyte._interface import extract_return_annotation
|
|
13
|
+
from flyte._interface import extract_return_annotation, literal_to_enum
|
|
13
14
|
from flyte._logging import logger
|
|
14
15
|
|
|
15
16
|
if TYPE_CHECKING:
|
|
@@ -329,7 +330,10 @@ class NativeInterface:
|
|
|
329
330
|
logger.warning(
|
|
330
331
|
f"Function {func.__name__} has parameter {name} without type annotation. Data will be pickled."
|
|
331
332
|
)
|
|
332
|
-
|
|
333
|
+
if typing.get_origin(param.annotation) is Literal:
|
|
334
|
+
param_info[name] = (literal_to_enum(param.annotation), param.default)
|
|
335
|
+
else:
|
|
336
|
+
param_info[name] = (param.annotation, param.default)
|
|
333
337
|
|
|
334
338
|
# Get return type
|
|
335
339
|
outputs = extract_return_annotation(sig.return_annotation)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
from rich import print as rich_print
|
|
2
2
|
|
|
3
3
|
from flyte._logging import logger
|
|
4
4
|
from flyte.remote._client.auth import _token_client as token_client
|
|
@@ -94,10 +94,9 @@ class DeviceCodeAuthenticator(Authenticator):
|
|
|
94
94
|
|
|
95
95
|
full_uri = f"{resp.verification_uri}?user_code={resp.user_code}"
|
|
96
96
|
text = (
|
|
97
|
-
f"To Authenticate, navigate in a browser to the following URL: "
|
|
98
|
-
f"{click.style(full_uri, fg='blue', underline=True)}"
|
|
97
|
+
f"To Authenticate, navigate in a browser to the following URL: [blue link={full_uri}]{full_uri}[/blue link]"
|
|
99
98
|
)
|
|
100
|
-
|
|
99
|
+
rich_print(text)
|
|
101
100
|
try:
|
|
102
101
|
token, refresh_token, expires_in = await token_client.poll_token_endpoint(
|
|
103
102
|
resp,
|
flyte/remote/_data.py
CHANGED
|
@@ -16,7 +16,6 @@ from flyteidl.service import dataproxy_pb2
|
|
|
16
16
|
from google.protobuf import duration_pb2
|
|
17
17
|
|
|
18
18
|
from flyte._initialize import CommonInit, ensure_client, get_client, get_common_config
|
|
19
|
-
from flyte._logging import make_hyperlink
|
|
20
19
|
from flyte.errors import InitializationError, RuntimeSystemError
|
|
21
20
|
from flyte.syncify import syncify
|
|
22
21
|
|
|
@@ -91,7 +90,7 @@ async def _upload_single_file(
|
|
|
91
90
|
raise RuntimeSystemError(e.code().value, f"Failed to get signed url for {fp}: {e.details()}")
|
|
92
91
|
except Exception as e:
|
|
93
92
|
raise RuntimeSystemError(type(e).__name__, f"Failed to get signed url for {fp}.") from e
|
|
94
|
-
logger.debug(f"Uploading to {
|
|
93
|
+
logger.debug(f"Uploading to [link={resp.signed_url}]signed url[/link] for [link=file://{fp}]{fp}[/link]")
|
|
95
94
|
extra_headers = get_extra_headers_for_protocol(resp.native_url)
|
|
96
95
|
extra_headers.update(resp.headers)
|
|
97
96
|
encoded_md5 = b64encode(md5_bytes)
|
|
@@ -101,7 +100,7 @@ async def _upload_single_file(
|
|
|
101
100
|
extra_headers.update({"Content-Length": str(content_length), "Content-MD5": encoded_md5.decode("utf-8")})
|
|
102
101
|
async with httpx.AsyncClient(verify=verify) as aclient:
|
|
103
102
|
put_resp = await aclient.put(resp.signed_url, headers=extra_headers, content=file)
|
|
104
|
-
if put_resp.status_code
|
|
103
|
+
if put_resp.status_code not in [200, 201, 204]:
|
|
105
104
|
raise RuntimeSystemError(
|
|
106
105
|
"UploadFailed",
|
|
107
106
|
f"Failed to upload {fp} to {resp.signed_url}, status code: {put_resp.status_code}, "
|
flyte/remote/_run.py
CHANGED
|
@@ -157,10 +157,26 @@ class Run(ToJSONMixin):
|
|
|
157
157
|
"""
|
|
158
158
|
Get the details of the run. This is a placeholder for getting the run details.
|
|
159
159
|
"""
|
|
160
|
-
if self._details is None:
|
|
160
|
+
if self._details is None or not self._details.done():
|
|
161
161
|
self._details = await RunDetails.get_details.aio(self.pb2.action.id.run)
|
|
162
162
|
return self._details
|
|
163
163
|
|
|
164
|
+
@syncify
|
|
165
|
+
async def inputs(self) -> ActionInputs:
|
|
166
|
+
"""
|
|
167
|
+
Get the inputs of the run. This is a placeholder for getting the run inputs.
|
|
168
|
+
"""
|
|
169
|
+
details = await self.details.aio()
|
|
170
|
+
return await details.inputs()
|
|
171
|
+
|
|
172
|
+
@syncify
|
|
173
|
+
async def outputs(self) -> ActionOutputs:
|
|
174
|
+
"""
|
|
175
|
+
Get the outputs of the run. This is a placeholder for getting the run outputs.
|
|
176
|
+
"""
|
|
177
|
+
details = await self.details.aio()
|
|
178
|
+
return await details.outputs()
|
|
179
|
+
|
|
164
180
|
@property
|
|
165
181
|
def url(self) -> str:
|
|
166
182
|
"""
|
flyte/storage/_config.py
CHANGED
|
@@ -61,6 +61,7 @@ class S3(Storage):
|
|
|
61
61
|
endpoint: typing.Optional[str] = None
|
|
62
62
|
access_key_id: typing.Optional[str] = None
|
|
63
63
|
secret_access_key: typing.Optional[str] = None
|
|
64
|
+
region: typing.Optional[str] = None
|
|
64
65
|
|
|
65
66
|
_KEY_ENV_VAR_MAPPING: ClassVar[typing.Dict[str, str]] = {
|
|
66
67
|
"endpoint": "FLYTE_AWS_ENDPOINT",
|
|
@@ -76,7 +77,7 @@ class S3(Storage):
|
|
|
76
77
|
_KEY_SKIP_SIGNATURE: ClassVar = "skip_signature"
|
|
77
78
|
|
|
78
79
|
@classmethod
|
|
79
|
-
def auto(cls) -> S3:
|
|
80
|
+
def auto(cls, region: str | None = None) -> S3:
|
|
80
81
|
"""
|
|
81
82
|
:return: Config
|
|
82
83
|
"""
|
|
@@ -88,6 +89,7 @@ class S3(Storage):
|
|
|
88
89
|
kwargs = set_if_exists(kwargs, "endpoint", endpoint)
|
|
89
90
|
kwargs = set_if_exists(kwargs, "access_key_id", access_key_id)
|
|
90
91
|
kwargs = set_if_exists(kwargs, "secret_access_key", secret_access_key)
|
|
92
|
+
kwargs = set_if_exists(kwargs, "region", region)
|
|
91
93
|
|
|
92
94
|
return S3(**kwargs)
|
|
93
95
|
|
|
@@ -141,6 +143,8 @@ class S3(Storage):
|
|
|
141
143
|
kwargs["config"] = config
|
|
142
144
|
kwargs["client_options"] = client_options or None
|
|
143
145
|
kwargs["retry_config"] = retry_config or None
|
|
146
|
+
if self.region:
|
|
147
|
+
kwargs["region"] = self.region
|
|
144
148
|
|
|
145
149
|
return kwargs
|
|
146
150
|
|
flyte/types/_type_engine.py
CHANGED
|
@@ -786,6 +786,13 @@ class EnumTransformer(TypeTransformer[enum.Enum]):
|
|
|
786
786
|
return LiteralType(enum_type=types_pb2.EnumType(values=values))
|
|
787
787
|
|
|
788
788
|
async def to_literal(self, python_val: enum.Enum, python_type: Type[T], expected: LiteralType) -> Literal:
|
|
789
|
+
if isinstance(python_val, str):
|
|
790
|
+
# this is the case when python Literals are used as enums
|
|
791
|
+
if python_val not in expected.enum_type.values:
|
|
792
|
+
raise TypeTransformerFailedError(
|
|
793
|
+
f"Value {python_val} is not valid value, expected - {expected.enum_type.values}"
|
|
794
|
+
)
|
|
795
|
+
return Literal(scalar=Scalar(primitive=Primitive(string_value=python_val))) # type: ignore
|
|
789
796
|
if type(python_val).__class__ != enum.EnumMeta:
|
|
790
797
|
raise TypeTransformerFailedError("Expected an enum")
|
|
791
798
|
if type(python_val.value) is not str:
|
|
@@ -21,8 +21,8 @@ import click
|
|
|
21
21
|
|
|
22
22
|
ACTION_NAME = "ACTION_NAME"
|
|
23
23
|
RUN_NAME = "RUN_NAME"
|
|
24
|
-
PROJECT_NAME = "
|
|
25
|
-
DOMAIN_NAME = "
|
|
24
|
+
PROJECT_NAME = "FLYTE_INTERNAL_EXECUTION_PROJECT"
|
|
25
|
+
DOMAIN_NAME = "FLYTE_INTERNAL_EXECUTION_DOMAIN"
|
|
26
26
|
ORG_NAME = "_U_ORG_NAME"
|
|
27
27
|
ENDPOINT_OVERRIDE = "_U_EP_OVERRIDE"
|
|
28
28
|
RUN_OUTPUT_BASE_DIR = "_U_RUN_BASE"
|
|
@@ -9,9 +9,9 @@ flyte/_excepthook.py,sha256=nXts84rzEg6-7RtFarbKzOsRZTQR4plnbWVIFMAEprs,1310
|
|
|
9
9
|
flyte/_group.py,sha256=7o1j16sZyUmYB50mOiq1ui4TBAKhRpDqLakV8Ya1kw4,803
|
|
10
10
|
flyte/_hash.py,sha256=KMKjoI7SaxXildb-xv6n5Vb32B0csvBiYc06iUe-BrI,137
|
|
11
11
|
flyte/_image.py,sha256=CSbH7XSSRSNtzri5hLOR-tKIaFW2m8VMEoC1TZmdg6M,38602
|
|
12
|
-
flyte/_initialize.py,sha256=
|
|
13
|
-
flyte/_interface.py,sha256=
|
|
14
|
-
flyte/_logging.py,sha256=
|
|
12
|
+
flyte/_initialize.py,sha256=XzbAtqPM83ml4jH14kvClUCeKshchFQUvFZghGZVGQM,17923
|
|
13
|
+
flyte/_interface.py,sha256=LBprgsS_DIx5fdnWUyeKQnl2XlAyc1SYlRNlZySwRIA,4766
|
|
14
|
+
flyte/_logging.py,sha256=7e_rQC4gtBcKvJStNX8Af-ZJG0U0r-2Om_8JMvkvb5k,6283
|
|
15
15
|
flyte/_map.py,sha256=8u4jZsM26V-M-dhVbSnyqSrkzJnGgisN3kwwSNQZaa4,10697
|
|
16
16
|
flyte/_pod.py,sha256=MB5eP2WvTc5lD5ovdVlxoOpx-wJeutv0S64s75astLc,1105
|
|
17
17
|
flyte/_resources.py,sha256=L2JuvQDlMo1JLJeUmJPRwtWbunhR2xJEhFgQW5yc72c,9690
|
|
@@ -25,22 +25,22 @@ flyte/_task_plugins.py,sha256=9MH3nFPOH_e8_92BT4sFk4oyAnj6GJFvaPYWaraX7yE,1037
|
|
|
25
25
|
flyte/_timeout.py,sha256=zx5sFcbYmjJAJbZWSGzzX-BpC9HC7Jfs35T7vVhKwkk,1571
|
|
26
26
|
flyte/_tools.py,sha256=lB3OiJSAhxzSMCYjLUF6nZjlFsmNpaRXtr3_Fefcxbg,747
|
|
27
27
|
flyte/_trace.py,sha256=-BIprs2MbupWl3vsC_Pn33SV3fSVku1rUIsnwfmrIy0,5204
|
|
28
|
-
flyte/_version.py,sha256=
|
|
28
|
+
flyte/_version.py,sha256=yhZDd6WrjR7VGM3U8AX0LKHWlEqOxtftv0MsV5z9dR0,722
|
|
29
29
|
flyte/errors.py,sha256=k1-pgz7xm4syViJmPwp7ZDusmqcrlM2uZKrl0com_9I,6707
|
|
30
30
|
flyte/extend.py,sha256=GB4ZedGzKa30vYWRVPOdxEeK62xnUVFY4z2tD6H9eEw,376
|
|
31
|
-
flyte/models.py,sha256=
|
|
31
|
+
flyte/models.py,sha256=l7h-o6pLHGqFcbymAOagHdR4BGKBLJUs6Pmd4J1xbQU,16409
|
|
32
32
|
flyte/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
flyte/_bin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
flyte/_bin/debug.py,sha256=hnX2tlv9QbqckoT5CJ3c3apJj3tGDpsrdV7ZAsE7j34,911
|
|
35
|
-
flyte/_bin/runtime.py,sha256=
|
|
35
|
+
flyte/_bin/runtime.py,sha256=SWSHMHGPQdKSjbc9yJkBbLOXUIpPq8iBk0eFsKDdCeM,6203
|
|
36
36
|
flyte/_cache/__init__.py,sha256=zhdO5UuHQRdzn8GHmSN40nrxfAmI4ihDRuHZM11U84Y,305
|
|
37
37
|
flyte/_cache/cache.py,sha256=-oS5q6QpkxPqZ8gWkn8uVNgzx3JFuXaWLV-h0KVKW9c,5010
|
|
38
38
|
flyte/_cache/defaults.py,sha256=gzJZW0QJPUfd2OPnGpv3tzIfwPtgFjAKoie3NP1P97U,217
|
|
39
39
|
flyte/_cache/policy_function_body.py,sha256=_AcyN6XKRXq16yV5lWuRJYCIVUlmyPvvWuYRxfU-Ldo,1507
|
|
40
40
|
flyte/_code_bundle/__init__.py,sha256=G7DJTQ0UN_ETvdh55pYcWsTrZJKXEcyQl9iQQNQOBXQ,328
|
|
41
|
-
flyte/_code_bundle/_ignore.py,sha256=
|
|
42
|
-
flyte/_code_bundle/_packaging.py,sha256=
|
|
43
|
-
flyte/_code_bundle/_utils.py,sha256=
|
|
41
|
+
flyte/_code_bundle/_ignore.py,sha256=INTPvv8ironCBIl_sJ_VaXnMd7gJcx0hL-OvrZNXdRo,4127
|
|
42
|
+
flyte/_code_bundle/_packaging.py,sha256=H-_boKm4Wlri2D1zR-VzjvDxM-_R-_hKUBWVPUWYFKU,7094
|
|
43
|
+
flyte/_code_bundle/_utils.py,sha256=UXyYiW5fPGgSDi1KnVX1Ow_03oKnROhLS21GiYRjlpE,12203
|
|
44
44
|
flyte/_code_bundle/bundle.py,sha256=L5RgACketbali3v9s5r97nsoueKWtaWyHbv2p2MeMIE,8821
|
|
45
45
|
flyte/_debug/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
46
|
flyte/_debug/constants.py,sha256=oAiXr59RJfg1rjlY4_Iw1SDH1V61kvqBLBua3aQ8oW4,1641
|
|
@@ -58,9 +58,9 @@ flyte/_internal/controllers/remote/_core.py,sha256=5qIGFNTilJwtYLQ_KQoawLQ172ih-
|
|
|
58
58
|
flyte/_internal/controllers/remote/_informer.py,sha256=M2uqfe0oz9ySkYK94UFLoTPRt9UoaYQKzmy4lrVOchY,14912
|
|
59
59
|
flyte/_internal/controllers/remote/_service_protocol.py,sha256=B9qbIg6DiGeac-iSccLmX_AL2xUgX4ezNUOiAbSy4V0,1357
|
|
60
60
|
flyte/_internal/imagebuild/__init__.py,sha256=dwXdJ1jMhw9RF8itF7jkPLanvX1yCviSns7hE5eoIts,102
|
|
61
|
-
flyte/_internal/imagebuild/docker_builder.py,sha256=
|
|
61
|
+
flyte/_internal/imagebuild/docker_builder.py,sha256=3PqIh8NGiNo8f9ekUxyZYF4i9I40BD06VoEGaV-ymoo,23840
|
|
62
62
|
flyte/_internal/imagebuild/image_builder.py,sha256=dXBXl62qcPabus6dR3eP8P9mBGNhpZHZ2Xm12AymKkk,11150
|
|
63
|
-
flyte/_internal/imagebuild/remote_builder.py,sha256=
|
|
63
|
+
flyte/_internal/imagebuild/remote_builder.py,sha256=QOs0miveAnDEDxXCNRnkblw7DB-BJwQUOeL0Y_9ao2A,13120
|
|
64
64
|
flyte/_internal/imagebuild/utils.py,sha256=2MMCNyyMoPLO8sJ5J9TnrZwd1xWTty5AW2VVp8ZUd_M,1250
|
|
65
65
|
flyte/_internal/resolvers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
66
|
flyte/_internal/resolvers/_task_module.py,sha256=jwy1QYygUK7xmpCZLt1SPTfJCkfox3Ck3mTlTsm66UI,1973
|
|
@@ -76,6 +76,8 @@ flyte/_internal/runtime/rusty.py,sha256=e2uSg9-Hooa65-BIuqXhIrEq86RHteFFs3W7dDuM
|
|
|
76
76
|
flyte/_internal/runtime/task_serde.py,sha256=lE1x_hEEvPkRN_ogVqWL76dGruG2pZt1q0LyCE2d-f4,14093
|
|
77
77
|
flyte/_internal/runtime/taskrunner.py,sha256=T1dviDXYds18eSwT_J6AMvD4oY91t1r_31EAFA5grO0,7683
|
|
78
78
|
flyte/_internal/runtime/types_serde.py,sha256=EjRh9Yypx9-20XXQprtNgp766LeQVRoYWtY6XPGMZQg,1813
|
|
79
|
+
flyte/_keyring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
|
+
flyte/_keyring/file.py,sha256=6XxDnk_hejWRnH8WLd7RVFqoiRY23Td8Cm2nh1VCloo,2950
|
|
79
81
|
flyte/_protos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
80
82
|
flyte/_protos/common/authorization_pb2.py,sha256=6G7CAfq_Vq1qrm8JFkAnMAj0AaEipiX7MkjA7nk91-M,6707
|
|
81
83
|
flyte/_protos/common/authorization_pb2.pyi,sha256=tdqc3wZo3Yc6lKfjVgJlUFUFzGv4GAaCknIv43RGd-8,4759
|
|
@@ -154,7 +156,7 @@ flyte/_protos/workflow/task_service_pb2_grpc.py,sha256=whmfmOTiNhz6_CBsXm8aXUCwt
|
|
|
154
156
|
flyte/_utils/__init__.py,sha256=Lwn9_fLxNF4YR0oCUIKCwM_aXYT5UFjUFInofTHnQTs,831
|
|
155
157
|
flyte/_utils/asyn.py,sha256=KeJKarXNIyD16g6oPM0T9cH7JDmh1KY7JLbwo7i0IlQ,3673
|
|
156
158
|
flyte/_utils/async_cache.py,sha256=JtZJmWO62OowJ0QFNl6wryWqh-kuDi76aAASMie87QY,4596
|
|
157
|
-
flyte/_utils/coro_management.py,sha256=
|
|
159
|
+
flyte/_utils/coro_management.py,sha256=2XPC1UznYDwJB9_BXMSUjsJmbksiW1JKIU3fNmBWMCI,1030
|
|
158
160
|
flyte/_utils/file_handling.py,sha256=iU4TxW--fCho_Eg5xTMODn96P03SxzF-V-5f-7bZAZY,2233
|
|
159
161
|
flyte/_utils/helpers.py,sha256=9N70yzfLF4lLGEEdOv5OcweEpYtrCvZqqhtzkjZUXNY,4779
|
|
160
162
|
flyte/_utils/lazy_module.py,sha256=fvXPjvZLzCfcI8Vzs4pKedUDdY0U_RQ1ZVrp9b8qBQY,1994
|
|
@@ -175,29 +177,29 @@ flyte/cli/_params.py,sha256=oCSnBh6fDSS1HLFZvNRstfXlaJHTWaOVwMQ_R6icehs,20009
|
|
|
175
177
|
flyte/cli/_run.py,sha256=bd024EikZwqHBSLCr1K45bkwwXMD8vxnl_0EIQAh4T0,16376
|
|
176
178
|
flyte/cli/main.py,sha256=t5Ivjipd6bVHIGjRBGwkeP577j59ASq9c1wgoNf3h2c,5334
|
|
177
179
|
flyte/config/__init__.py,sha256=MiwEYK5Iv7MRR22z61nzbsbvZ9Q6MdmAU_g9If1Pmb8,144
|
|
178
|
-
flyte/config/_config.py,sha256
|
|
180
|
+
flyte/config/_config.py,sha256=gsGtIZa9CUILfBmWm2CaEMRLHcSOeNUgwPHeIV807bs,10942
|
|
179
181
|
flyte/config/_internal.py,sha256=LMcAtDjvTjf5bGlsJVxPuLxQQ82mLd00xK5-JlYGCi8,2989
|
|
180
|
-
flyte/config/_reader.py,sha256=
|
|
182
|
+
flyte/config/_reader.py,sha256=dMS27dI8CUjwIEzpTR4aQpNzA_GP0vpaquLIlv-UW3E,7702
|
|
181
183
|
flyte/connectors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
182
184
|
flyte/extras/__init__.py,sha256=FhB0uK7H1Yo5De9vOuF7UGnezTKncj3u2Wo5uQdWN0g,74
|
|
183
185
|
flyte/extras/_container.py,sha256=xfbxaGrx2JyQyrvQx1UWTzho2ion8_xujPW5V4uDEIs,11818
|
|
184
186
|
flyte/git/__init__.py,sha256=OYDrwq1mZ70xC4QC205s1seFvdk9fjDPSv8DrbopdC8,70
|
|
185
|
-
flyte/git/_config.py,sha256=
|
|
187
|
+
flyte/git/_config.py,sha256=nOczu_9GwaDLji_TbrwjtKoG_buiJEPXMGzSDjeLhr0,739
|
|
186
188
|
flyte/io/__init__.py,sha256=qF8jq_IKuocuGU0LAvoy_uxjMs4G-vXjDA9Prba0JGU,538
|
|
187
|
-
flyte/io/_dir.py,sha256=
|
|
189
|
+
flyte/io/_dir.py,sha256=I2u2PeyIFHpfTmRVyogei1y8HnXOZIPpdaoXN0dRRSM,16456
|
|
188
190
|
flyte/io/_file.py,sha256=tMLp4rd5l_RZzM5zWSn82aSK_xcvi6fJ1Aogkvgc6tE,18641
|
|
189
191
|
flyte/io/_hashing_io.py,sha256=QvhQ4K5jiHgzzPqZY4gFz5Fm-BAzq6bzyCpzXhfnWlk,10014
|
|
190
192
|
flyte/io/_dataframe/__init__.py,sha256=SDgNw45uf7m3cHhbUCOA3V3-5A2zSKgPcsWriRLwd74,4283
|
|
191
193
|
flyte/io/_dataframe/basic_dfs.py,sha256=tUJKiBbIJ30r9hjwMo-y3bxjdLmyf3WVe9n9tYskKWk,8043
|
|
192
|
-
flyte/io/_dataframe/dataframe.py,sha256=
|
|
194
|
+
flyte/io/_dataframe/dataframe.py,sha256=HOW6W12uAlN_1YH9fOgk-HaAse3ACgVyb18vsa83Uzo,49371
|
|
193
195
|
flyte/remote/__init__.py,sha256=y9eke9JzEJkygk8eKZjSj44fJGlyepuW4i-j6lbCAPY,617
|
|
194
196
|
flyte/remote/_action.py,sha256=o19TUh7qo5JrCU1NhqXWAPKCWco6yjrvKVP5gt6fskU,24254
|
|
195
197
|
flyte/remote/_common.py,sha256=2XLLxWL1NjwfdPQUhOfYn3zMrg-yGNfi6NYIaqHutUA,862
|
|
196
198
|
flyte/remote/_console.py,sha256=avmELJPx8nQMAVPrHlh6jEIRPjrMwFpdZjJsWOOa9rE,660
|
|
197
|
-
flyte/remote/_data.py,sha256=
|
|
199
|
+
flyte/remote/_data.py,sha256=WeRkhUrJlx7rU3CpvbPvikosv7r02UMveWrf70cFilQ,6156
|
|
198
200
|
flyte/remote/_logs.py,sha256=t4H7DEZDYJC9Vx7oJ7R7m4Z56bWBAjm9ylU4UP1hKq0,6711
|
|
199
201
|
flyte/remote/_project.py,sha256=IbkxKRAvZunKLIwpmcreA4O-0GxWC0KPC62WSYvsK34,2868
|
|
200
|
-
flyte/remote/_run.py,sha256=
|
|
202
|
+
flyte/remote/_run.py,sha256=HQuIWPyZguFoSgl_fbH9HYiFhd1xIaX1iUlSzF2m3-s,10547
|
|
201
203
|
flyte/remote/_secret.py,sha256=CF9WiZKeMJaUNeIawVPf8XHk9OjFt2wc0m7S9ZOdGbE,4399
|
|
202
204
|
flyte/remote/_task.py,sha256=EuTNXfnqksQf-UxLMIo20sds53mbyl0qpgjujnw3y-A,18654
|
|
203
205
|
flyte/remote/_client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -214,7 +216,7 @@ flyte/remote/_client/auth/errors.py,sha256=ZYS9k4GX_McacKhxHKt5V2A4CWjLUq4RkBx_g
|
|
|
214
216
|
flyte/remote/_client/auth/_authenticators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
215
217
|
flyte/remote/_client/auth/_authenticators/base.py,sha256=LIIYt46j6_ShJRiwjNwNX-LxLiUoG1qbiN0ypyzGedY,17020
|
|
216
218
|
flyte/remote/_client/auth/_authenticators/client_credentials.py,sha256=e9DOFdKEvaM3uSR10lnNuJaOwAcCkZQWZPKv7xUoFsI,3483
|
|
217
|
-
flyte/remote/_client/auth/_authenticators/device_code.py,sha256=
|
|
219
|
+
flyte/remote/_client/auth/_authenticators/device_code.py,sha256=YKj0HLT2Gegoc8_mKEOgVRUw_Bp9EtDeTUAvmc3IoMY,4806
|
|
218
220
|
flyte/remote/_client/auth/_authenticators/external_command.py,sha256=IfTJQACPd1xc6htZYC-HdMIx6Q9JHBPw1HUG1Pv6lXg,3838
|
|
219
221
|
flyte/remote/_client/auth/_authenticators/factory.py,sha256=_oBWs7xIG6l13q06V2PUGIDmzU9-XYUK5hx5S6gZjrU,10291
|
|
220
222
|
flyte/remote/_client/auth/_authenticators/pkce.py,sha256=PXbYCmgYGn_LP2EED1O41uzeV4I7L03M1-u3CMRag_M,23097
|
|
@@ -225,7 +227,7 @@ flyte/report/__init__.py,sha256=yLbeUxYaVaDlgBod3Oh34zGBSotl1UlXq1vUkb9q7cs,152
|
|
|
225
227
|
flyte/report/_report.py,sha256=b-VMFke-5SitqGfNEXKTm0PuEPzonWpvlAl5V3wSh4o,5328
|
|
226
228
|
flyte/report/_template.html,sha256=YehmLJG3QMYQ10UT1YZBu2ncVmAJ4iyqVp5hF3sXRAs,3458
|
|
227
229
|
flyte/storage/__init__.py,sha256=0tcI9qtIVf0Fxczkno03vpwBDVlKMDSNN38uxMTH1bE,569
|
|
228
|
-
flyte/storage/_config.py,sha256=
|
|
230
|
+
flyte/storage/_config.py,sha256=Pl4i5KSkUJA_4HqDdvQlPn1OxFmVWIxl1bw0tp0mDGM,8871
|
|
229
231
|
flyte/storage/_remote_fs.py,sha256=kM_iszbccjVD5VtVdgfkl1FHS8NPnY__JOo_CPQUE4c,1124
|
|
230
232
|
flyte/storage/_storage.py,sha256=i9oAn9Co1S5U0noLeDxG9ROQd5KS-b7G1k1fMoVuYbE,14046
|
|
231
233
|
flyte/storage/_utils.py,sha256=8oLCM-7D7JyJhzUi1_Q1NFx8GBUPRfou0T_5tPBmPbE,309
|
|
@@ -236,13 +238,13 @@ flyte/types/_interface.py,sha256=5y9EC5r897xz03Hh0ltF8QVGKMfMfAznws-hKSEO4Go,167
|
|
|
236
238
|
flyte/types/_pickle.py,sha256=PjdR66OTDMZ3OYq6GvM_Ua0cIo5t2XQaIjmpJ9xo4Ys,4050
|
|
237
239
|
flyte/types/_renderer.py,sha256=ygcCo5l60lHufyQISFddZfWwLlQ8kJAKxUT_XnR_6dY,4818
|
|
238
240
|
flyte/types/_string_literals.py,sha256=NlG1xV8RSA-sZ-n-IFQCAsdB6jXJOAKkHWtnopxVVDk,4231
|
|
239
|
-
flyte/types/_type_engine.py,sha256=
|
|
241
|
+
flyte/types/_type_engine.py,sha256=CKWWGwSOP3vFZUlMnv-Rgzu-EJ-DkX--Yhn_g3M9cjw,95394
|
|
240
242
|
flyte/types/_utils.py,sha256=pbts9E1_2LTdLygAY0UYTLYJ8AsN3BZyviSXvrtcutc,2626
|
|
241
|
-
flyte-2.0.
|
|
242
|
-
flyte-2.0.
|
|
243
|
-
flyte-2.0.
|
|
244
|
-
flyte-2.0.
|
|
245
|
-
flyte-2.0.
|
|
246
|
-
flyte-2.0.
|
|
247
|
-
flyte-2.0.
|
|
248
|
-
flyte-2.0.
|
|
243
|
+
flyte-2.0.0b21.data/scripts/debug.py,sha256=hnX2tlv9QbqckoT5CJ3c3apJj3tGDpsrdV7ZAsE7j34,911
|
|
244
|
+
flyte-2.0.0b21.data/scripts/runtime.py,sha256=SWSHMHGPQdKSjbc9yJkBbLOXUIpPq8iBk0eFsKDdCeM,6203
|
|
245
|
+
flyte-2.0.0b21.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
246
|
+
flyte-2.0.0b21.dist-info/METADATA,sha256=P0WPet5aQBjjrj1JvlecH69jE20-AunhqhIGWkMld98,10045
|
|
247
|
+
flyte-2.0.0b21.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
248
|
+
flyte-2.0.0b21.dist-info/entry_points.txt,sha256=rb43Gfxw40iPH5B6EUs6Ter0ekLkGXsj7R890_MOTyk,136
|
|
249
|
+
flyte-2.0.0b21.dist-info/top_level.txt,sha256=7dkyFbikvA12LEZEqawx8oDG1CMod6hTliPj7iWzgYo,6
|
|
250
|
+
flyte-2.0.0b21.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|