flyte 2.0.0b21__py3-none-any.whl → 2.0.0b23__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.

Files changed (92) hide show
  1. flyte/__init__.py +5 -0
  2. flyte/_bin/runtime.py +36 -6
  3. flyte/_cache/cache.py +4 -2
  4. flyte/_cache/local_cache.py +215 -0
  5. flyte/_code_bundle/bundle.py +1 -0
  6. flyte/_debug/constants.py +0 -1
  7. flyte/_debug/vscode.py +6 -1
  8. flyte/_deploy.py +204 -55
  9. flyte/_environment.py +5 -0
  10. flyte/_excepthook.py +1 -1
  11. flyte/_image.py +101 -68
  12. flyte/_initialize.py +30 -1
  13. flyte/_interface.py +3 -1
  14. flyte/_internal/controllers/_local_controller.py +64 -24
  15. flyte/_internal/controllers/remote/_action.py +4 -1
  16. flyte/_internal/controllers/remote/_controller.py +5 -2
  17. flyte/_internal/controllers/remote/_core.py +6 -3
  18. flyte/_internal/controllers/remote/_informer.py +1 -1
  19. flyte/_internal/imagebuild/docker_builder.py +95 -28
  20. flyte/_internal/imagebuild/image_builder.py +0 -5
  21. flyte/_internal/imagebuild/remote_builder.py +6 -1
  22. flyte/_internal/runtime/io.py +13 -1
  23. flyte/_internal/runtime/rusty.py +17 -2
  24. flyte/_internal/runtime/task_serde.py +15 -11
  25. flyte/_internal/runtime/taskrunner.py +1 -1
  26. flyte/_internal/runtime/trigger_serde.py +153 -0
  27. flyte/_keyring/file.py +2 -2
  28. flyte/_logging.py +1 -1
  29. flyte/_protos/common/identifier_pb2.py +19 -1
  30. flyte/_protos/common/identifier_pb2.pyi +22 -0
  31. flyte/_protos/workflow/common_pb2.py +14 -3
  32. flyte/_protos/workflow/common_pb2.pyi +49 -0
  33. flyte/_protos/workflow/queue_service_pb2.py +41 -35
  34. flyte/_protos/workflow/queue_service_pb2.pyi +26 -12
  35. flyte/_protos/workflow/queue_service_pb2_grpc.py +34 -0
  36. flyte/_protos/workflow/run_definition_pb2.py +38 -38
  37. flyte/_protos/workflow/run_definition_pb2.pyi +4 -2
  38. flyte/_protos/workflow/run_service_pb2.py +60 -50
  39. flyte/_protos/workflow/run_service_pb2.pyi +24 -6
  40. flyte/_protos/workflow/run_service_pb2_grpc.py +34 -0
  41. flyte/_protos/workflow/task_definition_pb2.py +15 -11
  42. flyte/_protos/workflow/task_definition_pb2.pyi +19 -2
  43. flyte/_protos/workflow/task_service_pb2.py +18 -17
  44. flyte/_protos/workflow/task_service_pb2.pyi +5 -2
  45. flyte/_protos/workflow/trigger_definition_pb2.py +66 -0
  46. flyte/_protos/workflow/trigger_definition_pb2.pyi +117 -0
  47. flyte/_protos/workflow/trigger_definition_pb2_grpc.py +4 -0
  48. flyte/_protos/workflow/trigger_service_pb2.py +96 -0
  49. flyte/_protos/workflow/trigger_service_pb2.pyi +110 -0
  50. flyte/_protos/workflow/trigger_service_pb2_grpc.py +281 -0
  51. flyte/_run.py +42 -15
  52. flyte/_task.py +35 -4
  53. flyte/_task_environment.py +61 -16
  54. flyte/_trigger.py +382 -0
  55. flyte/_version.py +3 -3
  56. flyte/cli/_abort.py +3 -3
  57. flyte/cli/_build.py +1 -3
  58. flyte/cli/_common.py +17 -4
  59. flyte/cli/_create.py +74 -0
  60. flyte/cli/_delete.py +23 -1
  61. flyte/cli/_deploy.py +16 -10
  62. flyte/cli/_get.py +75 -34
  63. flyte/cli/_params.py +4 -2
  64. flyte/cli/_run.py +25 -6
  65. flyte/cli/_update.py +36 -0
  66. flyte/cli/_user.py +17 -0
  67. flyte/cli/main.py +9 -1
  68. flyte/errors.py +9 -0
  69. flyte/io/_dir.py +513 -115
  70. flyte/io/_file.py +495 -135
  71. flyte/models.py +32 -0
  72. flyte/remote/__init__.py +6 -1
  73. flyte/remote/_action.py +9 -8
  74. flyte/remote/_client/_protocols.py +36 -2
  75. flyte/remote/_client/controlplane.py +19 -3
  76. flyte/remote/_run.py +42 -2
  77. flyte/remote/_task.py +14 -1
  78. flyte/remote/_trigger.py +308 -0
  79. flyte/remote/_user.py +33 -0
  80. flyte/storage/__init__.py +6 -1
  81. flyte/storage/_storage.py +119 -101
  82. flyte/types/_pickle.py +34 -7
  83. flyte/types/_type_engine.py +6 -0
  84. {flyte-2.0.0b21.data → flyte-2.0.0b23.data}/scripts/runtime.py +36 -6
  85. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/METADATA +3 -1
  86. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/RECORD +91 -79
  87. flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
  88. {flyte-2.0.0b21.data → flyte-2.0.0b23.data}/scripts/debug.py +0 -0
  89. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/WHEEL +0 -0
  90. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/entry_points.txt +0 -0
  91. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/licenses/LICENSE +0 -0
  92. {flyte-2.0.0b21.dist-info → flyte-2.0.0b23.dist-info}/top_level.txt +0 -0
