flyte 0.0.1b3__py3-none-any.whl → 0.2.0a0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flyte might be problematic. Click here for more details.
- flyte/__init__.py +20 -4
- flyte/_bin/runtime.py +33 -7
- flyte/_build.py +3 -2
- flyte/_cache/cache.py +1 -2
- flyte/_code_bundle/_packaging.py +1 -1
- flyte/_code_bundle/_utils.py +0 -16
- flyte/_code_bundle/bundle.py +43 -12
- flyte/_context.py +8 -2
- flyte/_deploy.py +56 -15
- flyte/_environment.py +45 -4
- flyte/_excepthook.py +37 -0
- flyte/_group.py +2 -1
- flyte/_image.py +8 -4
- flyte/_initialize.py +112 -254
- flyte/_interface.py +3 -3
- flyte/_internal/controllers/__init__.py +19 -6
- flyte/_internal/controllers/_local_controller.py +83 -8
- flyte/_internal/controllers/_trace.py +2 -1
- flyte/_internal/controllers/remote/__init__.py +27 -7
- flyte/_internal/controllers/remote/_action.py +7 -2
- flyte/_internal/controllers/remote/_client.py +5 -1
- flyte/_internal/controllers/remote/_controller.py +159 -26
- flyte/_internal/controllers/remote/_core.py +13 -5
- flyte/_internal/controllers/remote/_informer.py +4 -4
- flyte/_internal/controllers/remote/_service_protocol.py +6 -6
- flyte/_internal/imagebuild/docker_builder.py +12 -1
- flyte/_internal/imagebuild/image_builder.py +16 -11
- flyte/_internal/runtime/convert.py +164 -21
- flyte/_internal/runtime/entrypoints.py +1 -1
- flyte/_internal/runtime/io.py +3 -3
- flyte/_internal/runtime/task_serde.py +140 -20
- flyte/_internal/runtime/taskrunner.py +4 -3
- flyte/_internal/runtime/types_serde.py +1 -1
- flyte/_logging.py +12 -1
- flyte/_map.py +215 -0
- flyte/_pod.py +19 -0
- flyte/_protos/common/list_pb2.py +3 -3
- flyte/_protos/common/list_pb2.pyi +2 -0
- flyte/_protos/logs/dataplane/payload_pb2.py +28 -24
- flyte/_protos/logs/dataplane/payload_pb2.pyi +11 -2
- flyte/_protos/workflow/common_pb2.py +27 -0
- flyte/_protos/workflow/common_pb2.pyi +14 -0
- flyte/_protos/workflow/environment_pb2.py +29 -0
- flyte/_protos/workflow/environment_pb2.pyi +12 -0
- flyte/_protos/workflow/queue_service_pb2.py +40 -41
- flyte/_protos/workflow/queue_service_pb2.pyi +35 -30
- flyte/_protos/workflow/queue_service_pb2_grpc.py +15 -15
- flyte/_protos/workflow/run_definition_pb2.py +61 -61
- flyte/_protos/workflow/run_definition_pb2.pyi +8 -4
- flyte/_protos/workflow/run_service_pb2.py +20 -24
- flyte/_protos/workflow/run_service_pb2.pyi +2 -6
- flyte/_protos/workflow/state_service_pb2.py +36 -28
- flyte/_protos/workflow/state_service_pb2.pyi +19 -15
- flyte/_protos/workflow/state_service_pb2_grpc.py +28 -28
- flyte/_protos/workflow/task_definition_pb2.py +29 -22
- flyte/_protos/workflow/task_definition_pb2.pyi +21 -5
- flyte/_protos/workflow/task_service_pb2.py +27 -11
- flyte/_protos/workflow/task_service_pb2.pyi +29 -1
- flyte/_protos/workflow/task_service_pb2_grpc.py +34 -0
- flyte/_run.py +166 -95
- flyte/_task.py +110 -28
- flyte/_task_environment.py +55 -72
- flyte/_trace.py +6 -14
- flyte/_utils/__init__.py +6 -0
- flyte/_utils/async_cache.py +139 -0
- flyte/_utils/coro_management.py +0 -2
- flyte/_utils/helpers.py +45 -19
- flyte/_utils/org_discovery.py +57 -0
- flyte/_version.py +2 -2
- flyte/cli/__init__.py +3 -0
- flyte/cli/_abort.py +28 -0
- flyte/{_cli → cli}/_common.py +73 -23
- flyte/cli/_create.py +145 -0
- flyte/{_cli → cli}/_delete.py +4 -4
- flyte/{_cli → cli}/_deploy.py +26 -14
- flyte/cli/_gen.py +163 -0
- flyte/{_cli → cli}/_get.py +98 -23
- {union/_cli → flyte/cli}/_params.py +106 -147
- flyte/{_cli → cli}/_run.py +99 -20
- flyte/cli/main.py +166 -0
- flyte/config/__init__.py +3 -0
- flyte/config/_config.py +216 -0
- flyte/config/_internal.py +64 -0
- flyte/config/_reader.py +207 -0
- flyte/errors.py +29 -0
- flyte/extras/_container.py +33 -43
- flyte/io/__init__.py +17 -1
- flyte/io/_dir.py +2 -2
- flyte/io/_file.py +3 -4
- flyte/io/{structured_dataset → _structured_dataset}/basic_dfs.py +1 -1
- flyte/io/{structured_dataset → _structured_dataset}/structured_dataset.py +1 -1
- flyte/{_datastructures.py → models.py} +56 -7
- flyte/remote/__init__.py +2 -1
- flyte/remote/_client/_protocols.py +2 -0
- flyte/remote/_client/auth/_auth_utils.py +14 -0
- flyte/remote/_client/auth/_channel.py +34 -3
- flyte/remote/_client/auth/_token_client.py +3 -3
- flyte/remote/_client/controlplane.py +13 -13
- flyte/remote/_console.py +1 -1
- flyte/remote/_data.py +10 -6
- flyte/remote/_logs.py +89 -29
- flyte/remote/_project.py +8 -9
- flyte/remote/_run.py +228 -131
- flyte/remote/_secret.py +12 -12
- flyte/remote/_task.py +179 -15
- flyte/report/_report.py +4 -4
- flyte/storage/__init__.py +5 -0
- flyte/storage/_config.py +233 -0
- flyte/storage/_storage.py +23 -3
- flyte/syncify/__init__.py +56 -0
- flyte/syncify/_api.py +371 -0
- flyte/types/__init__.py +23 -0
- flyte/types/_interface.py +22 -7
- flyte/{io/pickle/transformer.py → types/_pickle.py} +2 -1
- flyte/types/_type_engine.py +95 -18
- flyte-0.2.0a0.dist-info/METADATA +249 -0
- flyte-0.2.0a0.dist-info/RECORD +218 -0
- {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/entry_points.txt +1 -1
- flyte/_api_commons.py +0 -3
- flyte/_cli/__init__.py +0 -0
- flyte/_cli/_create.py +0 -42
- flyte/_cli/main.py +0 -72
- flyte/_internal/controllers/pbhash.py +0 -39
- flyte/io/_dataframe.py +0 -0
- flyte/io/pickle/__init__.py +0 -0
- flyte-0.0.1b3.dist-info/METADATA +0 -179
- flyte-0.0.1b3.dist-info/RECORD +0 -390
- union/__init__.py +0 -54
- union/_api_commons.py +0 -3
- union/_bin/__init__.py +0 -0
- union/_bin/runtime.py +0 -113
- union/_build.py +0 -25
- union/_cache/__init__.py +0 -12
- union/_cache/cache.py +0 -141
- union/_cache/defaults.py +0 -9
- union/_cache/policy_function_body.py +0 -42
- union/_cli/__init__.py +0 -0
- union/_cli/_common.py +0 -263
- union/_cli/_create.py +0 -40
- union/_cli/_delete.py +0 -23
- union/_cli/_deploy.py +0 -120
- union/_cli/_get.py +0 -162
- union/_cli/_run.py +0 -150
- union/_cli/main.py +0 -72
- union/_code_bundle/__init__.py +0 -8
- union/_code_bundle/_ignore.py +0 -113
- union/_code_bundle/_packaging.py +0 -187
- union/_code_bundle/_utils.py +0 -342
- union/_code_bundle/bundle.py +0 -176
- union/_context.py +0 -146
- union/_datastructures.py +0 -295
- union/_deploy.py +0 -185
- union/_doc.py +0 -29
- union/_docstring.py +0 -26
- union/_environment.py +0 -43
- union/_group.py +0 -31
- union/_hash.py +0 -23
- union/_image.py +0 -760
- union/_initialize.py +0 -585
- union/_interface.py +0 -84
- union/_internal/__init__.py +0 -3
- union/_internal/controllers/__init__.py +0 -77
- union/_internal/controllers/_local_controller.py +0 -77
- union/_internal/controllers/pbhash.py +0 -39
- union/_internal/controllers/remote/__init__.py +0 -40
- union/_internal/controllers/remote/_action.py +0 -131
- union/_internal/controllers/remote/_client.py +0 -43
- union/_internal/controllers/remote/_controller.py +0 -169
- union/_internal/controllers/remote/_core.py +0 -341
- union/_internal/controllers/remote/_informer.py +0 -260
- union/_internal/controllers/remote/_service_protocol.py +0 -44
- union/_internal/imagebuild/__init__.py +0 -11
- union/_internal/imagebuild/docker_builder.py +0 -416
- union/_internal/imagebuild/image_builder.py +0 -243
- union/_internal/imagebuild/remote_builder.py +0 -0
- union/_internal/resolvers/__init__.py +0 -0
- union/_internal/resolvers/_task_module.py +0 -31
- union/_internal/resolvers/common.py +0 -24
- union/_internal/resolvers/default.py +0 -27
- union/_internal/runtime/__init__.py +0 -0
- union/_internal/runtime/convert.py +0 -163
- union/_internal/runtime/entrypoints.py +0 -121
- union/_internal/runtime/io.py +0 -136
- union/_internal/runtime/resources_serde.py +0 -134
- union/_internal/runtime/task_serde.py +0 -202
- union/_internal/runtime/taskrunner.py +0 -179
- union/_internal/runtime/types_serde.py +0 -53
- union/_logging.py +0 -124
- union/_protos/__init__.py +0 -0
- union/_protos/common/authorization_pb2.py +0 -66
- union/_protos/common/authorization_pb2.pyi +0 -106
- union/_protos/common/identifier_pb2.py +0 -71
- union/_protos/common/identifier_pb2.pyi +0 -82
- union/_protos/common/identity_pb2.py +0 -48
- union/_protos/common/identity_pb2.pyi +0 -72
- union/_protos/common/identity_pb2_grpc.py +0 -4
- union/_protos/common/list_pb2.py +0 -36
- union/_protos/common/list_pb2.pyi +0 -69
- union/_protos/common/list_pb2_grpc.py +0 -4
- union/_protos/common/policy_pb2.py +0 -37
- union/_protos/common/policy_pb2.pyi +0 -27
- union/_protos/common/policy_pb2_grpc.py +0 -4
- union/_protos/common/role_pb2.py +0 -37
- union/_protos/common/role_pb2.pyi +0 -51
- union/_protos/common/role_pb2_grpc.py +0 -4
- union/_protos/common/runtime_version_pb2.py +0 -28
- union/_protos/common/runtime_version_pb2.pyi +0 -24
- union/_protos/common/runtime_version_pb2_grpc.py +0 -4
- union/_protos/logs/dataplane/payload_pb2.py +0 -96
- union/_protos/logs/dataplane/payload_pb2.pyi +0 -168
- union/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
- union/_protos/secret/definition_pb2.py +0 -49
- union/_protos/secret/definition_pb2.pyi +0 -93
- union/_protos/secret/definition_pb2_grpc.py +0 -4
- union/_protos/secret/payload_pb2.py +0 -62
- union/_protos/secret/payload_pb2.pyi +0 -94
- union/_protos/secret/payload_pb2_grpc.py +0 -4
- union/_protos/secret/secret_pb2.py +0 -38
- union/_protos/secret/secret_pb2.pyi +0 -6
- union/_protos/secret/secret_pb2_grpc.py +0 -198
- union/_protos/validate/validate/validate_pb2.py +0 -76
- union/_protos/workflow/node_execution_service_pb2.py +0 -26
- union/_protos/workflow/node_execution_service_pb2.pyi +0 -4
- union/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
- union/_protos/workflow/queue_service_pb2.py +0 -75
- union/_protos/workflow/queue_service_pb2.pyi +0 -103
- union/_protos/workflow/queue_service_pb2_grpc.py +0 -172
- union/_protos/workflow/run_definition_pb2.py +0 -100
- union/_protos/workflow/run_definition_pb2.pyi +0 -256
- union/_protos/workflow/run_definition_pb2_grpc.py +0 -4
- union/_protos/workflow/run_logs_service_pb2.py +0 -41
- union/_protos/workflow/run_logs_service_pb2.pyi +0 -28
- union/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
- union/_protos/workflow/run_service_pb2.py +0 -133
- union/_protos/workflow/run_service_pb2.pyi +0 -173
- union/_protos/workflow/run_service_pb2_grpc.py +0 -412
- union/_protos/workflow/state_service_pb2.py +0 -58
- union/_protos/workflow/state_service_pb2.pyi +0 -69
- union/_protos/workflow/state_service_pb2_grpc.py +0 -138
- union/_protos/workflow/task_definition_pb2.py +0 -72
- union/_protos/workflow/task_definition_pb2.pyi +0 -65
- union/_protos/workflow/task_definition_pb2_grpc.py +0 -4
- union/_protos/workflow/task_service_pb2.py +0 -44
- union/_protos/workflow/task_service_pb2.pyi +0 -31
- union/_protos/workflow/task_service_pb2_grpc.py +0 -104
- union/_resources.py +0 -226
- union/_retry.py +0 -32
- union/_reusable_environment.py +0 -25
- union/_run.py +0 -374
- union/_secret.py +0 -61
- union/_task.py +0 -354
- union/_task_environment.py +0 -186
- union/_timeout.py +0 -47
- union/_tools.py +0 -27
- union/_utils/__init__.py +0 -11
- union/_utils/asyn.py +0 -119
- union/_utils/file_handling.py +0 -71
- union/_utils/helpers.py +0 -46
- union/_utils/lazy_module.py +0 -54
- union/_utils/uv_script_parser.py +0 -49
- union/_version.py +0 -21
- union/connectors/__init__.py +0 -0
- union/errors.py +0 -128
- union/extras/__init__.py +0 -5
- union/extras/_container.py +0 -263
- union/io/__init__.py +0 -11
- union/io/_dataframe.py +0 -0
- union/io/_dir.py +0 -425
- union/io/_file.py +0 -418
- union/io/pickle/__init__.py +0 -0
- union/io/pickle/transformer.py +0 -117
- union/io/structured_dataset/__init__.py +0 -122
- union/io/structured_dataset/basic_dfs.py +0 -219
- union/io/structured_dataset/structured_dataset.py +0 -1057
- union/py.typed +0 -0
- union/remote/__init__.py +0 -23
- union/remote/_client/__init__.py +0 -0
- union/remote/_client/_protocols.py +0 -129
- union/remote/_client/auth/__init__.py +0 -12
- union/remote/_client/auth/_authenticators/__init__.py +0 -0
- union/remote/_client/auth/_authenticators/base.py +0 -391
- union/remote/_client/auth/_authenticators/client_credentials.py +0 -73
- union/remote/_client/auth/_authenticators/device_code.py +0 -120
- union/remote/_client/auth/_authenticators/external_command.py +0 -77
- union/remote/_client/auth/_authenticators/factory.py +0 -200
- union/remote/_client/auth/_authenticators/pkce.py +0 -515
- union/remote/_client/auth/_channel.py +0 -184
- union/remote/_client/auth/_client_config.py +0 -83
- union/remote/_client/auth/_default_html.py +0 -32
- union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- union/remote/_client/auth/_grpc_utils/auth_interceptor.py +0 -204
- union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +0 -144
- union/remote/_client/auth/_keyring.py +0 -154
- union/remote/_client/auth/_token_client.py +0 -258
- union/remote/_client/auth/errors.py +0 -16
- union/remote/_client/controlplane.py +0 -86
- union/remote/_data.py +0 -149
- union/remote/_logs.py +0 -74
- union/remote/_project.py +0 -86
- union/remote/_run.py +0 -820
- union/remote/_secret.py +0 -132
- union/remote/_task.py +0 -193
- union/report/__init__.py +0 -3
- union/report/_report.py +0 -178
- union/report/_template.html +0 -124
- union/storage/__init__.py +0 -24
- union/storage/_remote_fs.py +0 -34
- union/storage/_storage.py +0 -247
- union/storage/_utils.py +0 -5
- union/types/__init__.py +0 -11
- union/types/_renderer.py +0 -162
- union/types/_string_literals.py +0 -120
- union/types/_type_engine.py +0 -2131
- union/types/_utils.py +0 -80
- /union/_protos/common/authorization_pb2_grpc.py → /flyte/_protos/workflow/common_pb2_grpc.py +0 -0
- /union/_protos/common/identifier_pb2_grpc.py → /flyte/_protos/workflow/environment_pb2_grpc.py +0 -0
- /flyte/io/{structured_dataset → _structured_dataset}/__init__.py +0 -0
- {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/WHEEL +0 -0
- {flyte-0.0.1b3.dist-info → flyte-0.2.0a0.dist-info}/top_level.txt +0 -0
flyte/_task.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import weakref
|
|
4
5
|
from dataclasses import dataclass, field, replace
|
|
5
6
|
from functools import cached_property
|
|
7
|
+
from inspect import iscoroutinefunction
|
|
6
8
|
from typing import (
|
|
7
9
|
TYPE_CHECKING,
|
|
8
10
|
Any,
|
|
9
|
-
Awaitable,
|
|
10
11
|
Callable,
|
|
11
12
|
Coroutine,
|
|
12
13
|
Dict,
|
|
@@ -15,17 +16,18 @@ from typing import (
|
|
|
15
16
|
Literal,
|
|
16
17
|
Optional,
|
|
17
18
|
ParamSpec,
|
|
19
|
+
TypeAlias,
|
|
18
20
|
TypeVar,
|
|
19
21
|
Union,
|
|
20
22
|
)
|
|
21
23
|
|
|
22
24
|
from flyteidl.core.tasks_pb2 import DataLoadingConfig
|
|
23
25
|
|
|
26
|
+
from flyte._pod import PodTemplate
|
|
24
27
|
from flyte.errors import RuntimeSystemError, RuntimeUserError
|
|
25
28
|
|
|
26
29
|
from ._cache import Cache, CacheRequest
|
|
27
30
|
from ._context import internal_ctx
|
|
28
|
-
from ._datastructures import NativeInterface, SerializationContext
|
|
29
31
|
from ._doc import Documentation
|
|
30
32
|
from ._image import Image
|
|
31
33
|
from ._resources import Resources
|
|
@@ -33,15 +35,18 @@ from ._retry import RetryStrategy
|
|
|
33
35
|
from ._reusable_environment import ReusePolicy
|
|
34
36
|
from ._secret import SecretRequest
|
|
35
37
|
from ._timeout import TimeoutType
|
|
38
|
+
from .models import NativeInterface, SerializationContext
|
|
36
39
|
|
|
37
40
|
if TYPE_CHECKING:
|
|
38
|
-
from kubernetes.client import V1PodTemplate
|
|
39
|
-
|
|
40
41
|
from ._task_environment import TaskEnvironment
|
|
41
42
|
|
|
42
43
|
P = ParamSpec("P") # capture the function's parameters
|
|
43
44
|
R = TypeVar("R") # return type
|
|
44
45
|
|
|
46
|
+
AsyncFunctionType: TypeAlias = Callable[P, Coroutine[Any, Any, R]]
|
|
47
|
+
SyncFunctionType: TypeAlias = Callable[P, R]
|
|
48
|
+
FunctionTypes: TypeAlias = Union[AsyncFunctionType, SyncFunctionType]
|
|
49
|
+
|
|
45
50
|
|
|
46
51
|
@dataclass(kw_only=True)
|
|
47
52
|
class TaskTemplate(Generic[P, R]):
|
|
@@ -78,6 +83,7 @@ class TaskTemplate(Generic[P, R]):
|
|
|
78
83
|
|
|
79
84
|
name: str
|
|
80
85
|
interface: NativeInterface
|
|
86
|
+
friendly_name: str = ""
|
|
81
87
|
task_type: str = "python"
|
|
82
88
|
task_type_version: int = 0
|
|
83
89
|
image: Union[str, Image, Literal["auto"]] = "auto"
|
|
@@ -90,24 +96,17 @@ class TaskTemplate(Generic[P, R]):
|
|
|
90
96
|
env: Optional[Dict[str, str]] = None
|
|
91
97
|
secrets: Optional[SecretRequest] = None
|
|
92
98
|
timeout: Optional[TimeoutType] = None
|
|
93
|
-
|
|
94
|
-
pod_template: Optional[Union[str, V1PodTemplate]] = None
|
|
99
|
+
pod_template: Optional[Union[str, PodTemplate]] = None
|
|
95
100
|
report: bool = False
|
|
96
101
|
|
|
97
102
|
parent_env: Optional[weakref.ReferenceType[TaskEnvironment]] = None
|
|
98
103
|
local: bool = field(default=False, init=False)
|
|
99
104
|
ref: bool = field(default=False, init=False, repr=False, compare=False)
|
|
100
105
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if self.pod_template is not None and not isinstance(self.pod_template, str):
|
|
104
|
-
try:
|
|
105
|
-
from kubernetes.client import V1PodTemplate # noqa: F401
|
|
106
|
-
except ImportError as e:
|
|
107
|
-
raise ImportError(
|
|
108
|
-
"kubernetes is not installed, please install kubernetes package to use pod_template"
|
|
109
|
-
) from e
|
|
106
|
+
# Only used in python 3.10 and 3.11, where we cannot use markcoroutinefunction
|
|
107
|
+
_call_as_synchronous: bool = False
|
|
110
108
|
|
|
109
|
+
def __post_init__(self):
|
|
111
110
|
# Auto set the image based on the image request
|
|
112
111
|
if self.image == "auto":
|
|
113
112
|
self.image = Image.auto()
|
|
@@ -128,6 +127,10 @@ class TaskTemplate(Generic[P, R]):
|
|
|
128
127
|
if isinstance(self.retries, int):
|
|
129
128
|
self.retries = RetryStrategy(count=self.retries)
|
|
130
129
|
|
|
130
|
+
if self.friendly_name == "":
|
|
131
|
+
# If friendly_name is not set, use the name of the task
|
|
132
|
+
self.friendly_name = self.name
|
|
133
|
+
|
|
131
134
|
def __getstate__(self):
|
|
132
135
|
"""
|
|
133
136
|
This method is called when the object is pickled. We need to remove the parent_env reference
|
|
@@ -208,13 +211,60 @@ class TaskTemplate(Generic[P, R]):
|
|
|
208
211
|
def native_interface(self) -> NativeInterface:
|
|
209
212
|
return self.interface
|
|
210
213
|
|
|
211
|
-
async def
|
|
214
|
+
async def aio(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
|
|
215
|
+
"""
|
|
216
|
+
The aio function allows executing "sync" tasks, in an async context. This helps with migrating v1 defined sync
|
|
217
|
+
tasks to be used within an asyncio parent task.
|
|
218
|
+
This function will also re-raise exceptions from the underlying task.
|
|
219
|
+
|
|
220
|
+
Example:
|
|
221
|
+
```python
|
|
222
|
+
@env.task
|
|
223
|
+
def my_legacy_task(x: int) -> int:
|
|
224
|
+
return x
|
|
225
|
+
|
|
226
|
+
@env.task
|
|
227
|
+
async def my_new_parent_task(n: int) -> List[int]:
|
|
228
|
+
collect = []
|
|
229
|
+
for x in range(n):
|
|
230
|
+
collect.append(my_legacy_task.aio(x))
|
|
231
|
+
return asyncio.gather(*collect)
|
|
232
|
+
```
|
|
233
|
+
:param args:
|
|
234
|
+
:param kwargs:
|
|
235
|
+
:return:
|
|
236
|
+
"""
|
|
237
|
+
|
|
238
|
+
ctx = internal_ctx()
|
|
239
|
+
if ctx.is_task_context():
|
|
240
|
+
from ._internal.controllers import get_controller
|
|
241
|
+
|
|
242
|
+
# If we are in a task context, that implies we are executing a Run.
|
|
243
|
+
# In this scenario, we should submit the task to the controller.
|
|
244
|
+
controller = get_controller()
|
|
245
|
+
if controller:
|
|
246
|
+
if self._call_as_synchronous:
|
|
247
|
+
fut = controller.submit_sync(self, *args, **kwargs)
|
|
248
|
+
asyncio_future = asyncio.wrap_future(fut) # Wrap the future to make it awaitable
|
|
249
|
+
return await asyncio_future
|
|
250
|
+
else:
|
|
251
|
+
return await controller.submit(self, *args, **kwargs)
|
|
252
|
+
else:
|
|
253
|
+
raise RuntimeSystemError("BadContext", "Controller is not initialized.")
|
|
254
|
+
else:
|
|
255
|
+
# Local execute, just stay out of the way, but because .aio is used, we want to return an awaitable,
|
|
256
|
+
# even for synchronous tasks. This is to support migration.
|
|
257
|
+
return self.forward(*args, **kwargs)
|
|
258
|
+
|
|
259
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
|
|
212
260
|
"""
|
|
213
261
|
This is the entrypoint for an async function task at runtime. It will be called during an execution.
|
|
214
262
|
Please do not override this method, if you simply want to modify the execution behavior, override the
|
|
215
263
|
execute method.
|
|
216
264
|
|
|
217
|
-
|
|
265
|
+
This needs to be overridable to maybe be async.
|
|
266
|
+
The returned thing from here needs to be an awaitable if the underlying task is async, and a regular object
|
|
267
|
+
if the task is not.
|
|
218
268
|
"""
|
|
219
269
|
try:
|
|
220
270
|
ctx = internal_ctx()
|
|
@@ -224,10 +274,19 @@ class TaskTemplate(Generic[P, R]):
|
|
|
224
274
|
# We will also check if we are not initialized, It is not expected to be not initialized
|
|
225
275
|
from ._internal.controllers import get_controller
|
|
226
276
|
|
|
227
|
-
controller =
|
|
228
|
-
if controller:
|
|
229
|
-
|
|
230
|
-
|
|
277
|
+
controller = get_controller()
|
|
278
|
+
if not controller:
|
|
279
|
+
raise RuntimeSystemError("BadContext", "Controller is not initialized.")
|
|
280
|
+
|
|
281
|
+
if self._call_as_synchronous:
|
|
282
|
+
fut = controller.submit_sync(self, *args, **kwargs)
|
|
283
|
+
x = fut.result(None)
|
|
284
|
+
return x
|
|
285
|
+
else:
|
|
286
|
+
return controller.submit(self, *args, **kwargs)
|
|
287
|
+
else:
|
|
288
|
+
# If not in task context, purely function run, stay out of the way
|
|
289
|
+
return self.forward(*args, **kwargs)
|
|
231
290
|
except RuntimeSystemError:
|
|
232
291
|
raise
|
|
233
292
|
except RuntimeUserError:
|
|
@@ -235,6 +294,17 @@ class TaskTemplate(Generic[P, R]):
|
|
|
235
294
|
except Exception as e:
|
|
236
295
|
raise RuntimeUserError(type(e).__name__, str(e)) from e
|
|
237
296
|
|
|
297
|
+
def forward(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
|
|
298
|
+
"""
|
|
299
|
+
Think of this as a local execute method for your task. This function will be invoked by the __call__ method
|
|
300
|
+
when not in a Flyte task execution context. See the implementation below for an example.
|
|
301
|
+
|
|
302
|
+
:param args:
|
|
303
|
+
:param kwargs:
|
|
304
|
+
:return:
|
|
305
|
+
"""
|
|
306
|
+
raise NotImplementedError
|
|
307
|
+
|
|
238
308
|
def override(
|
|
239
309
|
self,
|
|
240
310
|
*,
|
|
@@ -290,26 +360,38 @@ class AsyncFunctionTaskTemplate(TaskTemplate[P, R]):
|
|
|
290
360
|
is decorated with the task decorator.
|
|
291
361
|
"""
|
|
292
362
|
|
|
293
|
-
func:
|
|
363
|
+
func: FunctionTypes
|
|
364
|
+
|
|
365
|
+
def __post_init__(self):
|
|
366
|
+
super().__post_init__()
|
|
367
|
+
if not iscoroutinefunction(self.func):
|
|
368
|
+
self._call_as_synchronous = True
|
|
294
369
|
|
|
295
370
|
@cached_property
|
|
296
371
|
def native_interface(self) -> NativeInterface:
|
|
297
372
|
return NativeInterface.from_callable(self.func)
|
|
298
373
|
|
|
374
|
+
def forward(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R] | R:
|
|
375
|
+
# In local execution, we want to just call the function. Note we're not awaiting anything here.
|
|
376
|
+
# If the function was a coroutine function, the coroutine is returned and the await that the caller has
|
|
377
|
+
# in front of the task invocation will handle the awaiting.
|
|
378
|
+
return self.func(*args, **kwargs)
|
|
379
|
+
|
|
299
380
|
async def execute(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
300
381
|
"""
|
|
301
382
|
This is the execute method that will be called when the task is invoked. It will call the actual function.
|
|
302
383
|
# TODO We may need to keep this as the bare func execute, and need a pre and post execute some other func.
|
|
303
384
|
"""
|
|
385
|
+
|
|
304
386
|
ctx = internal_ctx()
|
|
387
|
+
assert ctx.data.task_context is not None, "Function should have already returned if not in a task context"
|
|
305
388
|
ctx_data = await self.pre(*args, **kwargs)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
389
|
+
tctx = ctx.data.task_context.replace(data=ctx_data)
|
|
390
|
+
with ctx.replace_task_context(tctx):
|
|
391
|
+
if iscoroutinefunction(self.func):
|
|
309
392
|
v = await self.func(*args, **kwargs)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
v = await self.func(*args, **kwargs)
|
|
393
|
+
else:
|
|
394
|
+
v = self.func(*args, **kwargs)
|
|
313
395
|
await self.post(v)
|
|
314
396
|
return v
|
|
315
397
|
|
flyte/_task_environment.py
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
import weakref
|
|
5
4
|
from dataclasses import dataclass, field, replace
|
|
6
5
|
from datetime import timedelta
|
|
7
|
-
from
|
|
8
|
-
|
|
6
|
+
from typing import (
|
|
7
|
+
TYPE_CHECKING,
|
|
8
|
+
Any,
|
|
9
|
+
Callable,
|
|
10
|
+
Dict,
|
|
11
|
+
List,
|
|
12
|
+
Literal,
|
|
13
|
+
Optional,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
)
|
|
9
17
|
|
|
10
18
|
import rich.repr
|
|
11
19
|
|
|
12
20
|
from ._cache import CacheRequest
|
|
13
|
-
from ._datastructures import NativeInterface
|
|
14
21
|
from ._doc import Documentation
|
|
15
22
|
from ._environment import Environment
|
|
16
23
|
from ._image import Image
|
|
@@ -19,12 +26,12 @@ from ._retry import RetryStrategy
|
|
|
19
26
|
from ._reusable_environment import ReusePolicy
|
|
20
27
|
from ._secret import SecretRequest
|
|
21
28
|
from ._task import AsyncFunctionTaskTemplate, TaskTemplate
|
|
29
|
+
from .models import NativeInterface
|
|
22
30
|
|
|
23
31
|
if TYPE_CHECKING:
|
|
24
32
|
from kubernetes.client import V1PodTemplate
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
R = TypeVar("R") # return type
|
|
34
|
+
from ._task import FunctionTypes, P, R
|
|
28
35
|
|
|
29
36
|
|
|
30
37
|
@rich.repr.auto
|
|
@@ -47,14 +54,14 @@ class TaskEnvironment(Environment):
|
|
|
47
54
|
:param resources: Resources to allocate for the environment.
|
|
48
55
|
:param env: Environment variables to set for the environment.
|
|
49
56
|
:param secrets: Secrets to inject into the environment.
|
|
50
|
-
:param
|
|
57
|
+
:param depends_on: Environment dependencies to hint, so when you deploy the environment, the dependencies are
|
|
51
58
|
also deployed. This is useful when you have a set of environments that depend on each other.
|
|
52
59
|
:param cache: Cache policy for the environment.
|
|
53
60
|
:param reusable: Reuse policy for the environment, if set, a python process may be reused for multiple tasks.
|
|
54
61
|
"""
|
|
55
62
|
|
|
56
63
|
cache: Union[CacheRequest] = "auto"
|
|
57
|
-
reusable:
|
|
64
|
+
reusable: ReusePolicy | None = None
|
|
58
65
|
# TODO Shall we make this union of string or env? This way we can lookup the env by module/file:name
|
|
59
66
|
# TODO also we could add list of files that are used by this environment
|
|
60
67
|
|
|
@@ -65,32 +72,42 @@ class TaskEnvironment(Environment):
|
|
|
65
72
|
name: str,
|
|
66
73
|
image: Optional[Union[str, Image, Literal["auto"]]] = None,
|
|
67
74
|
resources: Optional[Resources] = None,
|
|
68
|
-
cache: Union[CacheRequest, None] = None,
|
|
69
75
|
env: Optional[Dict[str, str]] = None,
|
|
70
|
-
reusable: Union[ReusePolicy, None] = None,
|
|
71
76
|
secrets: Optional[SecretRequest] = None,
|
|
72
|
-
|
|
77
|
+
depends_on: Optional[List[Environment]] = None,
|
|
78
|
+
**kwargs: Any,
|
|
73
79
|
) -> TaskEnvironment:
|
|
74
80
|
"""
|
|
75
|
-
Clone the
|
|
81
|
+
Clone the TaskEnvironment with new parameters.
|
|
82
|
+
besides the base environment parameters, you can override, kwargs like `cache`, `reusable`, etc.
|
|
83
|
+
|
|
76
84
|
"""
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
cache = kwargs.pop("cache", None)
|
|
86
|
+
reusable = kwargs.pop("reusable", None)
|
|
87
|
+
|
|
88
|
+
# validate unknown kwargs if needed
|
|
89
|
+
if kwargs:
|
|
90
|
+
raise TypeError(f"Unexpected keyword arguments: {list(kwargs.keys())}")
|
|
91
|
+
|
|
92
|
+
kwargs = self._get_kwargs()
|
|
93
|
+
kwargs["name"] = name
|
|
94
|
+
if image is not None:
|
|
95
|
+
kwargs["image"] = image
|
|
96
|
+
if resources is not None:
|
|
97
|
+
kwargs["resources"] = resources
|
|
98
|
+
if cache is not None:
|
|
99
|
+
kwargs["cache"] = cache
|
|
100
|
+
if env is not None:
|
|
101
|
+
kwargs["env"] = env
|
|
102
|
+
if reusable is not None:
|
|
103
|
+
kwargs["reusable"] = reusable
|
|
104
|
+
if secrets is not None:
|
|
105
|
+
kwargs["secrets"] = secrets
|
|
106
|
+
if depends_on is not None:
|
|
107
|
+
kwargs["depends_on"] = depends_on
|
|
108
|
+
return replace(self, **kwargs)
|
|
109
|
+
|
|
110
|
+
def task(
|
|
94
111
|
self,
|
|
95
112
|
_func=None,
|
|
96
113
|
*,
|
|
@@ -104,7 +121,8 @@ class TaskEnvironment(Environment):
|
|
|
104
121
|
report: bool = False,
|
|
105
122
|
) -> Union[AsyncFunctionTaskTemplate, Callable[P, R]]:
|
|
106
123
|
"""
|
|
107
|
-
:param
|
|
124
|
+
:param _func: Optional The function to decorate. If not provided, the decorator will return a callable that
|
|
125
|
+
:param name: Optional A friendly name for the task (defaults to the function name)
|
|
108
126
|
:param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the
|
|
109
127
|
task.
|
|
110
128
|
:param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
|
|
@@ -119,25 +137,12 @@ class TaskEnvironment(Environment):
|
|
|
119
137
|
if pod_template is not None:
|
|
120
138
|
raise ValueError("Cannot set pod_template when environment is reusable.")
|
|
121
139
|
|
|
122
|
-
def decorator(func:
|
|
123
|
-
|
|
124
|
-
task_name = self.name + "." +
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
@wraps(func)
|
|
130
|
-
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
131
|
-
return await func(*args, **kwargs)
|
|
132
|
-
|
|
133
|
-
if not asyncio.iscoroutinefunction(func):
|
|
134
|
-
raise TypeError(
|
|
135
|
-
f"Function {func.__name__} is not a coroutine function. Use @env.task decorator for async tasks."
|
|
136
|
-
f"You can simply mark your function as async def {func.__name__} to make it a coroutine function, "
|
|
137
|
-
f"it is ok to write sync code in async functions, but not the other way around."
|
|
138
|
-
)
|
|
139
|
-
tmpl = AsyncFunctionTaskTemplate(
|
|
140
|
-
func=wrapper,
|
|
140
|
+
def decorator(func: FunctionTypes) -> AsyncFunctionTaskTemplate[P, R]:
|
|
141
|
+
friendly_name = name or func.__name__
|
|
142
|
+
task_name = self.name + "." + func.__name__
|
|
143
|
+
|
|
144
|
+
tmpl: AsyncFunctionTaskTemplate = AsyncFunctionTaskTemplate(
|
|
145
|
+
func=func,
|
|
141
146
|
name=task_name,
|
|
142
147
|
image=self.image,
|
|
143
148
|
resources=self.resources,
|
|
@@ -152,6 +157,7 @@ class TaskEnvironment(Environment):
|
|
|
152
157
|
parent_env=weakref.ref(self),
|
|
153
158
|
interface=NativeInterface.from_callable(func),
|
|
154
159
|
report=report,
|
|
160
|
+
friendly_name=friendly_name,
|
|
155
161
|
)
|
|
156
162
|
self._tasks[task_name] = tmpl
|
|
157
163
|
return tmpl
|
|
@@ -160,29 +166,6 @@ class TaskEnvironment(Environment):
|
|
|
160
166
|
return cast(AsyncFunctionTaskTemplate, decorator)
|
|
161
167
|
return cast(AsyncFunctionTaskTemplate, decorator(_func))
|
|
162
168
|
|
|
163
|
-
@property
|
|
164
|
-
def task(self) -> Callable:
|
|
165
|
-
"""
|
|
166
|
-
Decorator to create a new task with the environment settings.
|
|
167
|
-
The task will be executed in its own container with the specified image, resources, and environment variables,
|
|
168
|
-
unless reusePolicy is set, in which case the same container will be reused for all tasks with the same
|
|
169
|
-
environment settings.
|
|
170
|
-
|
|
171
|
-
:param name: Optional The name of the task (defaults to the function name)
|
|
172
|
-
:param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the
|
|
173
|
-
task.
|
|
174
|
-
:param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
|
|
175
|
-
:param docs: Optional The documentation for the task, if not provided the function docstring will be used.
|
|
176
|
-
:param secrets: Optional The secrets that will be injected into the task at runtime.
|
|
177
|
-
:param timeout: Optional The timeout for the task.
|
|
178
|
-
:param pod_template: Optional The pod template for the task, if not provided the default pod template will be
|
|
179
|
-
used.
|
|
180
|
-
:param report: Optional Whether to generate the html report for the task, defaults to False.
|
|
181
|
-
|
|
182
|
-
:return: New Task instance or Task decorator
|
|
183
|
-
"""
|
|
184
|
-
return self._task
|
|
185
|
-
|
|
186
169
|
@property
|
|
187
170
|
def tasks(self) -> Dict[str, TaskTemplate]:
|
|
188
171
|
"""
|
flyte/_trace.py
CHANGED
|
@@ -4,7 +4,7 @@ import time
|
|
|
4
4
|
from datetime import timedelta
|
|
5
5
|
from typing import Any, AsyncGenerator, AsyncIterator, Awaitable, Callable, TypeGuard, TypeVar, Union, cast
|
|
6
6
|
|
|
7
|
-
from flyte.
|
|
7
|
+
from flyte.models import NativeInterface
|
|
8
8
|
|
|
9
9
|
T = TypeVar("T")
|
|
10
10
|
|
|
@@ -14,7 +14,6 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
|
|
|
14
14
|
A decorator that traces function execution with timing information.
|
|
15
15
|
Works with regular functions, async functions, and async generators/iterators.
|
|
16
16
|
"""
|
|
17
|
-
func_name = func.__name__
|
|
18
17
|
|
|
19
18
|
@functools.wraps(func)
|
|
20
19
|
def wrapper_sync(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -31,9 +30,9 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
|
|
|
31
30
|
# We will also check if we are not initialized, It is not expected to be not initialized
|
|
32
31
|
from ._internal.controllers import get_controller
|
|
33
32
|
|
|
34
|
-
controller =
|
|
33
|
+
controller = get_controller()
|
|
35
34
|
iface = NativeInterface.from_callable(func)
|
|
36
|
-
info, ok = await controller.get_action_outputs(iface,
|
|
35
|
+
info, ok = await controller.get_action_outputs(iface, func, *args, **kwargs)
|
|
37
36
|
if ok:
|
|
38
37
|
if info.output:
|
|
39
38
|
return info.output
|
|
@@ -74,9 +73,9 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
|
|
|
74
73
|
# We will also check if we are not initialized, It is not expected to be not initialized
|
|
75
74
|
from ._internal.controllers import get_controller
|
|
76
75
|
|
|
77
|
-
controller =
|
|
76
|
+
controller = get_controller()
|
|
78
77
|
iface = NativeInterface.from_callable(func)
|
|
79
|
-
info, ok = await controller.get_action_outputs(iface,
|
|
78
|
+
info, ok = await controller.get_action_outputs(iface, func, *args, **kwargs)
|
|
80
79
|
if ok:
|
|
81
80
|
if info.output:
|
|
82
81
|
for item in info.output:
|
|
@@ -88,17 +87,12 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
|
|
|
88
87
|
items = []
|
|
89
88
|
result = func(*args, **kwargs)
|
|
90
89
|
# TODO ideally we should use streaming into the type-engine so that it stream uploads large blocks
|
|
91
|
-
if inspect.isasyncgen(result):
|
|
90
|
+
if inspect.isasyncgen(result) or is_async_iterable(result):
|
|
92
91
|
# If it's directly an async generator
|
|
93
92
|
async_iter = result
|
|
94
93
|
async for item in async_iter:
|
|
95
94
|
items.append(item)
|
|
96
95
|
yield item
|
|
97
|
-
elif is_async_iterable(result):
|
|
98
|
-
# If it's an async iterable (has __aiter__)
|
|
99
|
-
async for item in result:
|
|
100
|
-
items.append(item)
|
|
101
|
-
yield item
|
|
102
96
|
duration = time.time() - start_time
|
|
103
97
|
info.add_outputs(items, timedelta(seconds=duration))
|
|
104
98
|
await controller.record_trace(info)
|
|
@@ -118,10 +112,8 @@ def trace(func: Callable[..., T]) -> Callable[..., T]:
|
|
|
118
112
|
# Choose the appropriate wrapper based on the function type
|
|
119
113
|
if inspect.iscoroutinefunction(func):
|
|
120
114
|
# This handles async functions that return normal values
|
|
121
|
-
print(f"Coroutine function {func.__name__}")
|
|
122
115
|
return cast(Callable[..., T], wrapper_async)
|
|
123
116
|
elif inspect.isasyncgenfunction(func):
|
|
124
|
-
print(f"Async generator function {func.__name__}")
|
|
125
117
|
return cast(Callable[..., T], wrapper_async_iterator)
|
|
126
118
|
else:
|
|
127
119
|
# For regular sync functions
|
flyte/_utils/__init__.py
CHANGED
|
@@ -4,17 +4,23 @@ Internal utility functions.
|
|
|
4
4
|
Except for logging, modules in this package should not depend on any other part of the repo.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
from .async_cache import AsyncLRUCache
|
|
7
8
|
from .coro_management import run_coros
|
|
8
9
|
from .file_handling import filehash_update, update_hasher_for_source
|
|
9
10
|
from .helpers import get_cwd_editable_install
|
|
10
11
|
from .lazy_module import lazy_module
|
|
12
|
+
from .org_discovery import hostname_from_url, org_from_endpoint, sanitize_endpoint
|
|
11
13
|
from .uv_script_parser import parse_uv_script_file
|
|
12
14
|
|
|
13
15
|
__all__ = [
|
|
16
|
+
"AsyncLRUCache",
|
|
14
17
|
"filehash_update",
|
|
15
18
|
"get_cwd_editable_install",
|
|
19
|
+
"hostname_from_url",
|
|
16
20
|
"lazy_module",
|
|
21
|
+
"org_from_endpoint",
|
|
17
22
|
"parse_uv_script_file",
|
|
18
23
|
"run_coros",
|
|
24
|
+
"sanitize_endpoint",
|
|
19
25
|
"update_hasher_for_source",
|
|
20
26
|
]
|