ob-metaflow-extensions 1.1.45rc3__py2.py3-none-any.whl → 1.5.1__py2.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 ob-metaflow-extensions might be problematic. Click here for more details.
- metaflow_extensions/outerbounds/__init__.py +1 -7
- metaflow_extensions/outerbounds/config/__init__.py +35 -0
- metaflow_extensions/outerbounds/plugins/__init__.py +186 -57
- metaflow_extensions/outerbounds/plugins/apps/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/apps/app_cli.py +0 -0
- metaflow_extensions/outerbounds/plugins/apps/app_utils.py +187 -0
- metaflow_extensions/outerbounds/plugins/apps/consts.py +3 -0
- metaflow_extensions/outerbounds/plugins/apps/core/__init__.py +15 -0
- metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py +506 -0
- metaflow_extensions/outerbounds/plugins/apps/core/_vendor/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/__init__.py +4 -0
- metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/spinners.py +478 -0
- metaflow_extensions/outerbounds/plugins/apps/core/app_config.py +128 -0
- metaflow_extensions/outerbounds/plugins/apps/core/app_deploy_decorator.py +330 -0
- metaflow_extensions/outerbounds/plugins/apps/core/artifacts.py +0 -0
- metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +958 -0
- metaflow_extensions/outerbounds/plugins/apps/core/click_importer.py +24 -0
- metaflow_extensions/outerbounds/plugins/apps/core/code_package/__init__.py +3 -0
- metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py +618 -0
- metaflow_extensions/outerbounds/plugins/apps/core/code_package/examples.py +125 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +15 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py +165 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py +966 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py +299 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py +233 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py +537 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +1125 -0
- metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml +337 -0
- metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py +115 -0
- metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +959 -0
- metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py +89 -0
- metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py +87 -0
- metaflow_extensions/outerbounds/plugins/apps/core/secrets.py +164 -0
- metaflow_extensions/outerbounds/plugins/apps/core/utils.py +233 -0
- metaflow_extensions/outerbounds/plugins/apps/core/validations.py +17 -0
- metaflow_extensions/outerbounds/plugins/apps/deploy_decorator.py +201 -0
- metaflow_extensions/outerbounds/plugins/apps/supervisord_utils.py +243 -0
- metaflow_extensions/outerbounds/plugins/auth_server.py +28 -8
- metaflow_extensions/outerbounds/plugins/aws/__init__.py +4 -0
- metaflow_extensions/outerbounds/plugins/aws/assume_role.py +3 -0
- metaflow_extensions/outerbounds/plugins/aws/assume_role_decorator.py +118 -0
- metaflow_extensions/outerbounds/plugins/card_utilities/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/card_utilities/async_cards.py +142 -0
- metaflow_extensions/outerbounds/plugins/card_utilities/extra_components.py +545 -0
- metaflow_extensions/outerbounds/plugins/card_utilities/injector.py +70 -0
- metaflow_extensions/outerbounds/plugins/checkpoint_datastores/__init__.py +2 -0
- metaflow_extensions/outerbounds/plugins/checkpoint_datastores/coreweave.py +71 -0
- metaflow_extensions/outerbounds/plugins/checkpoint_datastores/external_chckpt.py +85 -0
- metaflow_extensions/outerbounds/plugins/checkpoint_datastores/nebius.py +73 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/baker.py +110 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py +391 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py +188 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_cli.py +54 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_decorator.py +50 -0
- metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py +79 -0
- metaflow_extensions/outerbounds/plugins/kubernetes/pod_killer.py +374 -0
- metaflow_extensions/outerbounds/plugins/nim/card.py +140 -0
- metaflow_extensions/outerbounds/plugins/nim/nim_decorator.py +101 -0
- metaflow_extensions/outerbounds/plugins/nim/nim_manager.py +379 -0
- metaflow_extensions/outerbounds/plugins/nim/utils.py +36 -0
- metaflow_extensions/outerbounds/plugins/nvcf/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/nvcf/constants.py +3 -0
- metaflow_extensions/outerbounds/plugins/nvcf/exceptions.py +94 -0
- metaflow_extensions/outerbounds/plugins/nvcf/heartbeat_store.py +178 -0
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf.py +417 -0
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf_cli.py +280 -0
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py +242 -0
- metaflow_extensions/outerbounds/plugins/nvcf/utils.py +6 -0
- metaflow_extensions/outerbounds/plugins/nvct/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/nvct/exceptions.py +71 -0
- metaflow_extensions/outerbounds/plugins/nvct/nvct.py +131 -0
- metaflow_extensions/outerbounds/plugins/nvct/nvct_cli.py +289 -0
- metaflow_extensions/outerbounds/plugins/nvct/nvct_decorator.py +286 -0
- metaflow_extensions/outerbounds/plugins/nvct/nvct_runner.py +218 -0
- metaflow_extensions/outerbounds/plugins/nvct/utils.py +29 -0
- metaflow_extensions/outerbounds/plugins/ollama/__init__.py +225 -0
- metaflow_extensions/outerbounds/plugins/ollama/constants.py +1 -0
- metaflow_extensions/outerbounds/plugins/ollama/exceptions.py +22 -0
- metaflow_extensions/outerbounds/plugins/ollama/ollama.py +1924 -0
- metaflow_extensions/outerbounds/plugins/ollama/status_card.py +292 -0
- metaflow_extensions/outerbounds/plugins/optuna/__init__.py +48 -0
- metaflow_extensions/outerbounds/plugins/perimeters.py +19 -5
- metaflow_extensions/outerbounds/plugins/profilers/deco_injector.py +70 -0
- metaflow_extensions/outerbounds/plugins/profilers/gpu_profile_decorator.py +88 -0
- metaflow_extensions/outerbounds/plugins/profilers/simple_card_decorator.py +96 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/__init__.py +7 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/binary_caller.py +132 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/constants.py +11 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/exceptions.py +13 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/proxy_bootstrap.py +59 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_api.py +93 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_decorator.py +250 -0
- metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_manager.py +225 -0
- metaflow_extensions/outerbounds/plugins/secrets/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/secrets/secrets.py +204 -0
- metaflow_extensions/outerbounds/plugins/snowflake/__init__.py +3 -0
- metaflow_extensions/outerbounds/plugins/snowflake/snowflake.py +378 -0
- metaflow_extensions/outerbounds/plugins/snowpark/__init__.py +0 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py +309 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py +277 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_client.py +150 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_decorator.py +273 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_exceptions.py +13 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_job.py +241 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_service_spec.py +259 -0
- metaflow_extensions/outerbounds/plugins/tensorboard/__init__.py +50 -0
- metaflow_extensions/outerbounds/plugins/torchtune/__init__.py +163 -0
- metaflow_extensions/outerbounds/plugins/vllm/__init__.py +255 -0
- metaflow_extensions/outerbounds/plugins/vllm/constants.py +1 -0
- metaflow_extensions/outerbounds/plugins/vllm/exceptions.py +1 -0
- metaflow_extensions/outerbounds/plugins/vllm/status_card.py +352 -0
- metaflow_extensions/outerbounds/plugins/vllm/vllm_manager.py +621 -0
- metaflow_extensions/outerbounds/profilers/gpu.py +131 -47
- metaflow_extensions/outerbounds/remote_config.py +53 -16
- metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +138 -2
- metaflow_extensions/outerbounds/toplevel/ob_internal.py +4 -0
- metaflow_extensions/outerbounds/toplevel/plugins/ollama/__init__.py +1 -0
- metaflow_extensions/outerbounds/toplevel/plugins/optuna/__init__.py +1 -0
- metaflow_extensions/outerbounds/toplevel/plugins/snowflake/__init__.py +1 -0
- metaflow_extensions/outerbounds/toplevel/plugins/torchtune/__init__.py +1 -0
- metaflow_extensions/outerbounds/toplevel/plugins/vllm/__init__.py +1 -0
- metaflow_extensions/outerbounds/toplevel/s3_proxy.py +88 -0
- {ob_metaflow_extensions-1.1.45rc3.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/METADATA +2 -2
- ob_metaflow_extensions-1.5.1.dist-info/RECORD +133 -0
- ob_metaflow_extensions-1.1.45rc3.dist-info/RECORD +0 -19
- {ob_metaflow_extensions-1.1.45rc3.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/WHEEL +0 -0
- {ob_metaflow_extensions-1.1.45rc3.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples demonstrating how to use the code packager abstraction.
|
|
3
|
+
|
|
4
|
+
This file provides usage examples for the code packager classes.
|
|
5
|
+
These examples are for documentation purposes and are not meant to be run directly.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
from io import BytesIO
|
|
11
|
+
from typing import List, Dict, Any, Callable, Optional
|
|
12
|
+
|
|
13
|
+
from .code_packager import CodePackager
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def basic_usage_example(datastore_type: str = "s3") -> None:
|
|
17
|
+
"""
|
|
18
|
+
Basic usage example with ContentAddressedStore.
|
|
19
|
+
|
|
20
|
+
This example shows how to:
|
|
21
|
+
1. Define paths to include in a package
|
|
22
|
+
2. Create a package using CodePackager's default packaging
|
|
23
|
+
3. Store the package using ContentAddressedStore directly
|
|
24
|
+
4. Generate a download command
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
datastore_type : str, default "s3"
|
|
29
|
+
The type of datastore to use: "s3", "azure", "gs", or "local"
|
|
30
|
+
"""
|
|
31
|
+
# Define the paths to include in the package
|
|
32
|
+
paths_to_include = ["./"]
|
|
33
|
+
|
|
34
|
+
# Define which file suffixes to include
|
|
35
|
+
file_suffixes = [".py", ".md"]
|
|
36
|
+
|
|
37
|
+
# Create metadata for the package
|
|
38
|
+
metadata = {"example": True, "timestamp": "2023-01-01T00:00:00Z"}
|
|
39
|
+
|
|
40
|
+
# Initialize the packager with datastore configuration
|
|
41
|
+
packager = CodePackager(
|
|
42
|
+
datastore_type=datastore_type,
|
|
43
|
+
code_package_prefix="my-custom-prefix", # Optional
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Store the package with packaging parameters
|
|
47
|
+
package_url, package_key = packager.store(
|
|
48
|
+
paths_to_include=paths_to_include,
|
|
49
|
+
file_suffixes=file_suffixes,
|
|
50
|
+
metadata=metadata,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Generate a download command
|
|
54
|
+
download_cmd = CodePackager.get_download_cmd(
|
|
55
|
+
package_url=package_url,
|
|
56
|
+
datastore_type=datastore_type,
|
|
57
|
+
target_file="my_package.tar",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
# Generate complete package commands for downloading and setup
|
|
61
|
+
package_commands = packager.get_package_commands(
|
|
62
|
+
code_package_url=package_url,
|
|
63
|
+
target_file="my_package.tar",
|
|
64
|
+
working_dir="my_app",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Print some information
|
|
68
|
+
print(f"Package URL: {package_url}")
|
|
69
|
+
print(f"Package Key: {package_key}")
|
|
70
|
+
print(f"Download Command: {download_cmd}")
|
|
71
|
+
print(f"Complete package commands: {package_commands}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def usage_with_custom_package_function(datastore_type: str = "s3") -> None:
|
|
75
|
+
"""
|
|
76
|
+
Example of using the CodePackager with a custom package creation function.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
datastore_type : str, default "s3"
|
|
81
|
+
The type of datastore to use: "s3", "azure", "gs", or "local"
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
# Define a custom package function
|
|
85
|
+
def create_custom_package():
|
|
86
|
+
# This is a simple example - in real use, you might create a more complex package
|
|
87
|
+
from io import BytesIO
|
|
88
|
+
import tarfile
|
|
89
|
+
import time
|
|
90
|
+
|
|
91
|
+
buf = BytesIO()
|
|
92
|
+
with tarfile.open(fileobj=buf, mode="w:gz") as tar:
|
|
93
|
+
# Add a simple file to the tarball
|
|
94
|
+
content = b"print('Hello, custom package!')"
|
|
95
|
+
info = tarfile.TarInfo(name="hello.py")
|
|
96
|
+
info.size = len(content)
|
|
97
|
+
info.mtime = int(time.time())
|
|
98
|
+
file_object = BytesIO(content)
|
|
99
|
+
tar.addfile(info, file_object)
|
|
100
|
+
|
|
101
|
+
return bytearray(buf.getvalue())
|
|
102
|
+
|
|
103
|
+
# Initialize the packager with datastore configuration
|
|
104
|
+
packager = CodePackager(datastore_type=datastore_type)
|
|
105
|
+
|
|
106
|
+
# Store the package with the custom package function
|
|
107
|
+
package_url, package_key = packager.store(package_create_fn=create_custom_package)
|
|
108
|
+
|
|
109
|
+
# Generate a download command
|
|
110
|
+
download_cmd = CodePackager.get_download_cmd(
|
|
111
|
+
package_url=package_url,
|
|
112
|
+
datastore_type=datastore_type,
|
|
113
|
+
target_file="custom_package.tar",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Generate complete package commands
|
|
117
|
+
package_commands = packager.get_package_commands(
|
|
118
|
+
code_package_url=package_url,
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Print some information
|
|
122
|
+
print(f"Package URL: {package_url}")
|
|
123
|
+
print(f"Package Key: {package_key}")
|
|
124
|
+
print(f"Download Command: {download_cmd}")
|
|
125
|
+
print(f"Complete commands: {package_commands}")
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .unified_config import CoreConfig, PackagedCode, BakedImage, AuthType
|
|
2
|
+
from .cli_generator import auto_cli_options
|
|
3
|
+
from .config_utils import (
|
|
4
|
+
PureStringKVPairType,
|
|
5
|
+
JsonFriendlyKeyValuePairType,
|
|
6
|
+
CommaSeparatedListType,
|
|
7
|
+
MergingNotAllowedFieldsException,
|
|
8
|
+
ConfigValidationFailedException,
|
|
9
|
+
RequiredFieldMissingException,
|
|
10
|
+
ConfigFieldContext,
|
|
11
|
+
ConfigField,
|
|
12
|
+
FieldBehavior,
|
|
13
|
+
)
|
|
14
|
+
from . import schema_export
|
|
15
|
+
from .typed_configs import TypedCoreConfig, TypedDict
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI Generator for Unified Configuration System
|
|
3
|
+
|
|
4
|
+
This module automatically generates Click CLI options from the CoreConfig,
|
|
5
|
+
eliminating the need for manual CLI option definitions and ensuring consistency
|
|
6
|
+
between configuration structure and CLI interface.
|
|
7
|
+
|
|
8
|
+
It also provides machinery for merging configurations from different sources
|
|
9
|
+
(CLI options, config files) with proper precedence and behavior handling.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Any, List, Optional
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
from ..click_importer import click
|
|
16
|
+
from .unified_config import (
|
|
17
|
+
CoreConfig,
|
|
18
|
+
CLIOption,
|
|
19
|
+
ConfigMeta,
|
|
20
|
+
)
|
|
21
|
+
from .config_utils import (
|
|
22
|
+
PureStringKVPairType,
|
|
23
|
+
JsonFriendlyKeyValuePairType,
|
|
24
|
+
CommaSeparatedListType,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class CLIGenerator:
|
|
29
|
+
"""Generates Click CLI options from CoreConfig dataclass."""
|
|
30
|
+
|
|
31
|
+
def __init__(self, config_class: type = CoreConfig):
|
|
32
|
+
self.config_class = config_class
|
|
33
|
+
self._type_mapping = {
|
|
34
|
+
str: str,
|
|
35
|
+
int: int,
|
|
36
|
+
float: float,
|
|
37
|
+
bool: bool,
|
|
38
|
+
list: CommaSeparatedListType,
|
|
39
|
+
dict: JsonFriendlyKeyValuePairType,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def generate_options(self):
|
|
43
|
+
"""Generate all CLI options from the configuration class."""
|
|
44
|
+
options = []
|
|
45
|
+
|
|
46
|
+
# Generate options for all fields automatically
|
|
47
|
+
options.extend(self._generate_all_options(self.config_class))
|
|
48
|
+
|
|
49
|
+
return options
|
|
50
|
+
|
|
51
|
+
def _generate_all_options(self, config_class: type):
|
|
52
|
+
"""Generate all options from a config class. Returns a list of click.Options"""
|
|
53
|
+
|
|
54
|
+
def _options_from_cfg_cls(_config_class):
|
|
55
|
+
options = []
|
|
56
|
+
for field_name, field_info in _config_class._fields.items():
|
|
57
|
+
# Skip fields not available in CLI context
|
|
58
|
+
if not field_info.is_available_in_cli():
|
|
59
|
+
continue
|
|
60
|
+
|
|
61
|
+
if ConfigMeta.is_instance(field_info.field_type):
|
|
62
|
+
_subfield_options = _options_from_cfg_cls(field_info.field_type)
|
|
63
|
+
options.extend(_subfield_options)
|
|
64
|
+
continue
|
|
65
|
+
|
|
66
|
+
cli_meta = field_info.cli_meta
|
|
67
|
+
if not cli_meta or cli_meta.hidden:
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
option = self._create_option(field_name, field_info, cli_meta)
|
|
71
|
+
if option:
|
|
72
|
+
options.append(option)
|
|
73
|
+
return options
|
|
74
|
+
|
|
75
|
+
return _options_from_cfg_cls(config_class)
|
|
76
|
+
|
|
77
|
+
def _create_option(self, field_name: str, field_info, cli_meta: CLIOption):
|
|
78
|
+
"""Create a Click option from field info and CLI metadata."""
|
|
79
|
+
# Use the cli_option_str from the CLIOption
|
|
80
|
+
option_str = cli_meta.cli_option_str
|
|
81
|
+
param_name = cli_meta.name
|
|
82
|
+
|
|
83
|
+
# Determine Click type
|
|
84
|
+
click_type = self._get_click_type(field_info, cli_meta)
|
|
85
|
+
|
|
86
|
+
# Build option parameters
|
|
87
|
+
help_text = cli_meta.help or field_info.help or f"Set {field_name}"
|
|
88
|
+
option_params = {
|
|
89
|
+
"help": help_text,
|
|
90
|
+
"default": cli_meta.default if cli_meta.default is not None else None,
|
|
91
|
+
"type": click_type,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# Handle multiple values
|
|
95
|
+
if cli_meta.multiple:
|
|
96
|
+
option_params["multiple"] = True
|
|
97
|
+
|
|
98
|
+
# Handle choices
|
|
99
|
+
if cli_meta.choices:
|
|
100
|
+
option_params["type"] = click.Choice(cli_meta.choices)
|
|
101
|
+
|
|
102
|
+
# Handle flags
|
|
103
|
+
if cli_meta.is_flag:
|
|
104
|
+
option_params["is_flag"] = True
|
|
105
|
+
option_params.pop("type", None)
|
|
106
|
+
|
|
107
|
+
# Handle special flag patterns (e.g., --public-access/--private-access)
|
|
108
|
+
return click.option(option_str, param_name, **option_params)
|
|
109
|
+
|
|
110
|
+
def _get_click_type(self, field_info, cli_meta: CLIOption) -> Any:
|
|
111
|
+
"""Determine the appropriate Click type for a field."""
|
|
112
|
+
if cli_meta.click_type:
|
|
113
|
+
return cli_meta.click_type
|
|
114
|
+
|
|
115
|
+
# Get the field type
|
|
116
|
+
field_type = field_info.field_type
|
|
117
|
+
|
|
118
|
+
# Handle basic types
|
|
119
|
+
if field_type == list:
|
|
120
|
+
return CommaSeparatedListType
|
|
121
|
+
elif field_type == dict:
|
|
122
|
+
return JsonFriendlyKeyValuePairType
|
|
123
|
+
elif field_type == str:
|
|
124
|
+
return str
|
|
125
|
+
elif field_type == int:
|
|
126
|
+
return int
|
|
127
|
+
elif field_type == bool:
|
|
128
|
+
return bool
|
|
129
|
+
elif field_type == float:
|
|
130
|
+
return float
|
|
131
|
+
|
|
132
|
+
# Handle custom config types
|
|
133
|
+
if hasattr(field_type, "__name__") and field_type.__name__.endswith("Config"):
|
|
134
|
+
return str # Default to string for complex types
|
|
135
|
+
|
|
136
|
+
# Use type mapping
|
|
137
|
+
return self._type_mapping.get(field_type, str)
|
|
138
|
+
|
|
139
|
+
def create_decorator(self, command_type: str = "deploy") -> callable:
|
|
140
|
+
"""Create a decorator that applies all CLI options to a command."""
|
|
141
|
+
|
|
142
|
+
def decorator(func):
|
|
143
|
+
# Apply options in reverse order since decorators are applied bottom-up
|
|
144
|
+
for option in reversed(self.generate_options()):
|
|
145
|
+
func = option(func)
|
|
146
|
+
return func
|
|
147
|
+
|
|
148
|
+
return decorator
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def auto_cli_options(config_class: type = CoreConfig, command_type: str = "deploy"):
|
|
152
|
+
"""
|
|
153
|
+
Decorator that automatically adds CLI options from CoreConfig.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
command_type: Type of command (e.g., "deploy", "list", "delete")
|
|
157
|
+
|
|
158
|
+
Usage:
|
|
159
|
+
@auto_cli_options("deploy")
|
|
160
|
+
def deploy_command(**kwargs):
|
|
161
|
+
config = CoreConfig.from_cli(kwargs)
|
|
162
|
+
# ... use config
|
|
163
|
+
"""
|
|
164
|
+
generator = CLIGenerator(config_class)
|
|
165
|
+
return generator.create_decorator(command_type)
|