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 CHANGED
@@ -21,8 +21,8 @@ import click
21
21
 
22
22
  ACTION_NAME = "ACTION_NAME"
23
23
  RUN_NAME = "RUN_NAME"
24
- PROJECT_NAME = "FLYTE_INTERNAL_TASK_PROJECT"
25
- DOMAIN_NAME = "FLYTE_INTERNAL_TASK_DOMAIN"
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"
@@ -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(path), pattern):
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.walk():
115
+ for dir, _, files in os.walk(self.root):
116
+ dir_path = Path(dir)
109
117
  for file in files:
110
- abs_path = dir / file
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
@@ -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
- click.secho("Files to be copied for fast registration...", fg="bright_blue")
29
+ logger.info("Files to be copied for fast registration...")
31
30
 
32
31
  tree_root = Tree(
33
- f":open_file_folder: [link file://{source}]{source} (detected source root)",
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
- rich_print(tree_root)
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:
@@ -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 source_path.walk(top_down=True, follow_symlinks=deref_symlinks):
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
- interactive_mode = ipython_check()
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
- logger.debug(f"Flyte config initialized as {cfg}")
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
- from typing import Dict, Generator, Tuple, Type, TypeVar, Union, cast, get_args, get_type_hints
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
- return dict(zip(list(output_name_generator(len(ra))), ra))
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
- async def handle(layer: CopyConfig, context_path: Path, dockerfile: str) -> str:
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
- shutil.copytree(abs_path, dst_path, dirs_exist_ok=True)
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
- raise ValueError(f"Source path is neither file nor directory: {layer.src}")
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(layer: Layer, context_path: Path, dockerfile: str) -> str:
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(click.style(f"Image {resp.image.fqin} found. Skip building.", fg="blue"))
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(click.style(f"Image {image_name} was not found or has expired.", fg="blue"))
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(click.style("🐳 Submitting a new build...", fg="blue", bold=True))
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(click.style(f"✅ Build completed in {elapsed}!", bold=True, fg="green"))
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 {click.style(run.url, fg='cyan')}")
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
- click.style(
187
- f"Context size is {context_size / (1024 * 1024):.2f} MB, which is larger than 5 MB. "
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.console import Console
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=Console(width=width),
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")
@@ -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.0b20'
32
- __version_tuple__ = version_tuple = (2, 0, 0, 'b20')
31
+ __version__ = version = '2.0.0b21'
32
+ __version_tuple__ = version_tuple = (2, 0, 0, 'b21')
33
33
 
34
- __commit_id__ = commit_id = 'g5109b02e4'
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. `UCTL_CONFIG` environment variable
235
- c. `FLYTECTL_CONFIG` environment variable
236
- d. ~/.union/config.yaml if it exists
237
- e. ~/.flyte/config.yaml if it exists
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. `UCTL_CONFIG` environment variable
144
- 4. `FLYTECTL_CONFIG` environment variable
145
- 5. ~/.union/config.yaml if it exists
146
- 6. ~/.flyte/config.yaml if it exists
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)
@@ -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("dataframe_type"):
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
- ```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
- ```
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
- ```python
98
- async for file in directory.walk():
99
- local_path = await file.download()
100
- # Process the file
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
- ```python
138
- for file in directory.walk_sync():
139
- local_path = file.download_sync()
140
- # Process the file
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
- ```python
161
- files = await directory.list_files()
162
- for file in files:
163
- # Process the file
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
- ```python
181
- files = directory.list_files_sync()
182
- for file in files:
183
- # Process the file
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
- ```python
201
- local_dir = await directory.download('/tmp/my_data/')
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
- ```python
234
- local_dir = directory.download_sync('/tmp/my_data/')
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
- ```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
- ```
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
- ```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
- ```
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
- ```python
316
- remote_dir = Dir[DataFrame].from_local_sync('/tmp/data_dir/', 's3://bucket/data/')
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
- ```python
331
- if await directory.exists():
332
- # Process the directory
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
- ```python
350
- if directory.exists_sync():
351
- # Process the directory
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
- ```python
369
- file = await directory.get_file("data.csv")
370
- if file:
371
- # Process the file
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
- ```python
394
- file = directory.get_file_sync("data.csv")
395
- if file:
396
- # Process the file
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
- param_info[name] = (param.annotation, param.default)
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 click
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
- click.secho(text)
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 {make_hyperlink('signed url', resp.signed_url)} for {fp}")
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 != 200:
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
 
@@ -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 = "FLYTE_INTERNAL_TASK_PROJECT"
25
- DOMAIN_NAME = "FLYTE_INTERNAL_TASK_DOMAIN"
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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flyte
3
- Version: 2.0.0b20
3
+ Version: 2.0.0b21
4
4
  Summary: Add your description here
5
5
  Author-email: Ketan Umare <kumare3@users.noreply.github.com>
6
6
  Requires-Python: >=3.10
@@ -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=trR10NvbDn7hRr0Tkk702D18CtZA7BA3PSIDgHr92eY,17733
13
- flyte/_interface.py,sha256=1B9zIwFDjiVp_3l_mk8EpA4g3Re-6DUBEBi9z9vDvPs,3504
14
- flyte/_logging.py,sha256=eFplcnmHdhkJ8wNByFk_04fwqYYmS-GvyCEhqosyxdg,6088
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=DHBNTfUVjKbnarRHJH69S1E8D0BHxMGpAixhCbYE448,722
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=dtaQyU4PhtEr5L39xwiPDVKSYuYKaArRfRNliIfPUf8,16207
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=CoMgKQ_pBifnHsNF1MlBGmMrenrKXuMIHTLRF7MKDfA,6193
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=Tfaoa62CQVTH17kBHD6Xv6xEh1FhcAyvXivl9m-MEE0,3853
42
- flyte/_code_bundle/_packaging.py,sha256=5QUuea6kg9s-ebBg7gFAHaxOMchxR5MhTQ8KohWsjPk,6909
43
- flyte/_code_bundle/_utils.py,sha256=_wUShhA7w46K8fYUbY3S2CkGgcSSHB4wVPNTza0zHFs,12190
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=qzKqicgGpWB6wC2DYTc4yh5LJT_hbQ7nacIqnx4bkOQ,21595
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=nJP-8NaOYubzcfPH8T_iOM38bdyGk1pYd1GzZkZOmaM,13901
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=wIsul4XY-tQbH9bjqZ3A0jKluE19xSzLlkMeYu_dk_A,934
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=-J3a9Iq_XN5GUREEGZcksElHaD0woY_kKNfCrmyKn5w,10807
180
+ flyte/config/_config.py,sha256=gsGtIZa9CUILfBmWm2CaEMRLHcSOeNUgwPHeIV807bs,10942
179
181
  flyte/config/_internal.py,sha256=LMcAtDjvTjf5bGlsJVxPuLxQQ82mLd00xK5-JlYGCi8,2989
180
- flyte/config/_reader.py,sha256=aG27pQAtoEl-r7uZmvZIWz_-lQbh3U4-3-7_Rl7CCZA,7282
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=sxiaqwEVwlI6fCznlOmj2QxX9v2pQm-avW2lPj95mU8,632
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=BED3aupTJUkan3dBXoqZ0r5u-F1Nm_8LUtlCxEg4gUM,16736
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=YLXqUt-1rzE4nklmSWbe-O2-6jmR-sfzdKVVhq80tK8,49283
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=zYXXlqEvPdsC44Gm7rP_hQjRgVe3EFfhZNEWKF0p4MQ,6163
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=FtIIMNODQGyc6oYLmuI_ku3bUxhDFIE-UU7ecMNZvBg,10018
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=E_TfI49Tcy1G0rn7BQV-Q1o4Ebu2ubx7h8pjeCYLieo,4805
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=xVibWJaioOnkeTb_M30azgiUe1jvmQaOWRZEkpdoTao,8680
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=IwBdBXr3sso2Y-ZMiIBmXmczfI7GyJMpThXDuQiOqco,94951
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.0b20.data/scripts/debug.py,sha256=hnX2tlv9QbqckoT5CJ3c3apJj3tGDpsrdV7ZAsE7j34,911
242
- flyte-2.0.0b20.data/scripts/runtime.py,sha256=CoMgKQ_pBifnHsNF1MlBGmMrenrKXuMIHTLRF7MKDfA,6193
243
- flyte-2.0.0b20.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
244
- flyte-2.0.0b20.dist-info/METADATA,sha256=J44ZHZJFMHKtBfaCx69-eDwqCklCBSgS64uKMJqtfz4,10045
245
- flyte-2.0.0b20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
246
- flyte-2.0.0b20.dist-info/entry_points.txt,sha256=MIq2z5dBurdCJfpXfMKzgBv7sJOakKRYxr8G0cMiTrg,75
247
- flyte-2.0.0b20.dist-info/top_level.txt,sha256=7dkyFbikvA12LEZEqawx8oDG1CMod6hTliPj7iWzgYo,6
248
- flyte-2.0.0b20.dist-info/RECORD,,
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,,
@@ -1,3 +1,6 @@
1
1
  [console_scripts]
2
2
  a0 = flyte._bin.runtime:main
3
3
  flyte = flyte.cli.main:main
4
+
5
+ [keyring.backends]
6
+ flyte_keyring_file = flyte._keyring.file