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/cli/_get.py
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import os
|
|
3
|
+
from typing import Tuple, Union
|
|
4
|
+
|
|
5
|
+
import rich_click as click
|
|
6
|
+
from rich.pretty import pretty_repr
|
|
7
|
+
|
|
8
|
+
import flyte.remote as remote
|
|
9
|
+
from flyte.models import ActionPhase
|
|
10
|
+
|
|
11
|
+
from . import _common as common
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(name="get")
|
|
15
|
+
def get():
|
|
16
|
+
"""
|
|
17
|
+
Retrieve resources from a Flyte deployment.
|
|
18
|
+
|
|
19
|
+
You can get information about projects, runs, tasks, actions, secrets, logs and input/output values.
|
|
20
|
+
|
|
21
|
+
Each command supports optional parameters to filter or specify the resource you want to retrieve.
|
|
22
|
+
|
|
23
|
+
Using a `get` subcommand without any arguments will retrieve a list of available resources to get.
|
|
24
|
+
For example:
|
|
25
|
+
|
|
26
|
+
* `get project` (without specifying a project), will list all projects.
|
|
27
|
+
* `get project my_project` will return the details of the project named `my_project`.
|
|
28
|
+
|
|
29
|
+
In some cases, a partially specified command will act as a filter and return available further parameters.
|
|
30
|
+
For example:
|
|
31
|
+
|
|
32
|
+
* `get action my_run` will return all actions for the run named `my_run`.
|
|
33
|
+
* `get action my_run my_action` will return the details of the action named `my_action` for the run `my_run`.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@get.command()
|
|
38
|
+
@click.argument("name", type=str, required=False)
|
|
39
|
+
@click.pass_obj
|
|
40
|
+
def project(cfg: common.CLIConfig, name: str | None = None):
|
|
41
|
+
"""
|
|
42
|
+
Get a list of all projects, or details of a specific project by name.
|
|
43
|
+
"""
|
|
44
|
+
cfg.init()
|
|
45
|
+
|
|
46
|
+
console = common.get_console()
|
|
47
|
+
if name:
|
|
48
|
+
console.print(pretty_repr(remote.Project.get(name)))
|
|
49
|
+
else:
|
|
50
|
+
console.print(common.format("Projects", remote.Project.listall(), cfg.output_format))
|
|
51
|
+
os._exit(0)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@get.command(cls=common.CommandBase)
|
|
55
|
+
@click.argument("name", type=str, required=False)
|
|
56
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of runs to fetch when listing.")
|
|
57
|
+
@click.option(
|
|
58
|
+
"--in-phase", # multiple=True, TODO support multiple phases once values in works
|
|
59
|
+
type=click.Choice([p.value for p in ActionPhase], case_sensitive=False),
|
|
60
|
+
help="Filter runs by their status.",
|
|
61
|
+
)
|
|
62
|
+
@click.option("--only-mine", is_flag=True, default=False, help="Show only runs created by the current user (you).")
|
|
63
|
+
@click.option("--task-name", type=str, default=None, help="Filter runs by task name.")
|
|
64
|
+
@click.option("--task-version", type=str, default=None, help="Filter runs by task version.")
|
|
65
|
+
@click.pass_obj
|
|
66
|
+
def run(
|
|
67
|
+
cfg: common.CLIConfig,
|
|
68
|
+
name: str | None = None,
|
|
69
|
+
project: str | None = None,
|
|
70
|
+
domain: str | None = None,
|
|
71
|
+
limit: int = 100,
|
|
72
|
+
in_phase: str | Tuple[str, ...] | None = None,
|
|
73
|
+
only_mine: bool = False,
|
|
74
|
+
task_name: str | None = None,
|
|
75
|
+
task_version: str | None = None,
|
|
76
|
+
):
|
|
77
|
+
"""
|
|
78
|
+
Get a list of all runs, or details of a specific run by name.
|
|
79
|
+
|
|
80
|
+
The run details will include information about the run, its status, but only the root action will be shown.
|
|
81
|
+
|
|
82
|
+
If you want to see the actions for a run, use `get action <run_name>`.
|
|
83
|
+
|
|
84
|
+
You can filter runs by task name and optionally task version:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
$ flyte get run --task-name my_task
|
|
88
|
+
$ flyte get run --task-name my_task --task-version v1.0
|
|
89
|
+
```
|
|
90
|
+
"""
|
|
91
|
+
|
|
92
|
+
cfg.init(project=project, domain=domain)
|
|
93
|
+
|
|
94
|
+
console = common.get_console()
|
|
95
|
+
if name:
|
|
96
|
+
details = remote.RunDetails.get(name=name)
|
|
97
|
+
console.print(common.format(f"Run {name}", [details], "json"))
|
|
98
|
+
else:
|
|
99
|
+
if in_phase and isinstance(in_phase, str):
|
|
100
|
+
in_phase = (ActionPhase(in_phase),)
|
|
101
|
+
|
|
102
|
+
subject = None
|
|
103
|
+
if only_mine:
|
|
104
|
+
usr = remote.User.get()
|
|
105
|
+
subject = usr.subject()
|
|
106
|
+
|
|
107
|
+
console.print(
|
|
108
|
+
common.format(
|
|
109
|
+
"Runs",
|
|
110
|
+
remote.Run.listall(
|
|
111
|
+
limit=limit,
|
|
112
|
+
in_phase=in_phase,
|
|
113
|
+
created_by_subject=subject,
|
|
114
|
+
task_name=task_name,
|
|
115
|
+
task_version=task_version,
|
|
116
|
+
),
|
|
117
|
+
cfg.output_format,
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@get.command(cls=common.CommandBase)
|
|
123
|
+
@click.argument("name", type=str, required=False)
|
|
124
|
+
@click.argument("version", type=str, required=False)
|
|
125
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of tasks to fetch.")
|
|
126
|
+
@click.pass_obj
|
|
127
|
+
def task(
|
|
128
|
+
cfg: common.CLIConfig,
|
|
129
|
+
name: str | None = None,
|
|
130
|
+
limit: int = 100,
|
|
131
|
+
version: str | None = None,
|
|
132
|
+
project: str | None = None,
|
|
133
|
+
domain: str | None = None,
|
|
134
|
+
):
|
|
135
|
+
"""
|
|
136
|
+
Retrieve a list of all tasks, or details of a specific task by name and version.
|
|
137
|
+
|
|
138
|
+
Currently, both `name` and `version` are required to get a specific task.
|
|
139
|
+
"""
|
|
140
|
+
cfg.init(project=project, domain=domain)
|
|
141
|
+
|
|
142
|
+
console = common.get_console()
|
|
143
|
+
if name:
|
|
144
|
+
if version:
|
|
145
|
+
v = remote.Task.get(name=name, version=version)
|
|
146
|
+
if v is None:
|
|
147
|
+
raise click.BadParameter(f"Task {name} not found.")
|
|
148
|
+
t = v.fetch()
|
|
149
|
+
console.print(common.format(f"Task {name}", [t], "json"))
|
|
150
|
+
else:
|
|
151
|
+
console.print(
|
|
152
|
+
common.format("Tasks", remote.Task.listall(by_task_name=name, limit=limit), cfg.output_format)
|
|
153
|
+
)
|
|
154
|
+
else:
|
|
155
|
+
console.print(common.format("Tasks", remote.Task.listall(limit=limit), cfg.output_format))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@get.command(cls=common.CommandBase)
|
|
159
|
+
@click.argument("run_name", type=str, required=True)
|
|
160
|
+
@click.argument("action_name", type=str, required=False)
|
|
161
|
+
@click.option(
|
|
162
|
+
"--in-phase",
|
|
163
|
+
type=click.Choice([p.value for p in ActionPhase], case_sensitive=False),
|
|
164
|
+
help="Filter actions by their phase.",
|
|
165
|
+
)
|
|
166
|
+
@click.pass_obj
|
|
167
|
+
def action(
|
|
168
|
+
cfg: common.CLIConfig,
|
|
169
|
+
run_name: str,
|
|
170
|
+
action_name: str | None = None,
|
|
171
|
+
in_phase: str | None = None,
|
|
172
|
+
project: str | None = None,
|
|
173
|
+
domain: str | None = None,
|
|
174
|
+
):
|
|
175
|
+
"""
|
|
176
|
+
Get all actions for a run or details for a specific action.
|
|
177
|
+
"""
|
|
178
|
+
cfg.init(project=project, domain=domain)
|
|
179
|
+
|
|
180
|
+
console = common.get_console()
|
|
181
|
+
if action_name:
|
|
182
|
+
console.print(
|
|
183
|
+
common.format(
|
|
184
|
+
f"Action {run_name}.{action_name}", [remote.Action.get(run_name=run_name, name=action_name)], "json"
|
|
185
|
+
)
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
# List all actions for the run
|
|
189
|
+
if in_phase:
|
|
190
|
+
in_phase_tuple = (ActionPhase(in_phase),)
|
|
191
|
+
else:
|
|
192
|
+
in_phase_tuple = None
|
|
193
|
+
|
|
194
|
+
console.print(
|
|
195
|
+
common.format(
|
|
196
|
+
f"Actions for {run_name}",
|
|
197
|
+
remote.Action.listall(for_run_name=run_name, in_phase=in_phase_tuple),
|
|
198
|
+
cfg.output_format,
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@get.command(cls=common.CommandBase)
|
|
204
|
+
@click.argument("run_name", type=str, required=True)
|
|
205
|
+
@click.argument("action_name", type=str, required=False)
|
|
206
|
+
@click.option("--lines", "-l", type=int, default=30, help="Number of lines to show, only useful for --pretty")
|
|
207
|
+
@click.option("--show-ts", is_flag=True, help="Show timestamps")
|
|
208
|
+
@click.option(
|
|
209
|
+
"--pretty",
|
|
210
|
+
is_flag=True,
|
|
211
|
+
default=False,
|
|
212
|
+
help="Show logs in an auto-scrolling box, where number of lines is limited to `--lines`",
|
|
213
|
+
)
|
|
214
|
+
@click.option(
|
|
215
|
+
"--attempt", "-a", type=int, default=None, help="Attempt number to show logs for, defaults to the latest attempt."
|
|
216
|
+
)
|
|
217
|
+
@click.option("--filter-system", is_flag=True, default=False, help="Filter all system logs from the output.")
|
|
218
|
+
@click.pass_obj
|
|
219
|
+
def logs(
|
|
220
|
+
cfg: common.CLIConfig,
|
|
221
|
+
run_name: str,
|
|
222
|
+
action_name: str | None = None,
|
|
223
|
+
project: str | None = None,
|
|
224
|
+
domain: str | None = None,
|
|
225
|
+
lines: int = 30,
|
|
226
|
+
show_ts: bool = False,
|
|
227
|
+
pretty: bool = True,
|
|
228
|
+
attempt: int | None = None,
|
|
229
|
+
filter_system: bool = False,
|
|
230
|
+
):
|
|
231
|
+
"""
|
|
232
|
+
Stream logs for the provided run or action.
|
|
233
|
+
If only the run is provided, only the logs for the parent action will be streamed:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
$ flyte get logs my_run
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
If you want to see the logs for a specific action, you can provide the action name as well:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
$ flyte get logs my_run my_action
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
By default, logs will be shown in the raw format and will scroll the terminal.
|
|
246
|
+
If automatic scrolling and only tailing `--lines` number of lines is desired, use the `--pretty` flag:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
$ flyte get logs my_run my_action --pretty --lines 50
|
|
250
|
+
```
|
|
251
|
+
"""
|
|
252
|
+
cfg.init(project=project, domain=domain)
|
|
253
|
+
|
|
254
|
+
async def _run_log_view(_obj):
|
|
255
|
+
task = asyncio.create_task(
|
|
256
|
+
_obj.show_logs.aio(
|
|
257
|
+
max_lines=lines, show_ts=show_ts, raw=not pretty, attempt=attempt, filter_system=filter_system
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
try:
|
|
261
|
+
await task
|
|
262
|
+
except KeyboardInterrupt:
|
|
263
|
+
task.cancel()
|
|
264
|
+
|
|
265
|
+
obj: Union[remote.Action, remote.Run]
|
|
266
|
+
if action_name:
|
|
267
|
+
obj = remote.Action.get(run_name=run_name, name=action_name)
|
|
268
|
+
else:
|
|
269
|
+
obj = remote.Run.get(name=run_name)
|
|
270
|
+
asyncio.run(_run_log_view(obj))
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@get.command(cls=common.CommandBase)
|
|
274
|
+
@click.argument("name", type=str, required=False)
|
|
275
|
+
@click.pass_obj
|
|
276
|
+
def secret(
|
|
277
|
+
cfg: common.CLIConfig,
|
|
278
|
+
name: str | None = None,
|
|
279
|
+
project: str | None = None,
|
|
280
|
+
domain: str | None = None,
|
|
281
|
+
):
|
|
282
|
+
"""
|
|
283
|
+
Get a list of all secrets, or details of a specific secret by name.
|
|
284
|
+
"""
|
|
285
|
+
if project is None:
|
|
286
|
+
project = ""
|
|
287
|
+
if domain is None:
|
|
288
|
+
domain = ""
|
|
289
|
+
cfg.init(project=project, domain=domain)
|
|
290
|
+
|
|
291
|
+
console = common.get_console()
|
|
292
|
+
if name:
|
|
293
|
+
console.print(common.format("Secret", [remote.Secret.get(name)], "json"))
|
|
294
|
+
else:
|
|
295
|
+
console.print(common.format("Secrets", remote.Secret.listall(), cfg.output_format))
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@get.command(cls=common.CommandBase)
|
|
299
|
+
@click.argument("run_name", type=str, required=True)
|
|
300
|
+
@click.argument("action_name", type=str, required=False)
|
|
301
|
+
@click.option("--inputs-only", "-i", is_flag=True, help="Show only inputs")
|
|
302
|
+
@click.option("--outputs-only", "-o", is_flag=True, help="Show only outputs")
|
|
303
|
+
@click.pass_obj
|
|
304
|
+
def io(
|
|
305
|
+
cfg: common.CLIConfig,
|
|
306
|
+
run_name: str,
|
|
307
|
+
action_name: str | None = None,
|
|
308
|
+
project: str | None = None,
|
|
309
|
+
domain: str | None = None,
|
|
310
|
+
inputs_only: bool = False,
|
|
311
|
+
outputs_only: bool = False,
|
|
312
|
+
):
|
|
313
|
+
"""
|
|
314
|
+
Get the inputs and outputs of a run or action.
|
|
315
|
+
If only the run name is provided, it will show the inputs and outputs of the root action of that run.
|
|
316
|
+
If an action name is provided, it will show the inputs and outputs for that action.
|
|
317
|
+
If `--inputs-only` or `--outputs-only` is specified, it will only show the inputs or outputs respectively.
|
|
318
|
+
|
|
319
|
+
Examples:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
$ flyte get io my_run
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
$ flyte get io my_run my_action
|
|
327
|
+
```
|
|
328
|
+
"""
|
|
329
|
+
if inputs_only and outputs_only:
|
|
330
|
+
raise click.BadParameter("Cannot use both --inputs-only and --outputs-only")
|
|
331
|
+
|
|
332
|
+
cfg.init(project=project, domain=domain)
|
|
333
|
+
console = common.get_console()
|
|
334
|
+
obj: Union[remote.ActionDetails, remote.RunDetails]
|
|
335
|
+
if action_name:
|
|
336
|
+
obj = remote.ActionDetails.get(run_name=run_name, name=action_name)
|
|
337
|
+
else:
|
|
338
|
+
obj = remote.RunDetails.get(name=run_name)
|
|
339
|
+
|
|
340
|
+
async def _get_io(
|
|
341
|
+
details: Union[remote.RunDetails, remote.ActionDetails],
|
|
342
|
+
) -> Tuple[remote.ActionInputs | None, remote.ActionOutputs | None | str]:
|
|
343
|
+
if inputs_only or outputs_only:
|
|
344
|
+
if inputs_only:
|
|
345
|
+
return await details.inputs(), None
|
|
346
|
+
elif outputs_only:
|
|
347
|
+
return None, await details.outputs()
|
|
348
|
+
inputs = await details.inputs()
|
|
349
|
+
outputs: remote.ActionOutputs | None | str = None
|
|
350
|
+
try:
|
|
351
|
+
outputs = await details.outputs()
|
|
352
|
+
except Exception:
|
|
353
|
+
# If the outputs are not available, we can still show the inputs
|
|
354
|
+
outputs = "[red]not yet available[/red]"
|
|
355
|
+
return inputs, outputs
|
|
356
|
+
|
|
357
|
+
inputs, outputs = asyncio.run(_get_io(obj))
|
|
358
|
+
# Show inputs and outputs side by side
|
|
359
|
+
console.print(
|
|
360
|
+
common.get_panel(
|
|
361
|
+
"Inputs & Outputs",
|
|
362
|
+
f"[green bold]Inputs[/green bold]\n{inputs}\n\n[blue bold]Outputs[/blue bold]\n{outputs}",
|
|
363
|
+
cfg.output_format,
|
|
364
|
+
)
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
@get.command(cls=click.RichCommand)
|
|
369
|
+
@click.pass_obj
|
|
370
|
+
def config(cfg: common.CLIConfig):
|
|
371
|
+
"""
|
|
372
|
+
Shows the automatically detected configuration to connect with the remote backend.
|
|
373
|
+
|
|
374
|
+
The configuration will include the endpoint, organization, and other settings that are used by the CLI.
|
|
375
|
+
"""
|
|
376
|
+
console = common.get_console()
|
|
377
|
+
console.print(cfg)
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
@get.command(cls=common.CommandBase)
|
|
381
|
+
@click.argument("task_name", type=str, required=False)
|
|
382
|
+
@click.argument("name", type=str, required=False)
|
|
383
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of triggers to fetch.")
|
|
384
|
+
@click.pass_obj
|
|
385
|
+
def trigger(
|
|
386
|
+
cfg: common.CLIConfig,
|
|
387
|
+
task_name: str | None = None,
|
|
388
|
+
name: str | None = None,
|
|
389
|
+
limit: int = 100,
|
|
390
|
+
project: str | None = None,
|
|
391
|
+
domain: str | None = None,
|
|
392
|
+
):
|
|
393
|
+
"""
|
|
394
|
+
Get a list of all triggers, or details of a specific trigger by name.
|
|
395
|
+
"""
|
|
396
|
+
if name and not task_name:
|
|
397
|
+
raise click.BadParameter("If you provide a trigger name, you must also provide the task name.")
|
|
398
|
+
|
|
399
|
+
from flyte.remote import Trigger
|
|
400
|
+
|
|
401
|
+
cfg.init(project=project, domain=domain)
|
|
402
|
+
|
|
403
|
+
console = common.get_console()
|
|
404
|
+
if name:
|
|
405
|
+
console.print(pretty_repr(Trigger.get(name=name, task_name=task_name)))
|
|
406
|
+
else:
|
|
407
|
+
console.print(common.format("Triggers", Trigger.listall(task_name=task_name, limit=limit), cfg.output_format))
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
@get.command(cls=common.CommandBase)
|
|
411
|
+
@click.argument("name", type=str, required=False)
|
|
412
|
+
@click.option("--limit", type=int, default=100, help="Limit the number of apps to fetch when listing.")
|
|
413
|
+
@click.option("--only-mine", is_flag=True, default=False, help="Show only apps created by the current user (you).")
|
|
414
|
+
@click.pass_obj
|
|
415
|
+
def app(
|
|
416
|
+
cfg: common.CLIConfig,
|
|
417
|
+
name: str | None = None,
|
|
418
|
+
project: str | None = None,
|
|
419
|
+
domain: str | None = None,
|
|
420
|
+
limit: int = 100,
|
|
421
|
+
only_mine: bool = False,
|
|
422
|
+
):
|
|
423
|
+
"""
|
|
424
|
+
Get a list of all apps, or details of a specific app by name.
|
|
425
|
+
|
|
426
|
+
Apps are long-running services deployed on the Flyte platform.
|
|
427
|
+
"""
|
|
428
|
+
cfg.init(project=project, domain=domain)
|
|
429
|
+
|
|
430
|
+
console = common.get_console()
|
|
431
|
+
if name:
|
|
432
|
+
app_details = remote.App.get(name=name)
|
|
433
|
+
console.print(common.format(f"App {name}", [app_details], "json"))
|
|
434
|
+
else:
|
|
435
|
+
subject = None
|
|
436
|
+
if only_mine:
|
|
437
|
+
usr = remote.User.get()
|
|
438
|
+
subject = usr.subject()
|
|
439
|
+
|
|
440
|
+
console.print(
|
|
441
|
+
common.format(
|
|
442
|
+
"Apps",
|
|
443
|
+
remote.App.listall(limit=limit, created_by_subject=subject),
|
|
444
|
+
cfg.output_format,
|
|
445
|
+
)
|
|
446
|
+
)
|
flyte/cli/_option.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from click import Option, UsageError
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class MutuallyExclusiveMixin:
|
|
5
|
+
def __init__(self, *args, **kwargs):
|
|
6
|
+
self.mutually_exclusive = set(kwargs.pop("mutually_exclusive", []))
|
|
7
|
+
self.error_format = kwargs.pop(
|
|
8
|
+
"error_msg", "Illegal usage: options '{name}' and '{invalid}' are mutually exclusive"
|
|
9
|
+
)
|
|
10
|
+
super().__init__(*args, **kwargs)
|
|
11
|
+
|
|
12
|
+
def handle_parse_result(self, ctx, opts, args):
|
|
13
|
+
self_present = self.name in opts and opts[self.name] is not None
|
|
14
|
+
others_intersect = self.mutually_exclusive.intersection(opts)
|
|
15
|
+
others_present = others_intersect and any(opts[value] is not None for value in others_intersect)
|
|
16
|
+
|
|
17
|
+
if others_present:
|
|
18
|
+
if self_present:
|
|
19
|
+
raise UsageError(self.error_format.format(name=self.name, invalid=", ".join(self.mutually_exclusive)))
|
|
20
|
+
else:
|
|
21
|
+
self.prompt = None
|
|
22
|
+
|
|
23
|
+
return super().handle_parse_result(ctx, opts, args)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# See https://stackoverflow.com/a/37491504/499285 and https://stackoverflow.com/a/44349292/499285
|
|
27
|
+
class MutuallyExclusiveOption(MutuallyExclusiveMixin, Option):
|
|
28
|
+
def __init__(self, *args, **kwargs):
|
|
29
|
+
mutually_exclusive = kwargs.get("mutually_exclusive", [])
|
|
30
|
+
help = kwargs.get("help", "")
|
|
31
|
+
if mutually_exclusive:
|
|
32
|
+
kwargs["help"] = help + f" Mutually exclusive with {', '.join(mutually_exclusive)}."
|
|
33
|
+
super().__init__(*args, **kwargs)
|