flyte/__init__.py CHANGED
@@ -25,6 +25,7 @@ from ._secret import Secret, SecretRequest
25
25
  from ._task_environment import TaskEnvironment
26
26
  from ._timeout import Timeout, TimeoutType
27
27
  from ._trace import trace
28
+ from ._trigger import Cron, FixedRate, Trigger, TriggerTime
28
29
  from ._version import __version__
29
30
 
30
31
  sys.excepthook = custom_excepthook
@@ -64,8 +65,10 @@ __all__ = [
64
65
  "Cache",
65
66
  "CachePolicy",
66
67
  "CacheRequest",
68
+ "Cron",
67
69
  "Device",
68
70
  "Environment",
71
+ "FixedRate",
69
72
  "Image",
70
73
  "PodTemplate",
71
74
  "Resources",
@@ -76,6 +79,8 @@ __all__ = [
76
79
  "TaskEnvironment",
77
80
  "Timeout",
78
81
  "TimeoutType",
82
+ "Trigger",
83
+ "TriggerTime",
79
84
  "__version__",
80
85
  "build",
81
86
  "build_images",
flyte/_bin/runtime.py CHANGED
@@ -12,6 +12,8 @@ from typing import Any, List
12
12
 
13
13
  import click
14
14
 
15
+ from flyte.models import PathRewrite
16
+
15
17
  # Todo: work with pvditt to make these the names
16
18
  # ACTION_NAME = "_U_ACTION_NAME"
17
19
  # RUN_NAME = "_U_RUN_NAME"
@@ -28,8 +30,8 @@ ENDPOINT_OVERRIDE = "_U_EP_OVERRIDE"
28
30
  RUN_OUTPUT_BASE_DIR = "_U_RUN_BASE"
29
31
  FLYTE_ENABLE_VSCODE_KEY = "_F_E_VS"
30
32
 
31
- # TODO: Remove this after proper auth is implemented
32
33
  _UNION_EAGER_API_KEY_ENV_VAR = "_UNION_EAGER_API_KEY"
34
+ _F_PATH_REWRITE = "_F_PATH_REWRITE"
33
35
 
34
36
 
35
37
  @click.group()
@@ -94,6 +96,7 @@ def main(
94
96
  import flyte
95
97
  import flyte._utils as utils
96
98
  import flyte.errors
99
+ import flyte.storage as storage
97
100
  from flyte._initialize import init
98
101
  from flyte._internal.controllers import create_controller
99
102
  from flyte._internal.imagebuild.image_builder import ImageCache
@@ -136,19 +139,34 @@ def main(
136
139
  controller_kwargs["insecure"] = True
137
140
  logger.debug(f"Using controller endpoint: {ep} with kwargs: {controller_kwargs}")
138
141
 
139
- bundle = CodeBundle(tgz=tgz, pkl=pkl, destination=dest, computed_version=version)
140
- init(org=org, project=project, domain=domain, **controller_kwargs)
142
+ bundle = None
143
+ if tgz or pkl:
144
+ bundle = CodeBundle(tgz=tgz, pkl=pkl, destination=dest, computed_version=version)
145
+ init(org=org, project=project, domain=domain, image_builder="remote", **controller_kwargs)
141
146
  # Controller is created with the same kwargs as init, so that it can be used to run tasks
142
147
  controller = create_controller(ct="remote", **controller_kwargs)
143
148
 
144
149
  ic = ImageCache.from_transport(image_cache) if image_cache else None
145
150
 
151
+ path_rewrite_cfg = os.getenv(_F_PATH_REWRITE, None)
152
+ path_rewrite = None
153
+ if path_rewrite_cfg:
154
+ potential_path_rewrite = PathRewrite.from_str(path_rewrite_cfg)
155
+ if storage.exists_sync(potential_path_rewrite.new_prefix):
156
+ path_rewrite = potential_path_rewrite
157
+ logger.info(f"Path rewrite configured for {path_rewrite.new_prefix}")
158
+ else:
159
+ logger.error(
160
+ f"Path rewrite failed for path {potential_path_rewrite.new_prefix}, "
161
+ f"not found, reverting to original path {potential_path_rewrite.old_prefix}"
162
+ )
163
+
146
164
  # Create a coroutine to load the task and run it
147
165
  task_coroutine = load_and_run_task(
148
166
  resolver=resolver,
149
167
  resolver_args=resolver_args,
150
168
  action=ActionID(name=name, run_name=run_name, project=project, domain=domain, org=org),
151
- raw_data_path=RawDataPath(path=raw_data_path),
169
+ raw_data_path=RawDataPath(path=raw_data_path, path_rewrite=path_rewrite),
152
170
  checkpoints=Checkpoints(checkpoint_path, prev_checkpoint),
153
171
  code_bundle=bundle,
154
172
  input_path=inputs,
@@ -166,8 +184,20 @@ def main(
166
184
  async def _run_and_stop():
167
185
  loop = asyncio.get_event_loop()
168
186
  loop.set_exception_handler(flyte.errors.silence_grpc_polling_error)
169
- await utils.run_coros(controller_failure, task_coroutine)
170
- await controller.stop()
187
+ try:
188
+ await utils.run_coros(controller_failure, task_coroutine)
189
+ await controller.stop()
190
+ except flyte.errors.RuntimeSystemError as e:
191
+ logger.error(f"Runtime system error: {e}")
192
+ from flyte._internal.runtime.convert import convert_from_native_to_error
193
+ from flyte._internal.runtime.io import upload_error
194
+
195
+ logger.error(f"Flyte runtime failed for action {name} with run name {run_name}, error: {e}")
196
+ err = convert_from_native_to_error(e)
197
+ path = await upload_error(err.err, outputs_path)
198
+ logger.error(f"Run {run_name} Action {name} failed with error: {err}. Uploaded error to {path}")
199
+ await controller.stop()
200
+ raise
171
201
 
172
202
  asyncio.run(_run_and_stop())
173
203
  logger.warning(f"Flyte runtime completed for action {name} with run name {run_name}")
flyte/_cache/cache.py CHANGED
@@ -77,14 +77,16 @@ class Cache:
77
77
  def __post_init__(self):
78
78
  if self.behavior not in get_args(CacheBehavior):
79
79
  raise ValueError(f"Invalid cache behavior: {self.behavior}. Must be one of ['auto', 'override', 'disable']")
80
- if self.behavior == "disable":
81
- return
82
80
 
81
+ # Still setup _ignore_inputs when cache is disabled to prevent _ignored_inputs attribute not found error
83
82
  if isinstance(self.ignored_inputs, str):
84
83
  self._ignored_inputs = (self.ignored_inputs,)
85
84
  else:
86
85
  self._ignored_inputs = self.ignored_inputs
87
86
 
87
+ if self.behavior == "disable":
88
+ return
89
+
88
90
  # Normalize policies so that self._policies is always a list
89
91
  if self.policies is None:
90
92
  from flyte._cache.defaults import get_default_policies
@@ -0,0 +1,215 @@
1
+ import sqlite3
2
+ from pathlib import Path
3
+
4
+ try:
5
+ import aiosqlite
6
+
7
+ HAS_AIOSQLITE = True
8
+ except ImportError:
9
+ HAS_AIOSQLITE = False
10
+
11
+ from flyte._internal.runtime import convert
12
+ from flyte._logging import logger
13
+ from flyte._protos.workflow import run_definition_pb2
14
+ from flyte.config import auto
15
+
16
+ DEFAULT_CACHE_DIR = "~/.flyte"
17
+ CACHE_LOCATION = "local-cache/cache.db"
18
+
19
+
20
+ class LocalTaskCache(object):
21
+ """
22
+ This class implements a persistent store able to cache the result of local task executions.
23
+ """
24
+
25
+ _conn: "aiosqlite.Connection | None" = None
26
+ _conn_sync: sqlite3.Connection | None = None
27
+ _initialized: bool = False
28
+
29
+ @staticmethod
30
+ def _get_cache_path() -> str:
31
+ """Get the cache database path, creating directory if needed."""
32
+ config = auto()
33
+ if config.source:
34
+ cache_dir = config.source.parent
35
+ else:
36
+ cache_dir = Path(DEFAULT_CACHE_DIR).expanduser()
37
+
38
+ cache_path = cache_dir / CACHE_LOCATION
39
+ # Ensure the directory exists
40
+ cache_path.parent.mkdir(parents=True, exist_ok=True)
41
+ logger.info(f"Use local cache path: {cache_path}")
42
+ return str(cache_path)
43
+
44
+ @staticmethod
45
+ async def initialize():
46
+ """Initialize the cache with database connection."""
47
+ if not LocalTaskCache._initialized:
48
+ if HAS_AIOSQLITE:
49
+ await LocalTaskCache._initialize_async()
50
+ else:
51
+ LocalTaskCache._initialize_sync()
52
+
53
+ @staticmethod
54
+ async def _initialize_async():
55
+ """Initialize async cache connection."""
56
+ db_path = LocalTaskCache._get_cache_path()
57
+ conn = await aiosqlite.connect(db_path)
58
+ await conn.execute("""
59
+ CREATE TABLE IF NOT EXISTS task_cache (
60
+ key TEXT PRIMARY KEY,
61
+ value BLOB
62
+ )
63
+ """)
64
+ await conn.commit()
65
+ LocalTaskCache._conn = conn
66
+ LocalTaskCache._initialized = True
67
+
68
+ @staticmethod
69
+ def _initialize_sync():
70
+ """Initialize sync cache connection."""
71
+ db_path = LocalTaskCache._get_cache_path()
72
+ conn = sqlite3.connect(db_path)
73
+ conn.execute("""
74
+ CREATE TABLE IF NOT EXISTS task_cache (
75
+ key TEXT PRIMARY KEY,
76
+ value BLOB
77
+ )
78
+ """)
79
+ conn.commit()
80
+ LocalTaskCache._conn_sync = conn
81
+ LocalTaskCache._initialized = True
82
+
83
+ @staticmethod
84
+ async def clear():
85
+ """Clear all cache entries."""
86
+ if not LocalTaskCache._initialized:
87
+ await LocalTaskCache.initialize()
88
+
89
+ if HAS_AIOSQLITE:
90
+ await LocalTaskCache._clear_async()
91
+ else:
92
+ LocalTaskCache._clear_sync()
93
+
94
+ @staticmethod
95
+ async def _clear_async():
96
+ """Clear all cache entries (async)."""
97
+ if LocalTaskCache._conn is None:
98
+ raise RuntimeError("Cache not properly initialized")
99
+ await LocalTaskCache._conn.execute("DELETE FROM task_cache")
100
+ await LocalTaskCache._conn.commit()
101
+
102
+ @staticmethod
103
+ def _clear_sync():
104
+ """Clear all cache entries (sync)."""
105
+ if LocalTaskCache._conn_sync is None:
106
+ raise RuntimeError("Cache not properly initialized")
107
+ LocalTaskCache._conn_sync.execute("DELETE FROM task_cache")
108
+ LocalTaskCache._conn_sync.commit()
109
+
110
+ @staticmethod
111
+ async def get(cache_key: str) -> convert.Outputs | None:
112
+ if not LocalTaskCache._initialized:
113
+ await LocalTaskCache.initialize()
114
+
115
+ if HAS_AIOSQLITE:
116
+ return await LocalTaskCache._get_async(cache_key)
117
+ else:
118
+ return LocalTaskCache._get_sync(cache_key)
119
+
120
+ @staticmethod
121
+ async def _get_async(cache_key: str) -> convert.Outputs | None:
122
+ """Get cache entry (async)."""
123
+ if LocalTaskCache._conn is None:
124
+ raise RuntimeError("Cache not properly initialized")
125
+
126
+ async with LocalTaskCache._conn.execute("SELECT value FROM task_cache WHERE key = ?", (cache_key,)) as cursor:
127
+ row = await cursor.fetchone()
128
+ if row:
129
+ outputs_bytes = row[0]
130
+ outputs = run_definition_pb2.Outputs()
131
+ outputs.ParseFromString(outputs_bytes)
132
+ return convert.Outputs(proto_outputs=outputs)
133
+ return None
134
+
135
+ @staticmethod
136
+ def _get_sync(cache_key: str) -> convert.Outputs | None:
137
+ """Get cache entry (sync)."""
138
+ if LocalTaskCache._conn_sync is None:
139
+ raise RuntimeError("Cache not properly initialized")
140
+
141
+ cursor = LocalTaskCache._conn_sync.execute("SELECT value FROM task_cache WHERE key = ?", (cache_key,))
142
+ row = cursor.fetchone()
143
+ if row:
144
+ outputs_bytes = row[0]
145
+ outputs = run_definition_pb2.Outputs()
146
+ outputs.ParseFromString(outputs_bytes)
147
+ return convert.Outputs(proto_outputs=outputs)
148
+ return None
149
+
150
+ @staticmethod
151
+ async def set(
152
+ cache_key: str,
153
+ value: convert.Outputs,
154
+ ) -> None:
155
+ if not LocalTaskCache._initialized:
156
+ await LocalTaskCache.initialize()
157
+
158
+ if HAS_AIOSQLITE:
159
+ await LocalTaskCache._set_async(cache_key, value)
160
+ else:
161
+ LocalTaskCache._set_sync(cache_key, value)
162
+
163
+ @staticmethod
164
+ async def _set_async(
165
+ cache_key: str,
166
+ value: convert.Outputs,
167
+ ) -> None:
168
+ """Set cache entry (async)."""
169
+ if LocalTaskCache._conn is None:
170
+ raise RuntimeError("Cache not properly initialized")
171
+
172
+ output_bytes = value.proto_outputs.SerializeToString()
173
+ await LocalTaskCache._conn.execute(
174
+ "INSERT OR REPLACE INTO task_cache (key, value) VALUES (?, ?)", (cache_key, output_bytes)
175
+ )
176
+ await LocalTaskCache._conn.commit()
177
+
178
+ @staticmethod
179
+ def _set_sync(
180
+ cache_key: str,
181
+ value: convert.Outputs,
182
+ ) -> None:
183
+ """Set cache entry (sync)."""
184
+ if LocalTaskCache._conn_sync is None:
185
+ raise RuntimeError("Cache not properly initialized")
186
+
187
+ output_bytes = value.proto_outputs.SerializeToString()
188
+ LocalTaskCache._conn_sync.execute(
189
+ "INSERT OR REPLACE INTO task_cache (key, value) VALUES (?, ?)", (cache_key, output_bytes)
190
+ )
191
+ LocalTaskCache._conn_sync.commit()
192
+
193
+ @staticmethod
194
+ async def close():
195
+ """Close the database connection."""
196
+ if HAS_AIOSQLITE:
197
+ await LocalTaskCache._close_async()
198
+ else:
199
+ LocalTaskCache._close_sync()
200
+
201
+ @staticmethod
202
+ async def _close_async():
203
+ """Close async database connection."""
204
+ if LocalTaskCache._conn:
205
+ await LocalTaskCache._conn.close()
206
+ LocalTaskCache._conn = None
207
+ LocalTaskCache._initialized = False
208
+
209
+ @staticmethod
210
+ def _close_sync():
211
+ """Close sync database connection."""
212
+ if LocalTaskCache._conn_sync:
213
+ LocalTaskCache._conn_sync.close()
214
+ LocalTaskCache._conn_sync = None
215
+ LocalTaskCache._initialized = False
@@ -187,6 +187,7 @@ async def download_bundle(bundle: CodeBundle) -> pathlib.Path:
187
187
  # fsspec, which requires a trailing slash in case of pre-existing directory.
188
188
  process = await asyncio.create_subprocess_exec(
189
189
  "tar",
190
+ "--overwrite",
190
191
  "-xvf",
191
192
  str(downloaded_bundle),
192
193
  "-C",
flyte/_debug/constants.py CHANGED
@@ -12,7 +12,6 @@ DEFAULT_CODE_SERVER_REMOTE_PATHS = {
12
12
  }
13
13
  DEFAULT_CODE_SERVER_EXTENSIONS = [
14
14
  "https://raw.githubusercontent.com/flyteorg/flytetools/master/flytekitplugins/flyin/ms-python.python-2023.20.0.vsix",
15
- "https://raw.githubusercontent.com/flyteorg/flytetools/master/flytekitplugins/flyin/ms-toolsai.jupyter-2023.9.100.vsix",
16
15
  ]
17
16
 
18
17
  # Duration to pause the checking of the heartbeat file until the next one
flyte/_debug/vscode.py CHANGED
@@ -256,7 +256,12 @@ def prepare_launch_json(ctx: click.Context, pid: int):
256
256
 
257
257
 
258
258
  async def _start_vscode_server(ctx: click.Context):
259
- await asyncio.gather(download_tgz(ctx.params["dest"], ctx.params["version"], ctx.params["tgz"]), download_vscode())
259
+ if ctx.params["tgz"] is None:
260
+ await download_vscode()
261
+ else:
262
+ await asyncio.gather(
263
+ download_tgz(ctx.params["dest"], ctx.params["version"], ctx.params["tgz"]), download_vscode()
264
+ )
260
265
  child_process = multiprocessing.Process(
261
266
  target=lambda cmd: asyncio.run(asyncio.run(execute_command(cmd))),
262
267
  kwargs={"cmd": f"code-server --bind-addr 0.0.0.0:6060 --disable-workspace-trust --auth none {os.getcwd()}"},