flyte 0.0.1b0__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 +62 -0
- flyte/_api_commons.py +3 -0
- flyte/_bin/__init__.py +0 -0
- flyte/_bin/runtime.py +126 -0
- flyte/_build.py +25 -0
- flyte/_cache/__init__.py +12 -0
- flyte/_cache/cache.py +146 -0
- flyte/_cache/defaults.py +9 -0
- flyte/_cache/policy_function_body.py +42 -0
- flyte/_cli/__init__.py +0 -0
- flyte/_cli/_common.py +287 -0
- flyte/_cli/_create.py +42 -0
- flyte/_cli/_delete.py +23 -0
- flyte/_cli/_deploy.py +140 -0
- flyte/_cli/_get.py +235 -0
- flyte/_cli/_run.py +152 -0
- flyte/_cli/main.py +72 -0
- flyte/_code_bundle/__init__.py +8 -0
- flyte/_code_bundle/_ignore.py +113 -0
- flyte/_code_bundle/_packaging.py +187 -0
- flyte/_code_bundle/_utils.py +339 -0
- flyte/_code_bundle/bundle.py +178 -0
- flyte/_context.py +146 -0
- flyte/_datastructures.py +342 -0
- flyte/_deploy.py +202 -0
- flyte/_doc.py +29 -0
- flyte/_docstring.py +32 -0
- flyte/_environment.py +43 -0
- flyte/_group.py +31 -0
- flyte/_hash.py +23 -0
- flyte/_image.py +760 -0
- flyte/_initialize.py +634 -0
- flyte/_interface.py +84 -0
- flyte/_internal/__init__.py +3 -0
- flyte/_internal/controllers/__init__.py +115 -0
- flyte/_internal/controllers/_local_controller.py +118 -0
- flyte/_internal/controllers/_trace.py +40 -0
- flyte/_internal/controllers/pbhash.py +39 -0
- flyte/_internal/controllers/remote/__init__.py +40 -0
- flyte/_internal/controllers/remote/_action.py +141 -0
- flyte/_internal/controllers/remote/_client.py +43 -0
- flyte/_internal/controllers/remote/_controller.py +361 -0
- flyte/_internal/controllers/remote/_core.py +402 -0
- flyte/_internal/controllers/remote/_informer.py +361 -0
- flyte/_internal/controllers/remote/_service_protocol.py +50 -0
- flyte/_internal/imagebuild/__init__.py +11 -0
- flyte/_internal/imagebuild/docker_builder.py +416 -0
- flyte/_internal/imagebuild/image_builder.py +241 -0
- flyte/_internal/imagebuild/remote_builder.py +0 -0
- flyte/_internal/resolvers/__init__.py +0 -0
- flyte/_internal/resolvers/_task_module.py +54 -0
- flyte/_internal/resolvers/common.py +31 -0
- flyte/_internal/resolvers/default.py +28 -0
- flyte/_internal/runtime/__init__.py +0 -0
- flyte/_internal/runtime/convert.py +199 -0
- flyte/_internal/runtime/entrypoints.py +135 -0
- flyte/_internal/runtime/io.py +136 -0
- flyte/_internal/runtime/resources_serde.py +138 -0
- flyte/_internal/runtime/task_serde.py +210 -0
- flyte/_internal/runtime/taskrunner.py +190 -0
- flyte/_internal/runtime/types_serde.py +54 -0
- flyte/_logging.py +124 -0
- flyte/_protos/__init__.py +0 -0
- flyte/_protos/common/authorization_pb2.py +66 -0
- flyte/_protos/common/authorization_pb2.pyi +108 -0
- flyte/_protos/common/authorization_pb2_grpc.py +4 -0
- flyte/_protos/common/identifier_pb2.py +71 -0
- flyte/_protos/common/identifier_pb2.pyi +82 -0
- flyte/_protos/common/identifier_pb2_grpc.py +4 -0
- flyte/_protos/common/identity_pb2.py +48 -0
- flyte/_protos/common/identity_pb2.pyi +72 -0
- flyte/_protos/common/identity_pb2_grpc.py +4 -0
- flyte/_protos/common/list_pb2.py +36 -0
- flyte/_protos/common/list_pb2.pyi +69 -0
- flyte/_protos/common/list_pb2_grpc.py +4 -0
- flyte/_protos/common/policy_pb2.py +37 -0
- flyte/_protos/common/policy_pb2.pyi +27 -0
- flyte/_protos/common/policy_pb2_grpc.py +4 -0
- flyte/_protos/common/role_pb2.py +37 -0
- flyte/_protos/common/role_pb2.pyi +53 -0
- flyte/_protos/common/role_pb2_grpc.py +4 -0
- flyte/_protos/common/runtime_version_pb2.py +28 -0
- flyte/_protos/common/runtime_version_pb2.pyi +24 -0
- flyte/_protos/common/runtime_version_pb2_grpc.py +4 -0
- flyte/_protos/logs/dataplane/payload_pb2.py +96 -0
- flyte/_protos/logs/dataplane/payload_pb2.pyi +168 -0
- flyte/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
- flyte/_protos/secret/definition_pb2.py +49 -0
- flyte/_protos/secret/definition_pb2.pyi +93 -0
- flyte/_protos/secret/definition_pb2_grpc.py +4 -0
- flyte/_protos/secret/payload_pb2.py +62 -0
- flyte/_protos/secret/payload_pb2.pyi +94 -0
- flyte/_protos/secret/payload_pb2_grpc.py +4 -0
- flyte/_protos/secret/secret_pb2.py +38 -0
- flyte/_protos/secret/secret_pb2.pyi +6 -0
- flyte/_protos/secret/secret_pb2_grpc.py +198 -0
- flyte/_protos/secret/secret_pb2_grpc_grpc.py +198 -0
- flyte/_protos/validate/validate/validate_pb2.py +76 -0
- flyte/_protos/workflow/node_execution_service_pb2.py +26 -0
- flyte/_protos/workflow/node_execution_service_pb2.pyi +4 -0
- flyte/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
- flyte/_protos/workflow/queue_service_pb2.py +106 -0
- flyte/_protos/workflow/queue_service_pb2.pyi +141 -0
- flyte/_protos/workflow/queue_service_pb2_grpc.py +172 -0
- flyte/_protos/workflow/run_definition_pb2.py +128 -0
- flyte/_protos/workflow/run_definition_pb2.pyi +310 -0
- flyte/_protos/workflow/run_definition_pb2_grpc.py +4 -0
- flyte/_protos/workflow/run_logs_service_pb2.py +41 -0
- flyte/_protos/workflow/run_logs_service_pb2.pyi +28 -0
- flyte/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
- flyte/_protos/workflow/run_service_pb2.py +133 -0
- flyte/_protos/workflow/run_service_pb2.pyi +175 -0
- flyte/_protos/workflow/run_service_pb2_grpc.py +412 -0
- flyte/_protos/workflow/state_service_pb2.py +58 -0
- flyte/_protos/workflow/state_service_pb2.pyi +71 -0
- flyte/_protos/workflow/state_service_pb2_grpc.py +138 -0
- flyte/_protos/workflow/task_definition_pb2.py +72 -0
- flyte/_protos/workflow/task_definition_pb2.pyi +65 -0
- flyte/_protos/workflow/task_definition_pb2_grpc.py +4 -0
- flyte/_protos/workflow/task_service_pb2.py +44 -0
- flyte/_protos/workflow/task_service_pb2.pyi +31 -0
- flyte/_protos/workflow/task_service_pb2_grpc.py +104 -0
- flyte/_resources.py +226 -0
- flyte/_retry.py +32 -0
- flyte/_reusable_environment.py +25 -0
- flyte/_run.py +411 -0
- flyte/_secret.py +61 -0
- flyte/_task.py +367 -0
- flyte/_task_environment.py +200 -0
- flyte/_timeout.py +47 -0
- flyte/_tools.py +27 -0
- flyte/_trace.py +128 -0
- flyte/_utils/__init__.py +20 -0
- flyte/_utils/asyn.py +119 -0
- flyte/_utils/coro_management.py +25 -0
- flyte/_utils/file_handling.py +72 -0
- flyte/_utils/helpers.py +108 -0
- flyte/_utils/lazy_module.py +54 -0
- flyte/_utils/uv_script_parser.py +49 -0
- flyte/_version.py +21 -0
- flyte/connectors/__init__.py +0 -0
- flyte/errors.py +143 -0
- flyte/extras/__init__.py +5 -0
- flyte/extras/_container.py +273 -0
- flyte/io/__init__.py +11 -0
- flyte/io/_dataframe.py +0 -0
- flyte/io/_dir.py +448 -0
- flyte/io/_file.py +468 -0
- flyte/io/pickle/__init__.py +0 -0
- flyte/io/pickle/transformer.py +117 -0
- flyte/io/structured_dataset/__init__.py +129 -0
- flyte/io/structured_dataset/basic_dfs.py +219 -0
- flyte/io/structured_dataset/structured_dataset.py +1061 -0
- flyte/py.typed +0 -0
- flyte/remote/__init__.py +25 -0
- flyte/remote/_client/__init__.py +0 -0
- flyte/remote/_client/_protocols.py +131 -0
- flyte/remote/_client/auth/__init__.py +12 -0
- flyte/remote/_client/auth/_authenticators/__init__.py +0 -0
- flyte/remote/_client/auth/_authenticators/base.py +397 -0
- flyte/remote/_client/auth/_authenticators/client_credentials.py +73 -0
- flyte/remote/_client/auth/_authenticators/device_code.py +118 -0
- flyte/remote/_client/auth/_authenticators/external_command.py +79 -0
- flyte/remote/_client/auth/_authenticators/factory.py +200 -0
- flyte/remote/_client/auth/_authenticators/pkce.py +516 -0
- flyte/remote/_client/auth/_channel.py +184 -0
- flyte/remote/_client/auth/_client_config.py +83 -0
- flyte/remote/_client/auth/_default_html.py +32 -0
- flyte/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- flyte/remote/_client/auth/_grpc_utils/auth_interceptor.py +288 -0
- flyte/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +151 -0
- flyte/remote/_client/auth/_keyring.py +143 -0
- flyte/remote/_client/auth/_token_client.py +260 -0
- flyte/remote/_client/auth/errors.py +16 -0
- flyte/remote/_client/controlplane.py +95 -0
- flyte/remote/_console.py +18 -0
- flyte/remote/_data.py +155 -0
- flyte/remote/_logs.py +116 -0
- flyte/remote/_project.py +86 -0
- flyte/remote/_run.py +873 -0
- flyte/remote/_secret.py +132 -0
- flyte/remote/_task.py +227 -0
- flyte/report/__init__.py +3 -0
- flyte/report/_report.py +178 -0
- flyte/report/_template.html +124 -0
- flyte/storage/__init__.py +24 -0
- flyte/storage/_remote_fs.py +34 -0
- flyte/storage/_storage.py +251 -0
- flyte/storage/_utils.py +5 -0
- flyte/types/__init__.py +13 -0
- flyte/types/_interface.py +25 -0
- flyte/types/_renderer.py +162 -0
- flyte/types/_string_literals.py +120 -0
- flyte/types/_type_engine.py +2210 -0
- flyte/types/_utils.py +80 -0
- flyte-0.0.1b0.dist-info/METADATA +179 -0
- flyte-0.0.1b0.dist-info/RECORD +390 -0
- flyte-0.0.1b0.dist-info/WHEEL +5 -0
- flyte-0.0.1b0.dist-info/entry_points.txt +3 -0
- flyte-0.0.1b0.dist-info/top_level.txt +1 -0
- union/__init__.py +54 -0
- union/_api_commons.py +3 -0
- union/_bin/__init__.py +0 -0
- union/_bin/runtime.py +113 -0
- union/_build.py +25 -0
- union/_cache/__init__.py +12 -0
- union/_cache/cache.py +141 -0
- union/_cache/defaults.py +9 -0
- union/_cache/policy_function_body.py +42 -0
- union/_cli/__init__.py +0 -0
- union/_cli/_common.py +263 -0
- union/_cli/_create.py +40 -0
- union/_cli/_delete.py +23 -0
- union/_cli/_deploy.py +120 -0
- union/_cli/_get.py +162 -0
- union/_cli/_params.py +579 -0
- union/_cli/_run.py +150 -0
- union/_cli/main.py +72 -0
- union/_code_bundle/__init__.py +8 -0
- union/_code_bundle/_ignore.py +113 -0
- union/_code_bundle/_packaging.py +187 -0
- union/_code_bundle/_utils.py +342 -0
- union/_code_bundle/bundle.py +176 -0
- union/_context.py +146 -0
- union/_datastructures.py +295 -0
- union/_deploy.py +185 -0
- union/_doc.py +29 -0
- union/_docstring.py +26 -0
- union/_environment.py +43 -0
- union/_group.py +31 -0
- union/_hash.py +23 -0
- union/_image.py +760 -0
- union/_initialize.py +585 -0
- union/_interface.py +84 -0
- union/_internal/__init__.py +3 -0
- union/_internal/controllers/__init__.py +77 -0
- union/_internal/controllers/_local_controller.py +77 -0
- union/_internal/controllers/pbhash.py +39 -0
- union/_internal/controllers/remote/__init__.py +40 -0
- union/_internal/controllers/remote/_action.py +131 -0
- union/_internal/controllers/remote/_client.py +43 -0
- union/_internal/controllers/remote/_controller.py +169 -0
- union/_internal/controllers/remote/_core.py +341 -0
- union/_internal/controllers/remote/_informer.py +260 -0
- union/_internal/controllers/remote/_service_protocol.py +44 -0
- union/_internal/imagebuild/__init__.py +11 -0
- union/_internal/imagebuild/docker_builder.py +416 -0
- union/_internal/imagebuild/image_builder.py +243 -0
- union/_internal/imagebuild/remote_builder.py +0 -0
- union/_internal/resolvers/__init__.py +0 -0
- union/_internal/resolvers/_task_module.py +31 -0
- union/_internal/resolvers/common.py +24 -0
- union/_internal/resolvers/default.py +27 -0
- union/_internal/runtime/__init__.py +0 -0
- union/_internal/runtime/convert.py +163 -0
- union/_internal/runtime/entrypoints.py +121 -0
- union/_internal/runtime/io.py +136 -0
- union/_internal/runtime/resources_serde.py +134 -0
- union/_internal/runtime/task_serde.py +202 -0
- union/_internal/runtime/taskrunner.py +179 -0
- union/_internal/runtime/types_serde.py +53 -0
- union/_logging.py +124 -0
- union/_protos/__init__.py +0 -0
- union/_protos/common/authorization_pb2.py +66 -0
- union/_protos/common/authorization_pb2.pyi +106 -0
- union/_protos/common/authorization_pb2_grpc.py +4 -0
- union/_protos/common/identifier_pb2.py +71 -0
- union/_protos/common/identifier_pb2.pyi +82 -0
- union/_protos/common/identifier_pb2_grpc.py +4 -0
- union/_protos/common/identity_pb2.py +48 -0
- union/_protos/common/identity_pb2.pyi +72 -0
- union/_protos/common/identity_pb2_grpc.py +4 -0
- union/_protos/common/list_pb2.py +36 -0
- union/_protos/common/list_pb2.pyi +69 -0
- union/_protos/common/list_pb2_grpc.py +4 -0
- union/_protos/common/policy_pb2.py +37 -0
- union/_protos/common/policy_pb2.pyi +27 -0
- union/_protos/common/policy_pb2_grpc.py +4 -0
- union/_protos/common/role_pb2.py +37 -0
- union/_protos/common/role_pb2.pyi +51 -0
- union/_protos/common/role_pb2_grpc.py +4 -0
- union/_protos/common/runtime_version_pb2.py +28 -0
- union/_protos/common/runtime_version_pb2.pyi +24 -0
- union/_protos/common/runtime_version_pb2_grpc.py +4 -0
- union/_protos/logs/dataplane/payload_pb2.py +96 -0
- union/_protos/logs/dataplane/payload_pb2.pyi +168 -0
- union/_protos/logs/dataplane/payload_pb2_grpc.py +4 -0
- union/_protos/secret/definition_pb2.py +49 -0
- union/_protos/secret/definition_pb2.pyi +93 -0
- union/_protos/secret/definition_pb2_grpc.py +4 -0
- union/_protos/secret/payload_pb2.py +62 -0
- union/_protos/secret/payload_pb2.pyi +94 -0
- union/_protos/secret/payload_pb2_grpc.py +4 -0
- union/_protos/secret/secret_pb2.py +38 -0
- union/_protos/secret/secret_pb2.pyi +6 -0
- union/_protos/secret/secret_pb2_grpc.py +198 -0
- union/_protos/validate/validate/validate_pb2.py +76 -0
- union/_protos/workflow/node_execution_service_pb2.py +26 -0
- union/_protos/workflow/node_execution_service_pb2.pyi +4 -0
- union/_protos/workflow/node_execution_service_pb2_grpc.py +32 -0
- union/_protos/workflow/queue_service_pb2.py +75 -0
- union/_protos/workflow/queue_service_pb2.pyi +103 -0
- union/_protos/workflow/queue_service_pb2_grpc.py +172 -0
- union/_protos/workflow/run_definition_pb2.py +100 -0
- union/_protos/workflow/run_definition_pb2.pyi +256 -0
- union/_protos/workflow/run_definition_pb2_grpc.py +4 -0
- union/_protos/workflow/run_logs_service_pb2.py +41 -0
- union/_protos/workflow/run_logs_service_pb2.pyi +28 -0
- union/_protos/workflow/run_logs_service_pb2_grpc.py +69 -0
- union/_protos/workflow/run_service_pb2.py +133 -0
- union/_protos/workflow/run_service_pb2.pyi +173 -0
- union/_protos/workflow/run_service_pb2_grpc.py +412 -0
- union/_protos/workflow/state_service_pb2.py +58 -0
- union/_protos/workflow/state_service_pb2.pyi +69 -0
- union/_protos/workflow/state_service_pb2_grpc.py +138 -0
- union/_protos/workflow/task_definition_pb2.py +72 -0
- union/_protos/workflow/task_definition_pb2.pyi +65 -0
- union/_protos/workflow/task_definition_pb2_grpc.py +4 -0
- union/_protos/workflow/task_service_pb2.py +44 -0
- union/_protos/workflow/task_service_pb2.pyi +31 -0
- union/_protos/workflow/task_service_pb2_grpc.py +104 -0
- union/_resources.py +226 -0
- union/_retry.py +32 -0
- union/_reusable_environment.py +25 -0
- union/_run.py +374 -0
- union/_secret.py +61 -0
- union/_task.py +354 -0
- union/_task_environment.py +186 -0
- union/_timeout.py +47 -0
- union/_tools.py +27 -0
- union/_utils/__init__.py +11 -0
- union/_utils/asyn.py +119 -0
- union/_utils/file_handling.py +71 -0
- union/_utils/helpers.py +46 -0
- union/_utils/lazy_module.py +54 -0
- union/_utils/uv_script_parser.py +49 -0
- union/_version.py +21 -0
- union/connectors/__init__.py +0 -0
- union/errors.py +128 -0
- union/extras/__init__.py +5 -0
- union/extras/_container.py +263 -0
- union/io/__init__.py +11 -0
- union/io/_dataframe.py +0 -0
- union/io/_dir.py +425 -0
- union/io/_file.py +418 -0
- union/io/pickle/__init__.py +0 -0
- union/io/pickle/transformer.py +117 -0
- union/io/structured_dataset/__init__.py +122 -0
- union/io/structured_dataset/basic_dfs.py +219 -0
- union/io/structured_dataset/structured_dataset.py +1057 -0
- union/py.typed +0 -0
- union/remote/__init__.py +23 -0
- union/remote/_client/__init__.py +0 -0
- union/remote/_client/_protocols.py +129 -0
- union/remote/_client/auth/__init__.py +12 -0
- union/remote/_client/auth/_authenticators/__init__.py +0 -0
- union/remote/_client/auth/_authenticators/base.py +391 -0
- union/remote/_client/auth/_authenticators/client_credentials.py +73 -0
- union/remote/_client/auth/_authenticators/device_code.py +120 -0
- union/remote/_client/auth/_authenticators/external_command.py +77 -0
- union/remote/_client/auth/_authenticators/factory.py +200 -0
- union/remote/_client/auth/_authenticators/pkce.py +515 -0
- union/remote/_client/auth/_channel.py +184 -0
- union/remote/_client/auth/_client_config.py +83 -0
- union/remote/_client/auth/_default_html.py +32 -0
- union/remote/_client/auth/_grpc_utils/__init__.py +0 -0
- union/remote/_client/auth/_grpc_utils/auth_interceptor.py +204 -0
- union/remote/_client/auth/_grpc_utils/default_metadata_interceptor.py +144 -0
- union/remote/_client/auth/_keyring.py +154 -0
- union/remote/_client/auth/_token_client.py +258 -0
- union/remote/_client/auth/errors.py +16 -0
- union/remote/_client/controlplane.py +86 -0
- union/remote/_data.py +149 -0
- union/remote/_logs.py +74 -0
- union/remote/_project.py +86 -0
- union/remote/_run.py +820 -0
- union/remote/_secret.py +132 -0
- union/remote/_task.py +193 -0
- union/report/__init__.py +3 -0
- union/report/_report.py +178 -0
- union/report/_template.html +124 -0
- union/storage/__init__.py +24 -0
- union/storage/_remote_fs.py +34 -0
- union/storage/_storage.py +247 -0
- union/storage/_utils.py +5 -0
- union/types/__init__.py +11 -0
- union/types/_renderer.py +162 -0
- union/types/_string_literals.py +120 -0
- union/types/_type_engine.py +2131 -0
- union/types/_utils.py +80 -0
flyte/_secret.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
import re
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional, Union
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Secret:
|
|
9
|
+
"""
|
|
10
|
+
Secrets are used to inject sensitive information into tasks. Secrets can be mounted as environment variables or
|
|
11
|
+
files. The secret key is the name of the secret in the secret store. The group is optional and maybe used with some
|
|
12
|
+
secret stores to organize secrets. The secret_mount is used to specify how the secret should be mounted. If the
|
|
13
|
+
secret_mount is set to "env" the secret will be mounted as an environment variable. If the secret_mount is set to
|
|
14
|
+
"file" the secret will be mounted as a file. The as_env_var is an optional parameter that can be used to specify the
|
|
15
|
+
name of the environment variable that the secret should be mounted as.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
```python
|
|
19
|
+
@task(secrets="MY_SECRET")
|
|
20
|
+
async def my_task():
|
|
21
|
+
os.environ["MY_SECRET"] # This will be set to the value of the secret
|
|
22
|
+
|
|
23
|
+
@task(secrets=Secret("MY_SECRET", mount="/path/to/secret"))
|
|
24
|
+
async def my_task2():
|
|
25
|
+
async with open("/path/to/secret") as f:
|
|
26
|
+
secret_value = f.read()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
TODO: Add support for secret versioning (some stores) and secret groups (some stores) and mounting as files.
|
|
30
|
+
|
|
31
|
+
:param key: The name of the secret in the secret store.
|
|
32
|
+
:param group: The group of the secret in the secret store.
|
|
33
|
+
:param mount: Use this to specify the path where the secret should be mounted.
|
|
34
|
+
:param as_env_var: The name of the environment variable that the secret should be mounted as.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
key: str
|
|
38
|
+
group: Optional[str] = None
|
|
39
|
+
mount: pathlib.Path | None = None
|
|
40
|
+
as_env_var: Optional[str] = None
|
|
41
|
+
|
|
42
|
+
def __post_init__(self):
|
|
43
|
+
if self.as_env_var is not None:
|
|
44
|
+
pattern = r"^[A-Z_][A-Z0-9_]*$"
|
|
45
|
+
if not re.match(pattern, self.as_env_var):
|
|
46
|
+
raise ValueError(f"Invalid environment variable name: {self.as_env_var}, must match {pattern}")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
SecretRequest = Union[str, Secret, List[str | Secret]]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def secrets_from_request(secrets: SecretRequest) -> List[Secret]:
|
|
53
|
+
"""
|
|
54
|
+
Converts a secret request into a list of secrets.
|
|
55
|
+
"""
|
|
56
|
+
if isinstance(secrets, str):
|
|
57
|
+
return [Secret(key=secrets)]
|
|
58
|
+
elif isinstance(secrets, Secret):
|
|
59
|
+
return [secrets]
|
|
60
|
+
else:
|
|
61
|
+
return [Secret(key=s) if isinstance(s, str) else s for s in secrets]
|
flyte/_task.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import weakref
|
|
4
|
+
from dataclasses import dataclass, field, replace
|
|
5
|
+
from functools import cached_property
|
|
6
|
+
from typing import (
|
|
7
|
+
TYPE_CHECKING,
|
|
8
|
+
Any,
|
|
9
|
+
Awaitable,
|
|
10
|
+
Callable,
|
|
11
|
+
Coroutine,
|
|
12
|
+
Dict,
|
|
13
|
+
Generic,
|
|
14
|
+
List,
|
|
15
|
+
Literal,
|
|
16
|
+
Optional,
|
|
17
|
+
ParamSpec,
|
|
18
|
+
TypeVar,
|
|
19
|
+
Union,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from flyteidl.core.tasks_pb2 import DataLoadingConfig
|
|
23
|
+
|
|
24
|
+
from flyte.errors import RuntimeSystemError, RuntimeUserError
|
|
25
|
+
|
|
26
|
+
from ._cache import Cache, CacheRequest
|
|
27
|
+
from ._context import internal_ctx
|
|
28
|
+
from ._datastructures import NativeInterface, SerializationContext
|
|
29
|
+
from ._doc import Documentation
|
|
30
|
+
from ._image import Image
|
|
31
|
+
from ._resources import Resources
|
|
32
|
+
from ._retry import RetryStrategy
|
|
33
|
+
from ._reusable_environment import ReusePolicy
|
|
34
|
+
from ._secret import SecretRequest
|
|
35
|
+
from ._timeout import TimeoutType
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from kubernetes.client import V1PodTemplate
|
|
39
|
+
|
|
40
|
+
from ._task_environment import TaskEnvironment
|
|
41
|
+
|
|
42
|
+
P = ParamSpec("P") # capture the function's parameters
|
|
43
|
+
R = TypeVar("R") # return type
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass(kw_only=True)
|
|
47
|
+
class TaskTemplate(Generic[P, R]):
|
|
48
|
+
"""
|
|
49
|
+
Task template is a template for a task that can be executed. It defines various parameters for the task, which
|
|
50
|
+
can be defined statically at the time of task definition or dynamically at the time of task invocation using
|
|
51
|
+
the override method.
|
|
52
|
+
|
|
53
|
+
Example usage:
|
|
54
|
+
```python
|
|
55
|
+
@task(name="my_task", image="my_image", resources=Resources(cpu="1", memory="1Gi"))
|
|
56
|
+
def my_task():
|
|
57
|
+
pass
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
:param name: Optional The name of the task (defaults to the function name)
|
|
61
|
+
:param task_type: Router type for the task, this is used to determine how the task will be executed.
|
|
62
|
+
This is usually set to match with th execution plugin.
|
|
63
|
+
:param image: Optional The image to use for the task, if set to "auto" will use the default image for the python
|
|
64
|
+
version with flyte installed
|
|
65
|
+
:param resources: Optional The resources to use for the task
|
|
66
|
+
:param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the task.
|
|
67
|
+
:param interruptable: Optional The interruptable policy for the task, defaults to False, which means the task
|
|
68
|
+
will not be scheduled on interruptable nodes. If set to True, the task will be scheduled on interruptable nodes,
|
|
69
|
+
and the code should handle interruptions and resumptions.
|
|
70
|
+
:param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
|
|
71
|
+
:param reusable: Optional The reusability policy for the task, defaults to None, which means the task environment
|
|
72
|
+
will not be reused across task invocations.
|
|
73
|
+
:param docs: Optional The documentation for the task, if not provided the function docstring will be used.
|
|
74
|
+
:param env: Optional The environment variables to set for the task.
|
|
75
|
+
:param secrets: Optional The secrets that will be injected into the task at runtime.
|
|
76
|
+
:param timeout: Optional The timeout for the task.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
name: str
|
|
80
|
+
interface: NativeInterface
|
|
81
|
+
task_type: str = "python"
|
|
82
|
+
task_type_version: int = 0
|
|
83
|
+
image: Union[str, Image, Literal["auto"]] = "auto"
|
|
84
|
+
resources: Optional[Resources] = None
|
|
85
|
+
cache: CacheRequest = "auto"
|
|
86
|
+
interruptable: bool = False
|
|
87
|
+
retries: Union[int, RetryStrategy] = 0
|
|
88
|
+
reusable: Union[ReusePolicy, Literal["auto"], None] = None
|
|
89
|
+
docs: Optional[Documentation] = None
|
|
90
|
+
env: Optional[Dict[str, str]] = None
|
|
91
|
+
secrets: Optional[SecretRequest] = None
|
|
92
|
+
timeout: Optional[TimeoutType] = None
|
|
93
|
+
primary_container_name: str = "primary"
|
|
94
|
+
pod_template: Optional[Union[str, V1PodTemplate]] = None
|
|
95
|
+
report: bool = False
|
|
96
|
+
|
|
97
|
+
parent_env: Optional[weakref.ReferenceType[TaskEnvironment]] = None
|
|
98
|
+
local: bool = field(default=False, init=False)
|
|
99
|
+
ref: bool = field(default=False, init=False, repr=False, compare=False)
|
|
100
|
+
|
|
101
|
+
def __post_init__(self):
|
|
102
|
+
# If pod_template is set to a pod, verify
|
|
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
|
|
110
|
+
|
|
111
|
+
# Auto set the image based on the image request
|
|
112
|
+
if self.image == "auto":
|
|
113
|
+
self.image = Image.auto()
|
|
114
|
+
elif isinstance(self.image, str):
|
|
115
|
+
self.image = Image.from_prebuilt(str(self.image))
|
|
116
|
+
|
|
117
|
+
# Auto set cache based on the cache request
|
|
118
|
+
if isinstance(self.cache, str):
|
|
119
|
+
match self.cache:
|
|
120
|
+
case "auto":
|
|
121
|
+
self.cache = Cache(behavior="auto")
|
|
122
|
+
case "override":
|
|
123
|
+
self.cache = Cache(behavior="override")
|
|
124
|
+
case "disable":
|
|
125
|
+
self.cache = Cache(behavior="disable")
|
|
126
|
+
|
|
127
|
+
# if retries is set to int, convert to RetryStrategy
|
|
128
|
+
if isinstance(self.retries, int):
|
|
129
|
+
self.retries = RetryStrategy(count=self.retries)
|
|
130
|
+
|
|
131
|
+
def __getstate__(self):
|
|
132
|
+
"""
|
|
133
|
+
This method is called when the object is pickled. We need to remove the parent_env reference
|
|
134
|
+
to avoid circular references.
|
|
135
|
+
"""
|
|
136
|
+
state = self.__dict__.copy()
|
|
137
|
+
state.pop("parent_env", None)
|
|
138
|
+
return state
|
|
139
|
+
|
|
140
|
+
def __setstate__(self, state):
|
|
141
|
+
"""
|
|
142
|
+
This method is called when the object is unpickled. We need to set the parent_env reference
|
|
143
|
+
to the environment that created the task.
|
|
144
|
+
"""
|
|
145
|
+
self.__dict__.update(state)
|
|
146
|
+
self.parent_env = None
|
|
147
|
+
|
|
148
|
+
async def pre(self, *args, **kwargs) -> Dict[str, Any]:
|
|
149
|
+
"""
|
|
150
|
+
This is the preexecute function that will be
|
|
151
|
+
called before the task is executed
|
|
152
|
+
"""
|
|
153
|
+
return {}
|
|
154
|
+
|
|
155
|
+
async def execute(self, *args, **kwargs) -> Any:
|
|
156
|
+
"""
|
|
157
|
+
This is the pure python function that will be executed when the task is called.
|
|
158
|
+
"""
|
|
159
|
+
raise NotImplementedError
|
|
160
|
+
|
|
161
|
+
async def post(self, return_vals: Any) -> Any:
|
|
162
|
+
"""
|
|
163
|
+
This is the postexecute function that will be
|
|
164
|
+
called after the task is executed
|
|
165
|
+
"""
|
|
166
|
+
return return_vals
|
|
167
|
+
|
|
168
|
+
# ---- Extension points ----
|
|
169
|
+
def config(self, sctx: SerializationContext) -> Dict[str, str]:
|
|
170
|
+
"""
|
|
171
|
+
Returns additional configuration for the task. This is a set of key-value pairs that can be used to
|
|
172
|
+
configure the task execution environment at runtime. This is usually used by plugins.
|
|
173
|
+
"""
|
|
174
|
+
return {}
|
|
175
|
+
|
|
176
|
+
def custom_config(self, sctx: SerializationContext) -> Dict[str, str]:
|
|
177
|
+
"""
|
|
178
|
+
Returns additional configuration for the task. This is a set of key-value pairs that can be used to
|
|
179
|
+
configure the task execution environment at runtime. This is usually used by plugins.
|
|
180
|
+
"""
|
|
181
|
+
return {}
|
|
182
|
+
|
|
183
|
+
def data_loading_config(self, sctx: SerializationContext) -> DataLoadingConfig:
|
|
184
|
+
"""
|
|
185
|
+
This configuration allows executing raw containers in Flyte using the Flyte CoPilot system
|
|
186
|
+
Flyte CoPilot, eliminates the needs of sdk inside the container. Any inputs required by the users container
|
|
187
|
+
are side-loaded in the input_path
|
|
188
|
+
Any outputs generated by the user container - within output_path are automatically uploaded
|
|
189
|
+
"""
|
|
190
|
+
|
|
191
|
+
def container_args(self, sctx: SerializationContext) -> List[str]:
|
|
192
|
+
"""
|
|
193
|
+
Returns the container args for the task. This is a set of key-value pairs that can be used to
|
|
194
|
+
configure the task execution environment at runtime. This is usually used by plugins.
|
|
195
|
+
"""
|
|
196
|
+
return []
|
|
197
|
+
|
|
198
|
+
def sql(self, sctx: SerializationContext) -> Optional[str]:
|
|
199
|
+
"""
|
|
200
|
+
Returns the SQL for the task. This is a set of key-value pairs that can be used to
|
|
201
|
+
configure the task execution environment at runtime. This is usually used by plugins.
|
|
202
|
+
"""
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
# ---- Extension points ----
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def native_interface(self) -> NativeInterface:
|
|
209
|
+
return self.interface
|
|
210
|
+
|
|
211
|
+
async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, R]:
|
|
212
|
+
"""
|
|
213
|
+
This is the entrypoint for an async function task at runtime. It will be called during an execution.
|
|
214
|
+
Please do not override this method, if you simply want to modify the execution behavior, override the
|
|
215
|
+
execute method.
|
|
216
|
+
|
|
217
|
+
# TODO lets provide one hook to implement, _pre, _execute and _post. We do not want actual execute to
|
|
218
|
+
"""
|
|
219
|
+
try:
|
|
220
|
+
ctx = internal_ctx()
|
|
221
|
+
if ctx.is_task_context():
|
|
222
|
+
# If we are in a task context, that implies we are executing a Run.
|
|
223
|
+
# In this scenario, we should submit the task to the controller.
|
|
224
|
+
# We will also check if we are not initialized, It is not expected to be not initialized
|
|
225
|
+
from ._internal.controllers import get_controller
|
|
226
|
+
|
|
227
|
+
controller = await get_controller()
|
|
228
|
+
if controller:
|
|
229
|
+
return await controller.submit(self, *args, **kwargs)
|
|
230
|
+
return await self.execute(*args, **kwargs)
|
|
231
|
+
except RuntimeSystemError:
|
|
232
|
+
raise
|
|
233
|
+
except RuntimeUserError:
|
|
234
|
+
raise
|
|
235
|
+
except Exception as e:
|
|
236
|
+
raise RuntimeUserError(type(e).__name__, str(e)) from e
|
|
237
|
+
|
|
238
|
+
def override(
|
|
239
|
+
self,
|
|
240
|
+
*,
|
|
241
|
+
local: Optional[bool] = None,
|
|
242
|
+
ref: Optional[bool] = None,
|
|
243
|
+
resources: Optional[Resources] = None,
|
|
244
|
+
cache: CacheRequest = "auto",
|
|
245
|
+
retries: Union[int, RetryStrategy] = 0,
|
|
246
|
+
timeout: Optional[TimeoutType] = None,
|
|
247
|
+
reusable: Union[ReusePolicy, Literal["auto"], None] = None,
|
|
248
|
+
env: Optional[Dict[str, str]] = None,
|
|
249
|
+
secrets: Optional[SecretRequest] = None,
|
|
250
|
+
**kwargs: Any,
|
|
251
|
+
) -> TaskTemplate:
|
|
252
|
+
"""
|
|
253
|
+
Override various parameters of the task template. This allows for dynamic configuration of the task
|
|
254
|
+
when it is called, such as changing the image, resources, cache policy, etc.
|
|
255
|
+
"""
|
|
256
|
+
resources = resources or self.resources
|
|
257
|
+
cache = cache or self.cache
|
|
258
|
+
retries = retries or self.retries
|
|
259
|
+
timeout = timeout or self.timeout
|
|
260
|
+
reusable = reusable or self.reusable
|
|
261
|
+
env = env or self.env
|
|
262
|
+
secrets = secrets or self.secrets
|
|
263
|
+
local = local or self.local
|
|
264
|
+
ref = ref or self.ref
|
|
265
|
+
for k, v in kwargs.items():
|
|
266
|
+
if k == "name":
|
|
267
|
+
raise ValueError("Name cannot be overridden")
|
|
268
|
+
if k == "image":
|
|
269
|
+
raise ValueError("Image cannot be overridden")
|
|
270
|
+
if k == "docs":
|
|
271
|
+
raise ValueError("Docs cannot be overridden")
|
|
272
|
+
if k == "interface":
|
|
273
|
+
raise ValueError("Interface cannot be overridden")
|
|
274
|
+
return replace(
|
|
275
|
+
self,
|
|
276
|
+
resources=resources,
|
|
277
|
+
cache=cache,
|
|
278
|
+
retries=retries,
|
|
279
|
+
timeout=timeout,
|
|
280
|
+
reusable=reusable,
|
|
281
|
+
env=env,
|
|
282
|
+
secrets=secrets,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
@dataclass(kw_only=True)
|
|
287
|
+
class AsyncFunctionTaskTemplate(TaskTemplate[P, R]):
|
|
288
|
+
"""
|
|
289
|
+
A task template that wraps an asynchronous functions. This is automatically created when an asynchronous function
|
|
290
|
+
is decorated with the task decorator.
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
func: Callable[P, Awaitable[R]]
|
|
294
|
+
|
|
295
|
+
@cached_property
|
|
296
|
+
def native_interface(self) -> NativeInterface:
|
|
297
|
+
return NativeInterface.from_callable(self.func)
|
|
298
|
+
|
|
299
|
+
async def execute(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
300
|
+
"""
|
|
301
|
+
This is the execute method that will be called when the task is invoked. It will call the actual function.
|
|
302
|
+
# TODO We may need to keep this as the bare func execute, and need a pre and post execute some other func.
|
|
303
|
+
"""
|
|
304
|
+
ctx = internal_ctx()
|
|
305
|
+
ctx_data = await self.pre(*args, **kwargs)
|
|
306
|
+
if ctx.data.task_context is not None:
|
|
307
|
+
tctx = ctx.data.task_context.replace(data=ctx_data)
|
|
308
|
+
with ctx.replace_task_context(tctx):
|
|
309
|
+
v = await self.func(*args, **kwargs)
|
|
310
|
+
await self.post(v)
|
|
311
|
+
else:
|
|
312
|
+
v = await self.func(*args, **kwargs)
|
|
313
|
+
await self.post(v)
|
|
314
|
+
return v
|
|
315
|
+
|
|
316
|
+
def container_args(self, serialize_context: SerializationContext) -> List[str]:
|
|
317
|
+
args = [
|
|
318
|
+
"a0",
|
|
319
|
+
"--inputs",
|
|
320
|
+
serialize_context.input_path,
|
|
321
|
+
"--outputs-path",
|
|
322
|
+
serialize_context.output_path,
|
|
323
|
+
"--version",
|
|
324
|
+
serialize_context.version, # pr: should this be serialize_context.version or code_bundle.version?
|
|
325
|
+
"--raw-data-path",
|
|
326
|
+
"{{.rawOutputDataPrefix}}",
|
|
327
|
+
"--checkpoint-path",
|
|
328
|
+
"{{.checkpointOutputPrefix}}",
|
|
329
|
+
"--prev-checkpoint",
|
|
330
|
+
"{{.prevCheckpointPrefix}}",
|
|
331
|
+
"--run-name",
|
|
332
|
+
"{{.runName}}",
|
|
333
|
+
"--name",
|
|
334
|
+
"{{.actionName}}",
|
|
335
|
+
]
|
|
336
|
+
# Add on all the known images
|
|
337
|
+
if serialize_context.image_cache and serialize_context.image_cache.serialized_form:
|
|
338
|
+
args = [*args, "--image-cache", serialize_context.image_cache.serialized_form]
|
|
339
|
+
else:
|
|
340
|
+
if serialize_context.image_cache:
|
|
341
|
+
args = [*args, "--image-cache", serialize_context.image_cache.to_transport]
|
|
342
|
+
|
|
343
|
+
if serialize_context.code_bundle:
|
|
344
|
+
if serialize_context.code_bundle.tgz:
|
|
345
|
+
args = [*args, *["--tgz", f"{serialize_context.code_bundle.tgz}"]]
|
|
346
|
+
elif serialize_context.code_bundle.pkl:
|
|
347
|
+
args = [*args, *["--pkl", f"{serialize_context.code_bundle.pkl}"]]
|
|
348
|
+
args = [*args, *["--dest", f"{serialize_context.code_bundle.destination or '.'}"]]
|
|
349
|
+
|
|
350
|
+
if not serialize_context.code_bundle or not serialize_context.code_bundle.pkl:
|
|
351
|
+
# If we do not have a code bundle, or if we have one, but it is not a pkl, we need to add the resolver
|
|
352
|
+
|
|
353
|
+
from flyte._internal.resolvers.default import DefaultTaskResolver
|
|
354
|
+
|
|
355
|
+
_task_resolver = DefaultTaskResolver()
|
|
356
|
+
args = [
|
|
357
|
+
*args,
|
|
358
|
+
*[
|
|
359
|
+
"--resolver",
|
|
360
|
+
_task_resolver.import_path,
|
|
361
|
+
*_task_resolver.loader_args(task=self, root_dir=serialize_context.root_dir),
|
|
362
|
+
],
|
|
363
|
+
]
|
|
364
|
+
|
|
365
|
+
assert all(isinstance(item, str) for item in args), f"All args should be strings, non string item = {args}"
|
|
366
|
+
|
|
367
|
+
return args
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import weakref
|
|
5
|
+
from dataclasses import dataclass, field, replace
|
|
6
|
+
from datetime import timedelta
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from typing import TYPE_CHECKING, Awaitable, Callable, Dict, List, Literal, Optional, ParamSpec, TypeVar, Union, cast
|
|
9
|
+
|
|
10
|
+
import rich.repr
|
|
11
|
+
|
|
12
|
+
from ._cache import CacheRequest
|
|
13
|
+
from ._datastructures import NativeInterface
|
|
14
|
+
from ._doc import Documentation
|
|
15
|
+
from ._environment import Environment
|
|
16
|
+
from ._image import Image
|
|
17
|
+
from ._resources import Resources
|
|
18
|
+
from ._retry import RetryStrategy
|
|
19
|
+
from ._reusable_environment import ReusePolicy
|
|
20
|
+
from ._secret import SecretRequest
|
|
21
|
+
from ._task import AsyncFunctionTaskTemplate, TaskTemplate
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from kubernetes.client import V1PodTemplate
|
|
25
|
+
|
|
26
|
+
P = ParamSpec("P") # capture the function's parameters
|
|
27
|
+
R = TypeVar("R") # return type
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@rich.repr.auto
|
|
31
|
+
@dataclass(init=True, repr=True)
|
|
32
|
+
class TaskEnvironment(Environment):
|
|
33
|
+
"""
|
|
34
|
+
Environment class to define a new environment for a set of tasks.
|
|
35
|
+
|
|
36
|
+
Example usage:
|
|
37
|
+
```python
|
|
38
|
+
env = flyte.TaskEnvironment(name="my_env", image="my_image", resources=Resources(cpu="1", memory="1Gi"))
|
|
39
|
+
|
|
40
|
+
@env.task
|
|
41
|
+
async def my_task():
|
|
42
|
+
pass
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
:param name: Name of the environment
|
|
46
|
+
:param image: Docker image to use for the environment. If set to "auto", will use the default image.
|
|
47
|
+
:param resources: Resources to allocate for the environment.
|
|
48
|
+
:param env: Environment variables to set for the environment.
|
|
49
|
+
:param secrets: Secrets to inject into the environment.
|
|
50
|
+
:param env_dep_hints: Environment dependencies to hint, so when you deploy the environment, the dependencies are
|
|
51
|
+
also deployed. This is useful when you have a set of environments that depend on each other.
|
|
52
|
+
:param cache: Cache policy for the environment.
|
|
53
|
+
:param reusable: Reuse policy for the environment, if set, a python process may be reused for multiple tasks.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
cache: Union[CacheRequest] = "auto"
|
|
57
|
+
reusable: Union[ReusePolicy, Literal["auto"], None] = None
|
|
58
|
+
# TODO Shall we make this union of string or env? This way we can lookup the env by module/file:name
|
|
59
|
+
# TODO also we could add list of files that are used by this environment
|
|
60
|
+
|
|
61
|
+
_tasks: Dict[str, TaskTemplate] = field(default_factory=dict, init=False)
|
|
62
|
+
|
|
63
|
+
def clone_with(
|
|
64
|
+
self,
|
|
65
|
+
name: str,
|
|
66
|
+
image: Optional[Union[str, Image, Literal["auto"]]] = None,
|
|
67
|
+
resources: Optional[Resources] = None,
|
|
68
|
+
cache: Union[CacheRequest, None] = None,
|
|
69
|
+
env: Optional[Dict[str, str]] = None,
|
|
70
|
+
reusable: Union[ReusePolicy, None] = None,
|
|
71
|
+
secrets: Optional[SecretRequest] = None,
|
|
72
|
+
env_dep_hints: Optional[List[Environment]] = None,
|
|
73
|
+
) -> TaskEnvironment:
|
|
74
|
+
"""
|
|
75
|
+
Clone the environment with new settings.
|
|
76
|
+
"""
|
|
77
|
+
if image is None:
|
|
78
|
+
image = self.image
|
|
79
|
+
else:
|
|
80
|
+
image = "auto"
|
|
81
|
+
return replace(
|
|
82
|
+
self,
|
|
83
|
+
cache=cache if cache else "auto",
|
|
84
|
+
reusable=reusable,
|
|
85
|
+
name=name,
|
|
86
|
+
image=image,
|
|
87
|
+
resources=resources,
|
|
88
|
+
env=env,
|
|
89
|
+
secrets=secrets,
|
|
90
|
+
env_dep_hints=env_dep_hints if env_dep_hints else [],
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def _task(
|
|
94
|
+
self,
|
|
95
|
+
_func=None,
|
|
96
|
+
*,
|
|
97
|
+
name: Optional[str] = None,
|
|
98
|
+
cache: Union[CacheRequest] | None = None,
|
|
99
|
+
retries: Union[int, RetryStrategy] = 0,
|
|
100
|
+
timeout: Union[timedelta, int] = 0,
|
|
101
|
+
docs: Optional[Documentation] = None,
|
|
102
|
+
secrets: Optional[SecretRequest] = None,
|
|
103
|
+
pod_template: Optional[Union[str, "V1PodTemplate"]] = None,
|
|
104
|
+
report: bool = False,
|
|
105
|
+
) -> Union[AsyncFunctionTaskTemplate, Callable[P, R]]:
|
|
106
|
+
"""
|
|
107
|
+
:param name: Optional The name of the task (defaults to the function name)
|
|
108
|
+
:param cache: Optional The cache policy for the task, defaults to auto, which will cache the results of the
|
|
109
|
+
task.
|
|
110
|
+
:param retries: Optional The number of retries for the task, defaults to 0, which means no retries.
|
|
111
|
+
:param docs: Optional The documentation for the task, if not provided the function docstring will be used.
|
|
112
|
+
:param secrets: Optional The secrets that will be injected into the task at runtime.
|
|
113
|
+
:param timeout: Optional The timeout for the task.
|
|
114
|
+
:param pod_template: Optional The pod template for the task, if not provided the default pod template will be
|
|
115
|
+
used.
|
|
116
|
+
:param report: Optional Whether to generate the html report for the task, defaults to False.
|
|
117
|
+
"""
|
|
118
|
+
if self.reusable is not None:
|
|
119
|
+
if pod_template is not None:
|
|
120
|
+
raise ValueError("Cannot set pod_template when environment is reusable.")
|
|
121
|
+
|
|
122
|
+
def decorator(func: Callable[P, Awaitable[R]]) -> AsyncFunctionTaskTemplate[P, R]:
|
|
123
|
+
task_name = name or func.__name__
|
|
124
|
+
task_name = self.name + "." + task_name
|
|
125
|
+
if len(task_name) > 30:
|
|
126
|
+
# delete this if we can remove the restriction that task names must be <= 30 characters
|
|
127
|
+
task_name = task_name[-30:]
|
|
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,
|
|
141
|
+
name=task_name,
|
|
142
|
+
image=self.image,
|
|
143
|
+
resources=self.resources,
|
|
144
|
+
cache=cache or self.cache,
|
|
145
|
+
retries=retries,
|
|
146
|
+
timeout=timeout,
|
|
147
|
+
reusable=self.reusable,
|
|
148
|
+
docs=docs,
|
|
149
|
+
env=self.env,
|
|
150
|
+
secrets=secrets or self.secrets,
|
|
151
|
+
pod_template=pod_template or self.pod_template,
|
|
152
|
+
parent_env=weakref.ref(self),
|
|
153
|
+
interface=NativeInterface.from_callable(func),
|
|
154
|
+
report=report,
|
|
155
|
+
)
|
|
156
|
+
self._tasks[task_name] = tmpl
|
|
157
|
+
return tmpl
|
|
158
|
+
|
|
159
|
+
if _func is None:
|
|
160
|
+
return cast(AsyncFunctionTaskTemplate, decorator)
|
|
161
|
+
return cast(AsyncFunctionTaskTemplate, decorator(_func))
|
|
162
|
+
|
|
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
|
+
@property
|
|
187
|
+
def tasks(self) -> Dict[str, TaskTemplate]:
|
|
188
|
+
"""
|
|
189
|
+
Get all tasks defined in the environment.
|
|
190
|
+
"""
|
|
191
|
+
return self._tasks
|
|
192
|
+
|
|
193
|
+
def add_task(self, task: TaskTemplate) -> TaskTemplate:
|
|
194
|
+
"""
|
|
195
|
+
Add a task to the environment.
|
|
196
|
+
"""
|
|
197
|
+
if task.name in self._tasks:
|
|
198
|
+
raise ValueError(f"Task {task.name} already exists in the environment. Task names should be unique.")
|
|
199
|
+
self._tasks[task.name] = task
|
|
200
|
+
return task
|
flyte/_timeout.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class Timeout:
|
|
7
|
+
"""
|
|
8
|
+
Timeout class to define a timeout for a task.
|
|
9
|
+
The task timeout can be set to a maximum runtime and a maximum queued time.
|
|
10
|
+
Maximum runtime is the maximum time the task can run for (in one attempt).
|
|
11
|
+
Maximum queued time is the maximum time the task can stay in the queue before it starts executing.
|
|
12
|
+
|
|
13
|
+
Example usage:
|
|
14
|
+
```python
|
|
15
|
+
timeout = Timeout(max_runtime=timedelta(minutes=5), max_queued_time=timedelta(minutes=10))
|
|
16
|
+
@env.task(timeout=timeout)
|
|
17
|
+
async def my_task():
|
|
18
|
+
pass
|
|
19
|
+
```
|
|
20
|
+
:param max_runtime: timedelta or int - Maximum runtime for the task. If specified int, it will be converted to
|
|
21
|
+
timedelta as seconds.
|
|
22
|
+
:param max_queued_time: optional, timedelta or int - Maximum queued time for the task. If specified int,
|
|
23
|
+
it will be converted to timedelta as seconds. Defaults to None.
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
max_runtime: timedelta | int
|
|
28
|
+
max_queued_time: timedelta | int | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
TimeoutType = Timeout | int | timedelta
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def timeout_from_request(timeout: TimeoutType) -> Timeout:
|
|
35
|
+
"""
|
|
36
|
+
Converts a timeout request into a Timeout object.
|
|
37
|
+
"""
|
|
38
|
+
if isinstance(timeout, Timeout):
|
|
39
|
+
return timeout
|
|
40
|
+
else:
|
|
41
|
+
if isinstance(timeout, int):
|
|
42
|
+
timeout = timedelta(seconds=timeout)
|
|
43
|
+
elif isinstance(timeout, timedelta):
|
|
44
|
+
pass
|
|
45
|
+
else:
|
|
46
|
+
raise ValueError("Timeout must be an instance of Timeout, int, or timedelta.")
|
|
47
|
+
return Timeout(max_runtime=timeout)
|