flyte 0.0.1b0__py3-none-any.whl → 2.0.0b46__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.
- flyte/__init__.py +83 -30
- flyte/_bin/connect.py +61 -0
- flyte/_bin/debug.py +38 -0
- flyte/_bin/runtime.py +87 -19
- flyte/_bin/serve.py +351 -0
- flyte/_build.py +3 -2
- flyte/_cache/cache.py +6 -5
- flyte/_cache/local_cache.py +216 -0
- flyte/_code_bundle/_ignore.py +31 -5
- flyte/_code_bundle/_packaging.py +42 -11
- flyte/_code_bundle/_utils.py +57 -34
- flyte/_code_bundle/bundle.py +130 -27
- flyte/_constants.py +1 -0
- flyte/_context.py +21 -5
- flyte/_custom_context.py +73 -0
- flyte/_debug/constants.py +37 -0
- flyte/_debug/utils.py +17 -0
- flyte/_debug/vscode.py +315 -0
- flyte/_deploy.py +396 -75
- flyte/_deployer.py +109 -0
- flyte/_environment.py +94 -11
- flyte/_excepthook.py +37 -0
- flyte/_group.py +2 -1
- flyte/_hash.py +1 -16
- flyte/_image.py +544 -234
- flyte/_initialize.py +443 -294
- flyte/_interface.py +40 -5
- flyte/_internal/controllers/__init__.py +22 -8
- flyte/_internal/controllers/_local_controller.py +159 -35
- flyte/_internal/controllers/_trace.py +18 -10
- flyte/_internal/controllers/remote/__init__.py +38 -9
- flyte/_internal/controllers/remote/_action.py +82 -12
- flyte/_internal/controllers/remote/_client.py +6 -2
- flyte/_internal/controllers/remote/_controller.py +290 -64
- flyte/_internal/controllers/remote/_core.py +155 -95
- flyte/_internal/controllers/remote/_informer.py +40 -20
- flyte/_internal/controllers/remote/_service_protocol.py +2 -2
- flyte/_internal/imagebuild/__init__.py +2 -10
- flyte/_internal/imagebuild/docker_builder.py +391 -84
- flyte/_internal/imagebuild/image_builder.py +111 -55
- flyte/_internal/imagebuild/remote_builder.py +409 -0
- flyte/_internal/imagebuild/utils.py +79 -0
- flyte/_internal/resolvers/_app_env_module.py +92 -0
- flyte/_internal/resolvers/_task_module.py +5 -38
- flyte/_internal/resolvers/app_env.py +26 -0
- flyte/_internal/resolvers/common.py +8 -1
- flyte/_internal/resolvers/default.py +2 -2
- flyte/_internal/runtime/convert.py +322 -33
- flyte/_internal/runtime/entrypoints.py +106 -18
- flyte/_internal/runtime/io.py +71 -23
- flyte/_internal/runtime/resources_serde.py +21 -7
- flyte/_internal/runtime/reuse.py +125 -0
- flyte/_internal/runtime/rusty.py +196 -0
- flyte/_internal/runtime/task_serde.py +239 -66
- flyte/_internal/runtime/taskrunner.py +48 -8
- flyte/_internal/runtime/trigger_serde.py +162 -0
- flyte/_internal/runtime/types_serde.py +7 -16
- flyte/_keyring/file.py +115 -0
- flyte/_link.py +30 -0
- flyte/_logging.py +241 -42
- flyte/_map.py +312 -0
- flyte/_metrics.py +59 -0
- flyte/_module.py +74 -0
- flyte/_pod.py +30 -0
- flyte/_resources.py +296 -33
- flyte/_retry.py +1 -7
- flyte/_reusable_environment.py +72 -7
- flyte/_run.py +461 -132
- flyte/_secret.py +47 -11
- flyte/_serve.py +333 -0
- flyte/_task.py +245 -56
- flyte/_task_environment.py +219 -97
- flyte/_task_plugins.py +47 -0
- flyte/_tools.py +8 -8
- flyte/_trace.py +15 -24
- flyte/_trigger.py +1027 -0
- flyte/_utils/__init__.py +12 -1
- flyte/_utils/asyn.py +3 -1
- flyte/_utils/async_cache.py +139 -0
- flyte/_utils/coro_management.py +5 -4
- flyte/_utils/description_parser.py +19 -0
- flyte/_utils/docker_credentials.py +173 -0
- flyte/_utils/helpers.py +45 -19
- flyte/_utils/module_loader.py +123 -0
- flyte/_utils/org_discovery.py +57 -0
- flyte/_utils/uv_script_parser.py +8 -1
- flyte/_version.py +16 -3
- flyte/app/__init__.py +27 -0
- flyte/app/_app_environment.py +362 -0
- flyte/app/_connector_environment.py +40 -0
- flyte/app/_deploy.py +130 -0
- flyte/app/_parameter.py +343 -0
- flyte/app/_runtime/__init__.py +3 -0
- flyte/app/_runtime/app_serde.py +383 -0
- flyte/app/_types.py +113 -0
- flyte/app/extras/__init__.py +9 -0
- flyte/app/extras/_auth_middleware.py +217 -0
- flyte/app/extras/_fastapi.py +93 -0
- flyte/app/extras/_model_loader/__init__.py +3 -0
- flyte/app/extras/_model_loader/config.py +7 -0
- flyte/app/extras/_model_loader/loader.py +288 -0
- flyte/cli/__init__.py +12 -0
- flyte/cli/_abort.py +28 -0
- flyte/cli/_build.py +114 -0
- flyte/cli/_common.py +493 -0
- flyte/cli/_create.py +371 -0
- flyte/cli/_delete.py +45 -0
- flyte/cli/_deploy.py +401 -0
- flyte/cli/_gen.py +316 -0
- flyte/cli/_get.py +446 -0
- flyte/cli/_option.py +33 -0
- {union/_cli → flyte/cli}/_params.py +152 -153
- flyte/cli/_plugins.py +209 -0
- flyte/cli/_prefetch.py +292 -0
- flyte/cli/_run.py +690 -0
- flyte/cli/_serve.py +338 -0
- flyte/cli/_update.py +86 -0
- flyte/cli/_user.py +20 -0
- flyte/cli/main.py +246 -0
- flyte/config/__init__.py +3 -0
- flyte/config/_config.py +248 -0
- flyte/config/_internal.py +73 -0
- flyte/config/_reader.py +225 -0
- flyte/connectors/__init__.py +11 -0
- flyte/connectors/_connector.py +330 -0
- flyte/connectors/_server.py +194 -0
- flyte/connectors/utils.py +159 -0
- flyte/errors.py +134 -2
- flyte/extend.py +24 -0
- flyte/extras/_container.py +69 -56
- flyte/git/__init__.py +3 -0
- flyte/git/_config.py +279 -0
- flyte/io/__init__.py +8 -1
- flyte/io/{structured_dataset → _dataframe}/__init__.py +32 -30
- flyte/io/{structured_dataset → _dataframe}/basic_dfs.py +75 -68
- flyte/io/{structured_dataset/structured_dataset.py → _dataframe/dataframe.py} +207 -242
- flyte/io/_dir.py +575 -113
- flyte/io/_file.py +587 -141
- flyte/io/_hashing_io.py +342 -0
- flyte/io/extend.py +7 -0
- flyte/models.py +635 -0
- flyte/prefetch/__init__.py +22 -0
- flyte/prefetch/_hf_model.py +563 -0
- flyte/remote/__init__.py +14 -3
- flyte/remote/_action.py +879 -0
- flyte/remote/_app.py +346 -0
- flyte/remote/_auth_metadata.py +42 -0
- flyte/remote/_client/_protocols.py +62 -4
- flyte/remote/_client/auth/_auth_utils.py +19 -0
- flyte/remote/_client/auth/_authenticators/base.py +8 -2
- flyte/remote/_client/auth/_authenticators/device_code.py +4 -5
- flyte/remote/_client/auth/_authenticators/factory.py +4 -0
- flyte/remote/_client/auth/_authenticators/passthrough.py +79 -0
- flyte/remote/_client/auth/_authenticators/pkce.py +17 -18
- flyte/remote/_client/auth/_channel.py +47 -18
- flyte/remote/_client/auth/_client_config.py +5 -3
- flyte/remote/_client/auth/_keyring.py +15 -2
- flyte/remote/_client/auth/_token_client.py +3 -3
- flyte/remote/_client/controlplane.py +206 -18
- flyte/remote/_common.py +66 -0
- flyte/remote/_data.py +107 -22
- flyte/remote/_logs.py +116 -33
- flyte/remote/_project.py +21 -19
- flyte/remote/_run.py +164 -631
- flyte/remote/_secret.py +72 -29
- flyte/remote/_task.py +387 -46
- flyte/remote/_trigger.py +368 -0
- flyte/remote/_user.py +43 -0
- flyte/report/_report.py +10 -6
- flyte/storage/__init__.py +13 -1
- flyte/storage/_config.py +237 -0
- flyte/storage/_parallel_reader.py +289 -0
- flyte/storage/_storage.py +268 -59
- flyte/syncify/__init__.py +56 -0
- flyte/syncify/_api.py +414 -0
- flyte/types/__init__.py +39 -0
- flyte/types/_interface.py +22 -7
- flyte/{io/pickle/transformer.py → types/_pickle.py} +37 -9
- flyte/types/_string_literals.py +8 -9
- flyte/types/_type_engine.py +230 -129
- flyte/types/_utils.py +1 -1
- flyte-2.0.0b46.data/scripts/debug.py +38 -0
- flyte-2.0.0b46.data/scripts/runtime.py +194 -0
- flyte-2.0.0b46.dist-info/METADATA +352 -0
- flyte-2.0.0b46.dist-info/RECORD +221 -0
- flyte-2.0.0b46.dist-info/entry_points.txt +8 -0
- flyte-2.0.0b46.dist-info/licenses/LICENSE +201 -0
- flyte/_api_commons.py +0 -3
- flyte/_cli/_common.py +0 -287
- flyte/_cli/_create.py +0 -42
- flyte/_cli/_delete.py +0 -23
- flyte/_cli/_deploy.py +0 -140
- flyte/_cli/_get.py +0 -235
- flyte/_cli/_run.py +0 -152
- flyte/_cli/main.py +0 -72
- flyte/_datastructures.py +0 -342
- flyte/_internal/controllers/pbhash.py +0 -39
- flyte/_protos/common/authorization_pb2.py +0 -66
- flyte/_protos/common/authorization_pb2.pyi +0 -108
- flyte/_protos/common/authorization_pb2_grpc.py +0 -4
- flyte/_protos/common/identifier_pb2.py +0 -71
- flyte/_protos/common/identifier_pb2.pyi +0 -82
- flyte/_protos/common/identifier_pb2_grpc.py +0 -4
- flyte/_protos/common/identity_pb2.py +0 -48
- flyte/_protos/common/identity_pb2.pyi +0 -72
- flyte/_protos/common/identity_pb2_grpc.py +0 -4
- flyte/_protos/common/list_pb2.py +0 -36
- flyte/_protos/common/list_pb2.pyi +0 -69
- flyte/_protos/common/list_pb2_grpc.py +0 -4
- flyte/_protos/common/policy_pb2.py +0 -37
- flyte/_protos/common/policy_pb2.pyi +0 -27
- flyte/_protos/common/policy_pb2_grpc.py +0 -4
- flyte/_protos/common/role_pb2.py +0 -37
- flyte/_protos/common/role_pb2.pyi +0 -53
- flyte/_protos/common/role_pb2_grpc.py +0 -4
- flyte/_protos/common/runtime_version_pb2.py +0 -28
- flyte/_protos/common/runtime_version_pb2.pyi +0 -24
- flyte/_protos/common/runtime_version_pb2_grpc.py +0 -4
- flyte/_protos/logs/dataplane/payload_pb2.py +0 -96
- flyte/_protos/logs/dataplane/payload_pb2.pyi +0 -168
- flyte/_protos/logs/dataplane/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/definition_pb2.py +0 -49
- flyte/_protos/secret/definition_pb2.pyi +0 -93
- flyte/_protos/secret/definition_pb2_grpc.py +0 -4
- flyte/_protos/secret/payload_pb2.py +0 -62
- flyte/_protos/secret/payload_pb2.pyi +0 -94
- flyte/_protos/secret/payload_pb2_grpc.py +0 -4
- flyte/_protos/secret/secret_pb2.py +0 -38
- flyte/_protos/secret/secret_pb2.pyi +0 -6
- flyte/_protos/secret/secret_pb2_grpc.py +0 -198
- flyte/_protos/secret/secret_pb2_grpc_grpc.py +0 -198
- flyte/_protos/validate/validate/validate_pb2.py +0 -76
- flyte/_protos/workflow/node_execution_service_pb2.py +0 -26
- flyte/_protos/workflow/node_execution_service_pb2.pyi +0 -4
- flyte/_protos/workflow/node_execution_service_pb2_grpc.py +0 -32
- flyte/_protos/workflow/queue_service_pb2.py +0 -106
- flyte/_protos/workflow/queue_service_pb2.pyi +0 -141
- flyte/_protos/workflow/queue_service_pb2_grpc.py +0 -172
- flyte/_protos/workflow/run_definition_pb2.py +0 -128
- flyte/_protos/workflow/run_definition_pb2.pyi +0 -310
- flyte/_protos/workflow/run_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/run_logs_service_pb2.py +0 -41
- flyte/_protos/workflow/run_logs_service_pb2.pyi +0 -28
- flyte/_protos/workflow/run_logs_service_pb2_grpc.py +0 -69
- flyte/_protos/workflow/run_service_pb2.py +0 -133
- flyte/_protos/workflow/run_service_pb2.pyi +0 -175
- flyte/_protos/workflow/run_service_pb2_grpc.py +0 -412
- flyte/_protos/workflow/state_service_pb2.py +0 -58
- flyte/_protos/workflow/state_service_pb2.pyi +0 -71
- flyte/_protos/workflow/state_service_pb2_grpc.py +0 -138
- flyte/_protos/workflow/task_definition_pb2.py +0 -72
- flyte/_protos/workflow/task_definition_pb2.pyi +0 -65
- flyte/_protos/workflow/task_definition_pb2_grpc.py +0 -4
- flyte/_protos/workflow/task_service_pb2.py +0 -44
- flyte/_protos/workflow/task_service_pb2.pyi +0 -31
- flyte/_protos/workflow/task_service_pb2_grpc.py +0 -104
- flyte/io/_dataframe.py +0 -0
- flyte/io/pickle/__init__.py +0 -0
- flyte/remote/_console.py +0 -18
- flyte-0.0.1b0.dist-info/METADATA +0 -179
- flyte-0.0.1b0.dist-info/RECORD +0 -390
- flyte-0.0.1b0.dist-info/entry_points.txt +0 -3
- 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/authorization_pb2_grpc.py +0 -4
- union/_protos/common/identifier_pb2.py +0 -71
- union/_protos/common/identifier_pb2.pyi +0 -82
- union/_protos/common/identifier_pb2_grpc.py +0 -4
- 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
- /flyte/{_cli → _debug}/__init__.py +0 -0
- /flyte/{_protos → _keyring}/__init__.py +0 -0
- {flyte-0.0.1b0.dist-info → flyte-2.0.0b46.dist-info}/WHEEL +0 -0
- {flyte-0.0.1b0.dist-info → flyte-2.0.0b46.dist-info}/top_level.txt +0 -0
flyte/_deploy.py
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import hashlib
|
|
4
5
|
from dataclasses import dataclass
|
|
5
|
-
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
|
|
6
|
+
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
|
|
6
7
|
|
|
8
|
+
import cloudpickle
|
|
7
9
|
import rich.repr
|
|
8
10
|
|
|
9
|
-
from .
|
|
10
|
-
from .
|
|
11
|
+
from flyte.models import NativeInterface, SerializationContext
|
|
12
|
+
from flyte.syncify import syncify
|
|
13
|
+
|
|
11
14
|
from ._environment import Environment
|
|
12
15
|
from ._image import Image
|
|
13
|
-
from ._initialize import
|
|
16
|
+
from ._initialize import ensure_client, get_client, get_init_config, requires_initialization
|
|
14
17
|
from ._logging import logger
|
|
15
18
|
from ._task import TaskTemplate
|
|
16
19
|
from ._task_environment import TaskEnvironment
|
|
17
20
|
|
|
18
21
|
if TYPE_CHECKING:
|
|
19
|
-
from
|
|
22
|
+
from flyteidl2.core import interface_pb2
|
|
23
|
+
from flyteidl2.task import task_definition_pb2
|
|
20
24
|
|
|
21
25
|
from ._code_bundle import CopyFiles
|
|
26
|
+
from ._deployer import DeployedEnvironment, DeploymentContext
|
|
22
27
|
from ._internal.imagebuild.image_builder import ImageCache
|
|
23
28
|
|
|
24
29
|
|
|
@@ -31,51 +36,289 @@ class DeploymentPlan:
|
|
|
31
36
|
|
|
32
37
|
@rich.repr.auto
|
|
33
38
|
@dataclass
|
|
39
|
+
class DeployedTask:
|
|
40
|
+
deployed_task: task_definition_pb2.TaskSpec
|
|
41
|
+
deployed_triggers: List[task_definition_pb2.TaskTrigger]
|
|
42
|
+
|
|
43
|
+
def get_name(self) -> str:
|
|
44
|
+
"""
|
|
45
|
+
Returns the name of the deployed environment.
|
|
46
|
+
Returns:
|
|
47
|
+
"""
|
|
48
|
+
return self.deployed_task.task_template.id.name
|
|
49
|
+
|
|
50
|
+
def summary_repr(self) -> str:
|
|
51
|
+
"""
|
|
52
|
+
Returns a summary representation of the deployed task.
|
|
53
|
+
"""
|
|
54
|
+
return (
|
|
55
|
+
f"DeployedTask(name={self.deployed_task.task_template.id.name}, "
|
|
56
|
+
f"version={self.deployed_task.task_template.id.version})"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def table_repr(self) -> List[Tuple[str, ...]]:
|
|
60
|
+
"""
|
|
61
|
+
Returns a table representation of the deployed task.
|
|
62
|
+
"""
|
|
63
|
+
from flyte._initialize import get_client
|
|
64
|
+
|
|
65
|
+
client = get_client()
|
|
66
|
+
task_id = self.deployed_task.task_template.id
|
|
67
|
+
task_url = client.console.task_url(
|
|
68
|
+
project=task_id.project,
|
|
69
|
+
domain=task_id.domain,
|
|
70
|
+
task_name=task_id.name,
|
|
71
|
+
)
|
|
72
|
+
triggers = []
|
|
73
|
+
for t in self.deployed_triggers:
|
|
74
|
+
trigger_url = client.console.trigger_url(
|
|
75
|
+
project=task_id.project,
|
|
76
|
+
domain=task_id.domain,
|
|
77
|
+
task_name=task_id.name,
|
|
78
|
+
trigger_name=t.name,
|
|
79
|
+
)
|
|
80
|
+
triggers.append(f"[link={trigger_url}]{t.name}[/link]")
|
|
81
|
+
|
|
82
|
+
return [
|
|
83
|
+
("type", "task"),
|
|
84
|
+
("name", f"[link={task_url}]{task_id.name}[/link]"),
|
|
85
|
+
("version", task_id.version),
|
|
86
|
+
("triggers", ",".join(triggers)),
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@rich.repr.auto
|
|
91
|
+
@dataclass
|
|
92
|
+
class DeployedTaskEnvironment:
|
|
93
|
+
env: TaskEnvironment
|
|
94
|
+
deployed_entities: List[DeployedTask]
|
|
95
|
+
|
|
96
|
+
def get_name(self) -> str:
|
|
97
|
+
"""
|
|
98
|
+
Returns the name of the deployed environment.
|
|
99
|
+
"""
|
|
100
|
+
return self.env.name
|
|
101
|
+
|
|
102
|
+
def summary_repr(self) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Returns a summary representation of the deployment.
|
|
105
|
+
"""
|
|
106
|
+
entities = ", ".join(f"{e.summary_repr()}" for e in self.deployed_entities or [])
|
|
107
|
+
return f"Deployment(env=[{self.env.name}], entities=[{entities}])"
|
|
108
|
+
|
|
109
|
+
def table_repr(self) -> List[List[Tuple[str, ...]]]:
|
|
110
|
+
"""
|
|
111
|
+
Returns a detailed representation of the deployed tasks.
|
|
112
|
+
"""
|
|
113
|
+
tuples = []
|
|
114
|
+
if self.deployed_entities:
|
|
115
|
+
for e in self.deployed_entities:
|
|
116
|
+
tuples.append(e.table_repr())
|
|
117
|
+
return tuples
|
|
118
|
+
|
|
119
|
+
def env_repr(self) -> List[Tuple[str, ...]]:
|
|
120
|
+
"""
|
|
121
|
+
Returns a detailed representation of the deployed environments.
|
|
122
|
+
"""
|
|
123
|
+
env = self.env
|
|
124
|
+
return [
|
|
125
|
+
("environment", env.name),
|
|
126
|
+
("image", env.image.uri if isinstance(env.image, Image) else env.image or ""),
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@rich.repr.auto
|
|
131
|
+
@dataclass(frozen=True)
|
|
34
132
|
class Deployment:
|
|
35
|
-
envs: Dict[str,
|
|
36
|
-
deployed_tasks: List[task_definition_pb2.TaskSpec] | None = None
|
|
133
|
+
envs: Dict[str, DeployedEnvironment]
|
|
37
134
|
|
|
38
135
|
def summary_repr(self) -> str:
|
|
39
136
|
"""
|
|
40
137
|
Returns a summary representation of the deployment.
|
|
41
138
|
"""
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
139
|
+
envs = ", ".join(f"{e.summary_repr()}" for e in self.envs.values() or [])
|
|
140
|
+
return f"Deployment(envs=[{envs}])"
|
|
141
|
+
|
|
142
|
+
def table_repr(self) -> List[List[Tuple[str, ...]]]:
|
|
143
|
+
"""
|
|
144
|
+
Returns a detailed representation of the deployed tasks.
|
|
145
|
+
"""
|
|
146
|
+
tuples = []
|
|
147
|
+
for d in self.envs.values():
|
|
148
|
+
tuples.extend(d.table_repr())
|
|
149
|
+
return tuples
|
|
150
|
+
|
|
151
|
+
def env_repr(self) -> List[List[Tuple[str, ...]]]:
|
|
152
|
+
"""
|
|
153
|
+
Returns a detailed representation of the deployed environments.
|
|
154
|
+
"""
|
|
155
|
+
tuples = []
|
|
156
|
+
for d in self.envs.values():
|
|
157
|
+
tuples.append(d.env_repr())
|
|
158
|
+
return tuples
|
|
47
159
|
|
|
48
160
|
|
|
49
|
-
@requires_client
|
|
50
161
|
async def _deploy_task(
|
|
51
162
|
task: TaskTemplate, serialization_context: SerializationContext, dryrun: bool = False
|
|
52
|
-
) ->
|
|
163
|
+
) -> DeployedTask:
|
|
53
164
|
"""
|
|
54
165
|
Deploy the given task.
|
|
55
166
|
"""
|
|
167
|
+
ensure_client()
|
|
168
|
+
import grpc.aio
|
|
169
|
+
from flyteidl2.task import task_definition_pb2, task_service_pb2
|
|
170
|
+
|
|
171
|
+
import flyte.errors
|
|
172
|
+
|
|
173
|
+
from ._internal.runtime.convert import convert_upload_default_inputs
|
|
56
174
|
from ._internal.runtime.task_serde import translate_task_to_wire
|
|
57
|
-
from .
|
|
175
|
+
from ._internal.runtime.trigger_serde import to_task_trigger
|
|
58
176
|
|
|
59
177
|
image_uri = task.image.uri if isinstance(task.image, Image) else task.image
|
|
60
178
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
179
|
+
try:
|
|
180
|
+
if dryrun:
|
|
181
|
+
return DeployedTask(translate_task_to_wire(task, serialization_context), [])
|
|
182
|
+
|
|
183
|
+
default_inputs = await convert_upload_default_inputs(task.interface)
|
|
184
|
+
spec = translate_task_to_wire(task, serialization_context, default_inputs=default_inputs)
|
|
185
|
+
# Insert ENV description into spec
|
|
186
|
+
env = task.parent_env() if task.parent_env else None
|
|
187
|
+
if env and env.description:
|
|
188
|
+
spec.environment.description = env.description
|
|
189
|
+
|
|
190
|
+
# Insert documentation entity into task spec
|
|
191
|
+
documentation_entity = _get_documentation_entity(task)
|
|
192
|
+
spec.documentation.CopyFrom(documentation_entity)
|
|
193
|
+
|
|
194
|
+
# Update inputs and outputs descriptions from docstring
|
|
195
|
+
# This is done at deploy time to avoid runtime overhead
|
|
196
|
+
updated_interface = _update_interface_inputs_and_outputs_docstring(
|
|
197
|
+
spec.task_template.interface, task.native_interface
|
|
198
|
+
)
|
|
199
|
+
spec.task_template.interface.CopyFrom(updated_interface)
|
|
200
|
+
msg = f"Deploying task {task.name}, with image {image_uri} version {serialization_context.version}"
|
|
201
|
+
if spec.task_template.HasField("container") and spec.task_template.container.args:
|
|
202
|
+
msg += f" from {spec.task_template.container.args[-3]}.{spec.task_template.container.args[-1]}"
|
|
203
|
+
logger.info(msg)
|
|
204
|
+
task_id = task_definition_pb2.TaskIdentifier(
|
|
205
|
+
org=spec.task_template.id.org,
|
|
206
|
+
project=spec.task_template.id.project,
|
|
207
|
+
domain=spec.task_template.id.domain,
|
|
208
|
+
version=spec.task_template.id.version,
|
|
209
|
+
name=spec.task_template.id.name,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
deployable_triggers = []
|
|
213
|
+
for t in task.triggers:
|
|
214
|
+
inputs = spec.task_template.interface.inputs
|
|
215
|
+
default_inputs = spec.default_inputs
|
|
216
|
+
deployable_triggers.append(
|
|
217
|
+
await to_task_trigger(
|
|
218
|
+
t=t, task_name=task.name, task_inputs=inputs, task_default_inputs=list(default_inputs)
|
|
219
|
+
)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
try:
|
|
223
|
+
await get_client().task_service.DeployTask(
|
|
224
|
+
task_service_pb2.DeployTaskRequest(
|
|
225
|
+
task_id=task_id,
|
|
226
|
+
spec=spec,
|
|
227
|
+
triggers=deployable_triggers,
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
logger.info(f"Deployed task {task.name} with version {task_id.version}")
|
|
231
|
+
except grpc.aio.AioRpcError as e:
|
|
232
|
+
if e.code() == grpc.StatusCode.ALREADY_EXISTS:
|
|
233
|
+
logger.info(f"Task {task.name} with image {image_uri} already exists, skipping deployment.")
|
|
234
|
+
return DeployedTask(spec, deployable_triggers)
|
|
235
|
+
raise
|
|
236
|
+
|
|
237
|
+
return DeployedTask(spec, deployable_triggers)
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.error(f"Failed to deploy task {task.name} with image {image_uri}: {e}")
|
|
240
|
+
raise flyte.errors.DeploymentError(
|
|
241
|
+
f"Failed to deploy task {task.name} file{task.source_file} with image {image_uri}, Error: {e!s}"
|
|
242
|
+
) from e
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _get_documentation_entity(task_template: TaskTemplate) -> task_definition_pb2.DocumentationEntity:
|
|
246
|
+
"""
|
|
247
|
+
Create a DocumentationEntity with descriptions and source code url.
|
|
248
|
+
Short descriptions are truncated to 255 chars, long descriptions to 2048 chars.
|
|
249
|
+
|
|
250
|
+
:param task_template: TaskTemplate containing the interface docstring.
|
|
251
|
+
:return: DocumentationEntity with short description, long description, and source code url link.
|
|
252
|
+
"""
|
|
253
|
+
from flyteidl2.task import task_definition_pb2
|
|
254
|
+
|
|
255
|
+
from flyte._utils.description_parser import parse_description
|
|
256
|
+
from flyte.git import GitStatus
|
|
257
|
+
|
|
258
|
+
docstring = task_template.interface.docstring
|
|
259
|
+
short_desc = None
|
|
260
|
+
long_desc = None
|
|
261
|
+
source_code = None
|
|
262
|
+
if docstring and docstring.short_description:
|
|
263
|
+
short_desc = parse_description(docstring.short_description, 255)
|
|
264
|
+
if docstring and docstring.long_description:
|
|
265
|
+
long_desc = parse_description(docstring.long_description, 2048)
|
|
266
|
+
if hasattr(task_template, "func") and hasattr(task_template.func, "__code__") and task_template.func.__code__:
|
|
267
|
+
line_number = (
|
|
268
|
+
task_template.func.__code__.co_firstlineno + 1
|
|
269
|
+
) # The function definition line number is located at the line after @env.task decorator
|
|
270
|
+
file_path = task_template.func.__code__.co_filename
|
|
271
|
+
git_status = GitStatus.from_current_repo()
|
|
272
|
+
if git_status.is_valid:
|
|
273
|
+
# Build git host url
|
|
274
|
+
git_host_url = git_status.build_url(file_path, line_number)
|
|
275
|
+
if git_host_url:
|
|
276
|
+
source_code = task_definition_pb2.SourceCode(link=git_host_url)
|
|
277
|
+
|
|
278
|
+
return task_definition_pb2.DocumentationEntity(
|
|
279
|
+
short_description=short_desc,
|
|
280
|
+
long_description=long_desc,
|
|
281
|
+
source_code=source_code,
|
|
74
282
|
)
|
|
75
283
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
284
|
+
|
|
285
|
+
def _update_interface_inputs_and_outputs_docstring(
|
|
286
|
+
typed_interface: interface_pb2.TypedInterface, native_interface: NativeInterface
|
|
287
|
+
) -> interface_pb2.TypedInterface:
|
|
288
|
+
"""
|
|
289
|
+
Create a new TypedInterface with updated descriptions from the NativeInterface docstring.
|
|
290
|
+
This is done during deployment to avoid runtime overhead of parsing docstrings during task execution.
|
|
291
|
+
|
|
292
|
+
:param typed_interface: The protobuf TypedInterface to copy.
|
|
293
|
+
:param native_interface: The NativeInterface containing the docstring.
|
|
294
|
+
:return: New TypedInterface with descriptions from docstring if docstring exists.
|
|
295
|
+
"""
|
|
296
|
+
from flyteidl2.core import interface_pb2
|
|
297
|
+
|
|
298
|
+
# Create a copy of the typed_interface to avoid mutating the input
|
|
299
|
+
updated_interface = interface_pb2.TypedInterface()
|
|
300
|
+
updated_interface.CopyFrom(typed_interface)
|
|
301
|
+
|
|
302
|
+
if not native_interface.docstring:
|
|
303
|
+
return updated_interface
|
|
304
|
+
|
|
305
|
+
# Extract descriptions from the parsed docstring
|
|
306
|
+
input_descriptions = {k: v for k, v in native_interface.docstring.input_descriptions.items() if v is not None}
|
|
307
|
+
output_descriptions = {k: v for k, v in native_interface.docstring.output_descriptions.items() if v is not None}
|
|
308
|
+
|
|
309
|
+
# Update input variable descriptions
|
|
310
|
+
if updated_interface.inputs and updated_interface.inputs.variables:
|
|
311
|
+
for var_name, desc in input_descriptions.items():
|
|
312
|
+
if var_name in updated_interface.inputs.variables:
|
|
313
|
+
updated_interface.inputs.variables[var_name].description = desc
|
|
314
|
+
|
|
315
|
+
# Update output variable descriptions
|
|
316
|
+
if updated_interface.outputs and updated_interface.outputs.variables:
|
|
317
|
+
for var_name, desc in output_descriptions.items():
|
|
318
|
+
if var_name in updated_interface.outputs.variables:
|
|
319
|
+
updated_interface.outputs.variables[var_name].description = desc
|
|
320
|
+
|
|
321
|
+
return updated_interface
|
|
79
322
|
|
|
80
323
|
|
|
81
324
|
async def _build_image_bg(env_name: str, image: Image) -> Tuple[str, str]:
|
|
@@ -88,101 +331,163 @@ async def _build_image_bg(env_name: str, image: Image) -> Tuple[str, str]:
|
|
|
88
331
|
return env_name, await build.aio(image)
|
|
89
332
|
|
|
90
333
|
|
|
91
|
-
async def
|
|
334
|
+
async def _build_images(deployment: DeploymentPlan, image_refs: Dict[str, str] | None = None) -> ImageCache:
|
|
92
335
|
"""
|
|
93
336
|
Build the images for the given deployment plan and update the environment with the built image.
|
|
94
337
|
"""
|
|
338
|
+
from flyte._image import _DEFAULT_IMAGE_REF_NAME
|
|
339
|
+
|
|
95
340
|
from ._internal.imagebuild.image_builder import ImageCache
|
|
96
341
|
|
|
342
|
+
if image_refs is None:
|
|
343
|
+
image_refs = {}
|
|
344
|
+
|
|
97
345
|
images = []
|
|
98
346
|
image_identifier_map = {}
|
|
99
347
|
for env_name, env in deployment.envs.items():
|
|
100
348
|
if not isinstance(env.image, str):
|
|
101
|
-
|
|
349
|
+
if env.image._ref_name is not None:
|
|
350
|
+
if env.image._ref_name in image_refs:
|
|
351
|
+
# If the image is set in the config, set it as the base_image
|
|
352
|
+
image_uri = image_refs[env.image._ref_name]
|
|
353
|
+
env.image = env.image.clone(base_image=image_uri)
|
|
354
|
+
else:
|
|
355
|
+
raise ValueError(
|
|
356
|
+
f"Image name '{env.image._ref_name}' not found in config. Available: {list(image_refs.keys())}"
|
|
357
|
+
)
|
|
358
|
+
if not env.image._layers:
|
|
359
|
+
# No additional layers, use the base_image directly without building
|
|
360
|
+
image_identifier_map[env_name] = image_uri
|
|
361
|
+
continue
|
|
362
|
+
logger.debug(f"Building Image for environment {env_name}, image: {env.image}")
|
|
102
363
|
images.append(_build_image_bg(env_name, env.image))
|
|
103
364
|
|
|
104
365
|
elif env.image == "auto" and "auto" not in image_identifier_map:
|
|
105
|
-
|
|
106
|
-
|
|
366
|
+
if _DEFAULT_IMAGE_REF_NAME in image_refs:
|
|
367
|
+
# If the default image is set through CLI, use it instead
|
|
368
|
+
image_uri = image_refs[_DEFAULT_IMAGE_REF_NAME]
|
|
369
|
+
image_identifier_map[env_name] = image_uri
|
|
370
|
+
continue
|
|
371
|
+
auto_image = Image.from_debian_base()
|
|
372
|
+
images.append(_build_image_bg(env_name, auto_image))
|
|
107
373
|
final_images = await asyncio.gather(*images)
|
|
108
374
|
|
|
109
375
|
for env_name, image_uri in final_images:
|
|
110
|
-
logger.
|
|
111
|
-
|
|
112
|
-
if isinstance(env.image, Image):
|
|
113
|
-
image_identifier_map[env.image.identifier] = env.image.uri
|
|
376
|
+
logger.warning(f"Built Image for environment {env_name}, image: {image_uri}")
|
|
377
|
+
image_identifier_map[env_name] = image_uri
|
|
114
378
|
|
|
115
379
|
return ImageCache(image_lookup=image_identifier_map)
|
|
116
380
|
|
|
117
381
|
|
|
382
|
+
async def _deploy_task_env(context: DeploymentContext) -> DeployedTaskEnvironment:
|
|
383
|
+
"""
|
|
384
|
+
Deploy the given task environment.
|
|
385
|
+
"""
|
|
386
|
+
ensure_client()
|
|
387
|
+
env = context.environment
|
|
388
|
+
if not isinstance(env, TaskEnvironment):
|
|
389
|
+
raise ValueError(f"Expected TaskEnvironment, got {type(env)}")
|
|
390
|
+
|
|
391
|
+
task_coros = []
|
|
392
|
+
for task in env.tasks.values():
|
|
393
|
+
task_coros.append(_deploy_task(task, context.serialization_context, dryrun=context.dryrun))
|
|
394
|
+
deployed_task_vals = await asyncio.gather(*task_coros)
|
|
395
|
+
deployed_tasks = []
|
|
396
|
+
for t in deployed_task_vals:
|
|
397
|
+
deployed_tasks.append(t)
|
|
398
|
+
return DeployedTaskEnvironment(env=env, deployed_entities=deployed_tasks)
|
|
399
|
+
|
|
400
|
+
|
|
118
401
|
@requires_initialization
|
|
119
|
-
async def apply(
|
|
402
|
+
async def apply(deployment_plan: DeploymentPlan, copy_style: CopyFiles, dryrun: bool = False) -> Deployment:
|
|
403
|
+
import flyte.errors
|
|
404
|
+
|
|
120
405
|
from ._code_bundle import build_code_bundle
|
|
406
|
+
from ._deployer import DeploymentContext, get_deployer
|
|
407
|
+
|
|
408
|
+
cfg = get_init_config()
|
|
121
409
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if copy_style == "none":
|
|
125
|
-
|
|
126
|
-
assert deployment.version is not None, "Version must be set when copy_style is none"
|
|
410
|
+
image_cache = await _build_images(deployment_plan, cfg.images)
|
|
411
|
+
|
|
412
|
+
if copy_style == "none" and not deployment_plan.version:
|
|
413
|
+
raise flyte.errors.DeploymentError("Version must be set when copy_style is none")
|
|
127
414
|
else:
|
|
415
|
+
# if this is an AppEnvironment.include, skip code bundling here and build a code bundle at the
|
|
416
|
+
# app._deploy._deploy_app function
|
|
128
417
|
code_bundle = await build_code_bundle(from_dir=cfg.root_dir, dryrun=dryrun, copy_style=copy_style)
|
|
129
|
-
|
|
418
|
+
if deployment_plan.version:
|
|
419
|
+
version = deployment_plan.version
|
|
420
|
+
else:
|
|
421
|
+
h = hashlib.md5()
|
|
422
|
+
h.update(cloudpickle.dumps(deployment_plan.envs))
|
|
423
|
+
h.update(code_bundle.computed_version.encode("utf-8"))
|
|
424
|
+
h.update(cloudpickle.dumps(image_cache))
|
|
425
|
+
version = h.hexdigest()
|
|
130
426
|
|
|
131
427
|
sc = SerializationContext(
|
|
132
428
|
project=cfg.project,
|
|
133
429
|
domain=cfg.domain,
|
|
134
430
|
org=cfg.org,
|
|
135
431
|
code_bundle=code_bundle,
|
|
136
|
-
version=
|
|
432
|
+
version=version,
|
|
137
433
|
image_cache=image_cache,
|
|
138
434
|
root_dir=cfg.root_dir,
|
|
139
435
|
)
|
|
140
436
|
|
|
141
|
-
|
|
142
|
-
for env_name, env in
|
|
437
|
+
deployment_coros = []
|
|
438
|
+
for env_name, env in deployment_plan.envs.items():
|
|
143
439
|
logger.info(f"Deploying environment {env_name}")
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
440
|
+
deployer = get_deployer(type(env))
|
|
441
|
+
context = DeploymentContext(environment=env, serialization_context=sc, dryrun=dryrun)
|
|
442
|
+
deployment_coros.append(deployer(context))
|
|
443
|
+
deployed_envs = await asyncio.gather(*deployment_coros)
|
|
444
|
+
envs = {}
|
|
445
|
+
for d in deployed_envs:
|
|
446
|
+
envs[d.get_name()] = d
|
|
447
|
+
|
|
448
|
+
return Deployment(envs)
|
|
148
449
|
|
|
149
450
|
|
|
150
|
-
def _recursive_discover(
|
|
151
|
-
planned_envs: Dict[str, Environment], envs: Environment | List[Environment]
|
|
152
|
-
) -> Dict[str, Environment]:
|
|
451
|
+
def _recursive_discover(planned_envs: Dict[str, Environment], env: Environment) -> Dict[str, Environment]:
|
|
153
452
|
"""
|
|
154
453
|
Recursively deploy the environment and its dependencies, if not already deployed (present in env_tasks) and
|
|
155
454
|
return the updated env_tasks.
|
|
156
455
|
"""
|
|
157
|
-
if
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
planned_envs[env.name] = env
|
|
456
|
+
if env.name in planned_envs:
|
|
457
|
+
if planned_envs[env.name] is not env:
|
|
458
|
+
# Raise error if different TaskEnvironment objects have the same name
|
|
459
|
+
raise ValueError(f"Duplicate environment name '{env.name}' found")
|
|
460
|
+
# Add the environment to the existing envs
|
|
461
|
+
planned_envs[env.name] = env
|
|
462
|
+
|
|
463
|
+
# Recursively discover dependent environments
|
|
464
|
+
for dependent_env in env.depends_on:
|
|
465
|
+
_recursive_discover(planned_envs, dependent_env)
|
|
168
466
|
return planned_envs
|
|
169
467
|
|
|
170
468
|
|
|
171
|
-
def plan_deploy(*envs: Environment, version: Optional[str] = None) -> DeploymentPlan:
|
|
469
|
+
def plan_deploy(*envs: Environment, version: Optional[str] = None) -> List[DeploymentPlan]:
|
|
172
470
|
if envs is None:
|
|
173
|
-
return DeploymentPlan({})
|
|
174
|
-
|
|
175
|
-
|
|
471
|
+
return [DeploymentPlan({})]
|
|
472
|
+
deployment_plans = []
|
|
473
|
+
visited_envs: Set[str] = set()
|
|
474
|
+
for env in envs:
|
|
475
|
+
if env.name in visited_envs:
|
|
476
|
+
raise ValueError(f"Duplicate environment name '{env.name}' found")
|
|
477
|
+
planned_envs = _recursive_discover({}, env)
|
|
478
|
+
deployment_plans.append(DeploymentPlan(planned_envs, version=version))
|
|
479
|
+
visited_envs.update(planned_envs.keys())
|
|
480
|
+
return deployment_plans
|
|
176
481
|
|
|
177
482
|
|
|
178
|
-
@
|
|
483
|
+
@syncify
|
|
179
484
|
async def deploy(
|
|
180
485
|
*envs: Environment,
|
|
181
486
|
dryrun: bool = False,
|
|
182
487
|
version: str | None = None,
|
|
183
488
|
interactive_mode: bool | None = None,
|
|
184
489
|
copy_style: CopyFiles = "loaded_modules",
|
|
185
|
-
) -> Deployment:
|
|
490
|
+
) -> List[Deployment]:
|
|
186
491
|
"""
|
|
187
492
|
Deploy the given environment or list of environments.
|
|
188
493
|
:param envs: Environment or list of environments to deploy.
|
|
@@ -198,5 +503,21 @@ async def deploy(
|
|
|
198
503
|
"""
|
|
199
504
|
if interactive_mode:
|
|
200
505
|
raise NotImplementedError("Interactive mode not yet implemented for deployment")
|
|
201
|
-
|
|
202
|
-
|
|
506
|
+
deployment_plans = plan_deploy(*envs, version=version)
|
|
507
|
+
deployments = []
|
|
508
|
+
for deployment_plan in deployment_plans:
|
|
509
|
+
deployments.append(apply(deployment_plan, copy_style=copy_style, dryrun=dryrun))
|
|
510
|
+
return await asyncio.gather(*deployments)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
@syncify
|
|
514
|
+
async def build_images(envs: Environment) -> ImageCache:
|
|
515
|
+
"""
|
|
516
|
+
Build the images for the given environments.
|
|
517
|
+
:param envs: Environment to build images for.
|
|
518
|
+
:return: ImageCache containing the built images.
|
|
519
|
+
"""
|
|
520
|
+
cfg = get_init_config()
|
|
521
|
+
images = cfg.images if cfg else {}
|
|
522
|
+
deployment = plan_deploy(envs)
|
|
523
|
+
return await _build_images(deployment[0], images)
|
flyte/_deployer.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Dict, List, Protocol, Tuple, Type
|
|
5
|
+
|
|
6
|
+
import rich.repr
|
|
7
|
+
|
|
8
|
+
from flyte.models import SerializationContext
|
|
9
|
+
|
|
10
|
+
from ._deploy import _deploy_task_env
|
|
11
|
+
from ._environment import Environment
|
|
12
|
+
from ._task_environment import TaskEnvironment
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@rich.repr.auto
|
|
16
|
+
@dataclass
|
|
17
|
+
class DeploymentContext:
|
|
18
|
+
"""
|
|
19
|
+
Context for deployment operations.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
environment: Environment
|
|
23
|
+
serialization_context: SerializationContext
|
|
24
|
+
dryrun: bool = False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DeployedEnvironment(Protocol):
|
|
28
|
+
"""
|
|
29
|
+
Protocol for deployed environment representations.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def get_name(self) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Returns the name of the deployed environment.
|
|
35
|
+
Returns:
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
def env_repr(self) -> List[Tuple[str, ...]]:
|
|
40
|
+
"""
|
|
41
|
+
Returns a detailed representation of the deployed environment.
|
|
42
|
+
Returns:
|
|
43
|
+
"""
|
|
44
|
+
...
|
|
45
|
+
|
|
46
|
+
def table_repr(self) -> List[List[Tuple[str, ...]]]:
|
|
47
|
+
"""
|
|
48
|
+
Returns a detailed representation of the deployed entities in the environment, useful for tabular display.
|
|
49
|
+
Returns:
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
def summary_repr(self) -> str:
|
|
55
|
+
"""
|
|
56
|
+
Returns a summary representation of the deployed environment.
|
|
57
|
+
Returns:
|
|
58
|
+
"""
|
|
59
|
+
...
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class Deployer(Protocol):
|
|
63
|
+
"""
|
|
64
|
+
Protocol for deployment callables.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
async def __call__(self, context: DeploymentContext) -> DeployedEnvironment:
|
|
68
|
+
"""
|
|
69
|
+
Deploy the environment described in the context.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
context: Deployment context containing environment, serialization context, and dryrun flag
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Deployment result
|
|
76
|
+
"""
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
_ENVTYPE_REGISTRY: Dict[Type[Environment], Deployer] = {
|
|
81
|
+
TaskEnvironment: _deploy_task_env,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def register_deployer(env_type: Type[Environment], deployer: Deployer) -> None:
|
|
86
|
+
"""
|
|
87
|
+
Register a deployer for a specific environment type.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
env_type: Type of environment this deployer handles
|
|
91
|
+
deployer: Deployment callable that conforms to the Deployer protocol
|
|
92
|
+
"""
|
|
93
|
+
_ENVTYPE_REGISTRY[env_type] = deployer
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def get_deployer(env_type: Type[Environment | TaskEnvironment]) -> Deployer:
|
|
97
|
+
"""
|
|
98
|
+
Get the registered deployer for an environment type.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
env_type: Type of environment to get deployer for
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Deployer for the environment type, defaults to task environment deployer
|
|
105
|
+
"""
|
|
106
|
+
for tpe, v in _ENVTYPE_REGISTRY.items():
|
|
107
|
+
if issubclass(env_type, tpe):
|
|
108
|
+
return v
|
|
109
|
+
raise ValueError(f"No deployer registered for environment type {env_type}")
|