ob-metaflow-extensions 1.1.130__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 -1
- metaflow_extensions/outerbounds/plugins/__init__.py +34 -4
- 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/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/injector.py +1 -1
- 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/baker.py +110 -0
- metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py +43 -9
- metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py +12 -0
- metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py +18 -44
- metaflow_extensions/outerbounds/plugins/kubernetes/pod_killer.py +374 -0
- metaflow_extensions/outerbounds/plugins/nim/card.py +2 -16
- metaflow_extensions/outerbounds/plugins/nim/{__init__.py → nim_decorator.py} +13 -49
- metaflow_extensions/outerbounds/plugins/nim/nim_manager.py +294 -233
- metaflow_extensions/outerbounds/plugins/nim/utils.py +36 -0
- metaflow_extensions/outerbounds/plugins/nvcf/constants.py +2 -2
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf.py +100 -19
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py +6 -1
- 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/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/secrets.py +38 -2
- metaflow_extensions/outerbounds/plugins/snowflake/snowflake.py +81 -11
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py +18 -8
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py +6 -0
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_client.py +45 -18
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_decorator.py +18 -9
- metaflow_extensions/outerbounds/plugins/snowpark/snowpark_job.py +10 -4
- 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/remote_config.py +46 -9
- metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +94 -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/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.130.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/METADATA +2 -2
- ob_metaflow_extensions-1.5.1.dist-info/RECORD +133 -0
- metaflow_extensions/outerbounds/plugins/nim/utilities.py +0 -5
- ob_metaflow_extensions-1.1.130.dist-info/RECORD +0 -56
- {ob_metaflow_extensions-1.1.130.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/WHEEL +0 -0
- {ob_metaflow_extensions-1.1.130.dist-info → ob_metaflow_extensions-1.5.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Schema Export Module for Unified Configuration System
|
|
3
|
+
|
|
4
|
+
This module provides standalone functions to export configuration schemas in various formats:
|
|
5
|
+
- OpenAPI schemas in YAML or JSON format
|
|
6
|
+
- JSON schemas in YAML or JSON format
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
from schema_export import export_schema, to_openapi_schema, to_json_schema, to_dict
|
|
10
|
+
|
|
11
|
+
# Export schema to file
|
|
12
|
+
export_schema(CoreConfig, "schema.yaml")
|
|
13
|
+
export_schema(CoreConfig, "schema.json", schema_type="json", format="json")
|
|
14
|
+
|
|
15
|
+
# Generate schema in memory
|
|
16
|
+
openapi_schema = to_openapi_schema(CoreConfig)
|
|
17
|
+
json_schema = to_json_schema(CoreConfig)
|
|
18
|
+
|
|
19
|
+
# Export config instance to dict
|
|
20
|
+
config_instance = CoreConfig(name="myapp", port=8000)
|
|
21
|
+
config_dict = to_dict(config_instance)
|
|
22
|
+
|
|
23
|
+
No external dependencies required for basic functionality.
|
|
24
|
+
PyYAML is optional for YAML export support.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import json
|
|
28
|
+
import textwrap
|
|
29
|
+
from collections import OrderedDict
|
|
30
|
+
from typing import Any, Dict
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
import yaml
|
|
34
|
+
|
|
35
|
+
HAS_YAML = True
|
|
36
|
+
except ImportError:
|
|
37
|
+
HAS_YAML = False
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def to_openapi_schema(config_class) -> Dict[str, Any]:
|
|
41
|
+
"""Generate OpenAPI schema for a configuration class.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
config_class: The configuration class to generate schema for
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
OpenAPI schema dictionary
|
|
48
|
+
"""
|
|
49
|
+
return _generate_openapi_schema(config_class)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def to_json_schema(config_class) -> Dict[str, Any]:
|
|
53
|
+
"""Generate JSON schema for a configuration class.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
config_class: The configuration class to generate schema for
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
JSON schema dictionary
|
|
60
|
+
"""
|
|
61
|
+
return _generate_json_schema(config_class)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def export_schema(
|
|
65
|
+
config_class, filepath: str, schema_type: str = "openapi", format: str = "yaml"
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Export configuration schema to file.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
config_class: The configuration class to export schema for
|
|
71
|
+
filepath: Path to save the schema file
|
|
72
|
+
schema_type: Type of schema to generate ('openapi' or 'json')
|
|
73
|
+
format: Output format ('yaml' or 'json')
|
|
74
|
+
|
|
75
|
+
Examples:
|
|
76
|
+
# Export OpenAPI schema as YAML (default)
|
|
77
|
+
export_schema(CoreConfig, "schema.yaml")
|
|
78
|
+
|
|
79
|
+
# Export JSON schema as YAML
|
|
80
|
+
export_schema(CoreConfig, "schema.yaml", schema_type="json")
|
|
81
|
+
|
|
82
|
+
# Export OpenAPI schema as JSON
|
|
83
|
+
export_schema(CoreConfig, "schema.json", schema_type="openapi", format="json")
|
|
84
|
+
|
|
85
|
+
# Export JSON schema as JSON
|
|
86
|
+
export_schema(CoreConfig, "schema.json", schema_type="json", format="json")
|
|
87
|
+
"""
|
|
88
|
+
# Validate inputs
|
|
89
|
+
if schema_type.lower() not in ["openapi", "json"]:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"Unsupported schema type: {schema_type}. Use 'openapi' or 'json'."
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if format.lower() not in ["yaml", "json"]:
|
|
95
|
+
raise ValueError(f"Unsupported format: {format}. Use 'yaml' or 'json'.")
|
|
96
|
+
|
|
97
|
+
# Generate the appropriate schema
|
|
98
|
+
if schema_type.lower() == "openapi":
|
|
99
|
+
base_schema = _generate_openapi_schema(config_class)
|
|
100
|
+
# Wrap in OpenAPI document structure with proper ordering
|
|
101
|
+
schema_data = OrderedDict(
|
|
102
|
+
[
|
|
103
|
+
("openapi", "3.0.0"),
|
|
104
|
+
(
|
|
105
|
+
"info",
|
|
106
|
+
OrderedDict(
|
|
107
|
+
[
|
|
108
|
+
("title", f"{config_class.__name__} Configuration Schema"),
|
|
109
|
+
("version", "1.0.0"),
|
|
110
|
+
]
|
|
111
|
+
),
|
|
112
|
+
),
|
|
113
|
+
(
|
|
114
|
+
"components",
|
|
115
|
+
OrderedDict(
|
|
116
|
+
[
|
|
117
|
+
(
|
|
118
|
+
"schemas",
|
|
119
|
+
OrderedDict([(config_class.__name__, base_schema)]),
|
|
120
|
+
)
|
|
121
|
+
]
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
]
|
|
125
|
+
)
|
|
126
|
+
else: # json schema
|
|
127
|
+
schema_data = _generate_json_schema(config_class)
|
|
128
|
+
|
|
129
|
+
# Export in the requested format
|
|
130
|
+
if format.lower() == "yaml":
|
|
131
|
+
if not HAS_YAML:
|
|
132
|
+
raise ImportError(
|
|
133
|
+
"PyYAML is required for YAML export. Install with: pip install pyyaml"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Custom YAML representer for multiline strings
|
|
137
|
+
def multiline_representer(dumper, data):
|
|
138
|
+
if "\n" in data or len(data) > 80:
|
|
139
|
+
style = "|" # use literal block
|
|
140
|
+
else:
|
|
141
|
+
style = None # normal flow
|
|
142
|
+
return dumper.represent_scalar("tag:yaml.org,2002:str", data, style=style)
|
|
143
|
+
|
|
144
|
+
# Custom YAML representer for OrderedDict to preserve order
|
|
145
|
+
def ordered_dict_representer(dumper, data):
|
|
146
|
+
return dumper.represent_dict(data.items())
|
|
147
|
+
|
|
148
|
+
yaml.add_representer(str, multiline_representer)
|
|
149
|
+
yaml.add_representer(OrderedDict, ordered_dict_representer)
|
|
150
|
+
|
|
151
|
+
with open(filepath, "w") as f:
|
|
152
|
+
yaml.dump(
|
|
153
|
+
schema_data,
|
|
154
|
+
f,
|
|
155
|
+
default_flow_style=False,
|
|
156
|
+
sort_keys=False,
|
|
157
|
+
allow_unicode=True,
|
|
158
|
+
width=120,
|
|
159
|
+
indent=2,
|
|
160
|
+
)
|
|
161
|
+
else: # json format
|
|
162
|
+
with open(filepath, "w") as f:
|
|
163
|
+
json.dump(schema_data, f, indent=2)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
# Private helper functions
|
|
167
|
+
def _generate_openapi_schema(cls) -> Dict[str, Any]:
|
|
168
|
+
"""Generate OpenAPI schema for a configuration class.
|
|
169
|
+
|
|
170
|
+
Note: Schema is intended for CLI/config file usage, so PROGRAMMATIC-only
|
|
171
|
+
fields are excluded.
|
|
172
|
+
"""
|
|
173
|
+
# Clean up class docstring for better YAML formatting
|
|
174
|
+
description = f"{cls.__name__} configuration"
|
|
175
|
+
get_description = getattr(cls, "SCHEMA_DOC", None)
|
|
176
|
+
if get_description:
|
|
177
|
+
description = get_description
|
|
178
|
+
elif cls.__doc__:
|
|
179
|
+
# Remove common indentation and clean up whitespace
|
|
180
|
+
cleaned_doc = textwrap.dedent(cls.__doc__).strip()
|
|
181
|
+
# Replace multiple spaces with single spaces but preserve line breaks
|
|
182
|
+
lines = [line.strip() for line in cleaned_doc.split("\n") if line.strip()]
|
|
183
|
+
description = "\n".join(lines)
|
|
184
|
+
|
|
185
|
+
# Create ordered schema with specific order: title, description, type, required, then properties
|
|
186
|
+
schema = OrderedDict(
|
|
187
|
+
[
|
|
188
|
+
("title", cls.__name__),
|
|
189
|
+
("description", description),
|
|
190
|
+
("type", "object"),
|
|
191
|
+
("required", []),
|
|
192
|
+
("properties", OrderedDict()),
|
|
193
|
+
]
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
for field_name, field_info in cls._fields.items():
|
|
197
|
+
if field_name.startswith("_"):
|
|
198
|
+
continue
|
|
199
|
+
|
|
200
|
+
# Skip PROGRAMMATIC-only fields - schema is for CLI/config file usage
|
|
201
|
+
if (
|
|
202
|
+
hasattr(field_info, "is_available_in_cli")
|
|
203
|
+
and not field_info.is_available_in_cli()
|
|
204
|
+
):
|
|
205
|
+
continue
|
|
206
|
+
|
|
207
|
+
field_schema = _get_field_schema(field_info)
|
|
208
|
+
schema["properties"][field_name] = field_schema
|
|
209
|
+
|
|
210
|
+
# Add to required if field is required
|
|
211
|
+
if field_info.required:
|
|
212
|
+
schema["required"].append(field_name)
|
|
213
|
+
|
|
214
|
+
return schema
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _generate_json_schema(cls) -> Dict[str, Any]:
|
|
218
|
+
"""Generate JSON schema for a configuration class."""
|
|
219
|
+
openapi_schema = _generate_openapi_schema(cls)
|
|
220
|
+
|
|
221
|
+
# Create ordered JSON schema with $schema first
|
|
222
|
+
schema = OrderedDict(
|
|
223
|
+
[
|
|
224
|
+
("$schema", "https://json-schema.org/draft/2020-12/schema"),
|
|
225
|
+
("title", openapi_schema["title"]),
|
|
226
|
+
("description", openapi_schema["description"]),
|
|
227
|
+
("type", openapi_schema["type"]),
|
|
228
|
+
("required", openapi_schema["required"]),
|
|
229
|
+
("properties", openapi_schema["properties"]),
|
|
230
|
+
]
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
return schema
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _get_field_schema(field_info) -> Dict[str, Any]:
|
|
237
|
+
"""Generate schema for a single field."""
|
|
238
|
+
field_schema = OrderedDict()
|
|
239
|
+
|
|
240
|
+
# Get description from ConfigField.help first, then CLI metadata
|
|
241
|
+
description = field_info.help or (
|
|
242
|
+
field_info.cli_meta.help if field_info.cli_meta else None
|
|
243
|
+
)
|
|
244
|
+
if description:
|
|
245
|
+
field_schema["description"] = description
|
|
246
|
+
|
|
247
|
+
# Handle field type
|
|
248
|
+
if field_info.field_type == str:
|
|
249
|
+
field_schema["type"] = "string"
|
|
250
|
+
elif field_info.field_type == int:
|
|
251
|
+
field_schema["type"] = "integer"
|
|
252
|
+
elif field_info.field_type == float:
|
|
253
|
+
field_schema["type"] = "number"
|
|
254
|
+
elif field_info.field_type == bool:
|
|
255
|
+
field_schema["type"] = "boolean"
|
|
256
|
+
elif field_info.field_type == list:
|
|
257
|
+
field_schema["type"] = "array"
|
|
258
|
+
field_schema["items"] = {"type": "string"} # Default to string items
|
|
259
|
+
elif field_info.field_type == dict:
|
|
260
|
+
field_schema["type"] = "object"
|
|
261
|
+
field_schema["additionalProperties"] = True
|
|
262
|
+
elif hasattr(field_info.field_type, "_fields"):
|
|
263
|
+
# Nested configuration object
|
|
264
|
+
field_schema = _generate_openapi_schema(field_info.field_type)
|
|
265
|
+
else:
|
|
266
|
+
# Fallback to string for unknown types
|
|
267
|
+
field_schema["type"] = "string"
|
|
268
|
+
|
|
269
|
+
# Add default value
|
|
270
|
+
if field_info.default is not None and not callable(field_info.default):
|
|
271
|
+
field_schema["default"] = field_info.default
|
|
272
|
+
|
|
273
|
+
# Handle choices from CLI metadata
|
|
274
|
+
if field_info.cli_meta and field_info.cli_meta.choices:
|
|
275
|
+
if "type" in field_schema:
|
|
276
|
+
field_schema["enum"] = field_info.cli_meta.choices
|
|
277
|
+
|
|
278
|
+
# Add examples from ConfigField
|
|
279
|
+
if field_info.example is not None:
|
|
280
|
+
field_schema["example"] = field_info.example
|
|
281
|
+
|
|
282
|
+
# Add experimental flag
|
|
283
|
+
if field_info.is_experimental:
|
|
284
|
+
field_schema["experimental"] = True
|
|
285
|
+
|
|
286
|
+
# Add Field Behavior
|
|
287
|
+
if field_info.behavior:
|
|
288
|
+
field_schema["mutation_behavior"] = field_info.behavior
|
|
289
|
+
|
|
290
|
+
if field_info.cli_meta is not None:
|
|
291
|
+
field_schema["cli_option"] = field_info.cli_meta.cli_option_str
|
|
292
|
+
|
|
293
|
+
# Handle validation from CLI metadata
|
|
294
|
+
if field_info.cli_meta and field_info.validation_fn:
|
|
295
|
+
# Add validation hints in description
|
|
296
|
+
if "description" in field_schema:
|
|
297
|
+
field_schema["description"] += " (validation applied)"
|
|
298
|
+
|
|
299
|
+
return field_schema
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Auto-generated typed classes for ConfigMeta classes.
|
|
3
|
+
|
|
4
|
+
This module provides IDE-friendly typed interfaces for all configuration classes.
|
|
5
|
+
The reason we auto-generate this file is because we want to provide a bridge between what is the ConfigMeta classes and the typed programmatic interface.
|
|
6
|
+
The CoreConfig class is setup in a way that if any additionally params are missed out from being auto-generated then it will not affect the core functionality of the programmatic API.
|
|
7
|
+
The new parameters will just not show up in IDE autocompletions.
|
|
8
|
+
It is fine if this file is not regularly updated by running the script in the .pre-commit-config.app-changes.yaml
|
|
9
|
+
but it is recommended that this file not be deleted or manually edited.
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from typing import Optional, List, Dict, Any
|
|
14
|
+
from .unified_config import CoreConfig
|
|
15
|
+
|
|
16
|
+
import sys
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
# on 3.8+ use the stdlib TypedDict;
|
|
20
|
+
# in TYPE_CHECKING blocks mypy/pyright still pick it up on older Pythons
|
|
21
|
+
if sys.version_info >= (3, 8):
|
|
22
|
+
from typing import TypedDict
|
|
23
|
+
else:
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
# for the benefit of type-checkers
|
|
26
|
+
from typing import TypedDict # noqa: F401
|
|
27
|
+
# runtime no-op TypedDict shim
|
|
28
|
+
class _TypedDictMeta(type):
|
|
29
|
+
def __new__(cls, name, bases, namespace, total=True):
|
|
30
|
+
# ignore total at runtime
|
|
31
|
+
return super().__new__(cls, name, bases, namespace)
|
|
32
|
+
|
|
33
|
+
class TypedDict(dict, metaclass=_TypedDictMeta):
|
|
34
|
+
# Runtime stand-in for typing.TypedDict on <3.8.
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ResourceConfigDict(TypedDict, total=False):
|
|
39
|
+
cpu: Optional[str]
|
|
40
|
+
memory: Optional[str]
|
|
41
|
+
gpu: Optional[str]
|
|
42
|
+
disk: Optional[str]
|
|
43
|
+
shared_memory: Optional[str]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AuthConfigDict(TypedDict, total=False):
|
|
47
|
+
type: Optional[str]
|
|
48
|
+
public: Optional[bool]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ReplicaConfigDict(TypedDict, total=False):
|
|
52
|
+
fixed: Optional[int]
|
|
53
|
+
min: Optional[int]
|
|
54
|
+
max: Optional[int]
|
|
55
|
+
scaling_policy: Optional["ScalingPolicyConfigDict"]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ScalingPolicyConfigDict(TypedDict, total=False):
|
|
59
|
+
rpm: Optional[int]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class DependencyConfigDict(TypedDict, total=False):
|
|
63
|
+
from_requirements_file: Optional[str]
|
|
64
|
+
from_pyproject_toml: Optional[str]
|
|
65
|
+
python: Optional[str]
|
|
66
|
+
pypi: Optional[dict]
|
|
67
|
+
conda: Optional[dict]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class PackageConfigDict(TypedDict, total=False):
|
|
71
|
+
src_paths: Optional[list]
|
|
72
|
+
suffixes: Optional[list]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class TypedCoreConfig:
|
|
76
|
+
"""
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
name : str, optional
|
|
80
|
+
The name of the app to deploy.
|
|
81
|
+
|
|
82
|
+
port : int, optional
|
|
83
|
+
Port where the app is hosted. When deployed this will be port on which we will deploy the app.
|
|
84
|
+
|
|
85
|
+
description : str, optional
|
|
86
|
+
The description of the app to deploy.
|
|
87
|
+
|
|
88
|
+
app_type : str, optional
|
|
89
|
+
The User defined type of app to deploy. Its only used for bookkeeping purposes.
|
|
90
|
+
|
|
91
|
+
image : str, optional
|
|
92
|
+
The Docker image to deploy with the App.
|
|
93
|
+
|
|
94
|
+
tags : list, optional
|
|
95
|
+
The tags of the app to deploy.
|
|
96
|
+
|
|
97
|
+
secrets : list, optional
|
|
98
|
+
Outerbounds integrations to attach to the app. You can use the value you set in the `@secrets` decorator in your code.
|
|
99
|
+
|
|
100
|
+
compute_pools : list, optional
|
|
101
|
+
A list of compute pools to deploy the app to.
|
|
102
|
+
|
|
103
|
+
environment : dict, optional
|
|
104
|
+
Environment variables to deploy with the App.
|
|
105
|
+
|
|
106
|
+
commands : list, optional
|
|
107
|
+
A list of commands to run the app with.
|
|
108
|
+
|
|
109
|
+
resources : ResourceConfigDict, optional
|
|
110
|
+
Resource configuration for the app.
|
|
111
|
+
- cpu (str)
|
|
112
|
+
CPU requests
|
|
113
|
+
- memory (str)
|
|
114
|
+
Memory requests
|
|
115
|
+
- gpu (str)
|
|
116
|
+
GPU requests
|
|
117
|
+
- disk (str)
|
|
118
|
+
Storage disk size.
|
|
119
|
+
- shared_memory (str)
|
|
120
|
+
Shared memory
|
|
121
|
+
|
|
122
|
+
auth : AuthConfigDict, optional
|
|
123
|
+
Auth related configurations.
|
|
124
|
+
- type (str)
|
|
125
|
+
The type of authentication to use for the app.
|
|
126
|
+
- public (bool)
|
|
127
|
+
Whether the app is public or not.
|
|
128
|
+
|
|
129
|
+
replicas : ReplicaConfigDict, optional
|
|
130
|
+
The number of replicas to deploy the app with.
|
|
131
|
+
- fixed (int)
|
|
132
|
+
The fixed number of replicas to deploy the app with. If min and max are set, this will raise an error.
|
|
133
|
+
- min (int)
|
|
134
|
+
The minimum number of replicas to deploy the app with.
|
|
135
|
+
- max (int)
|
|
136
|
+
The maximum number of replicas to deploy the app with.
|
|
137
|
+
- scaling_policy (ScalingPolicyConfigDict)
|
|
138
|
+
Scaling policy defines the the metric based on which the replicas will horizontally scale. If min and max replicas are set and are not the same, then a scaling policy will be applied. Default scaling policies can be 60 rpm (ie 1 rps).
|
|
139
|
+
- rpm (int)
|
|
140
|
+
Scale up replicas when the requests per minute crosses this threshold. If nothing is provided and the replicas.max and replicas.min is set then the default rpm would be 60.
|
|
141
|
+
|
|
142
|
+
code_package : tuple, optional
|
|
143
|
+
Pre-packaged code from package_code(). A PackagedCode namedtuple containing url and key.
|
|
144
|
+
|
|
145
|
+
force_upgrade : bool, optional
|
|
146
|
+
Force upgrade the app even if it is currently being upgraded.
|
|
147
|
+
|
|
148
|
+
persistence : str, optional
|
|
149
|
+
The persistence mode to deploy the app with.
|
|
150
|
+
[Experimental] May change in the future.
|
|
151
|
+
|
|
152
|
+
project : str, optional
|
|
153
|
+
The project name to deploy the app to.
|
|
154
|
+
[Experimental] May change in the future.
|
|
155
|
+
|
|
156
|
+
branch : str, optional
|
|
157
|
+
The branch name to deploy the app to.
|
|
158
|
+
[Experimental] May change in the future.
|
|
159
|
+
|
|
160
|
+
models : list, optional
|
|
161
|
+
[Experimental] May change in the future.
|
|
162
|
+
|
|
163
|
+
data : list, optional
|
|
164
|
+
[Experimental] May change in the future.
|
|
165
|
+
|
|
166
|
+
generate_static_url : bool, optional
|
|
167
|
+
Generate a static URL for the app based on its name.
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def __init__(
|
|
171
|
+
self,
|
|
172
|
+
name: Optional[str] = None,
|
|
173
|
+
port: Optional[int] = None,
|
|
174
|
+
description: Optional[str] = None,
|
|
175
|
+
app_type: Optional[str] = None,
|
|
176
|
+
image: Optional[str] = None,
|
|
177
|
+
tags: Optional[list] = None,
|
|
178
|
+
secrets: Optional[list] = None,
|
|
179
|
+
compute_pools: Optional[list] = None,
|
|
180
|
+
environment: Optional[dict] = None,
|
|
181
|
+
commands: Optional[list] = None,
|
|
182
|
+
resources: Optional[ResourceConfigDict] = None,
|
|
183
|
+
auth: Optional[AuthConfigDict] = None,
|
|
184
|
+
replicas: Optional[ReplicaConfigDict] = None,
|
|
185
|
+
code_package: Optional[tuple] = None,
|
|
186
|
+
force_upgrade: Optional[bool] = None,
|
|
187
|
+
persistence: Optional[str] = None,
|
|
188
|
+
project: Optional[str] = None,
|
|
189
|
+
branch: Optional[str] = None,
|
|
190
|
+
models: Optional[list] = None,
|
|
191
|
+
data: Optional[list] = None,
|
|
192
|
+
generate_static_url: Optional[bool] = None,
|
|
193
|
+
**kwargs
|
|
194
|
+
) -> None:
|
|
195
|
+
self._kwargs = {
|
|
196
|
+
"name": name,
|
|
197
|
+
"port": port,
|
|
198
|
+
"description": description,
|
|
199
|
+
"app_type": app_type,
|
|
200
|
+
"image": image,
|
|
201
|
+
"tags": tags,
|
|
202
|
+
"secrets": secrets,
|
|
203
|
+
"compute_pools": compute_pools,
|
|
204
|
+
"environment": environment,
|
|
205
|
+
"commands": commands,
|
|
206
|
+
"resources": resources,
|
|
207
|
+
"auth": auth,
|
|
208
|
+
"replicas": replicas,
|
|
209
|
+
"code_package": code_package,
|
|
210
|
+
"force_upgrade": force_upgrade,
|
|
211
|
+
"persistence": persistence,
|
|
212
|
+
"project": project,
|
|
213
|
+
"branch": branch,
|
|
214
|
+
"models": models,
|
|
215
|
+
"data": data,
|
|
216
|
+
"generate_static_url": generate_static_url,
|
|
217
|
+
}
|
|
218
|
+
# Add any additional kwargs
|
|
219
|
+
self._kwargs.update(kwargs)
|
|
220
|
+
# Remove None values
|
|
221
|
+
self._kwargs = {k: v for k, v in self._kwargs.items() if v is not None}
|
|
222
|
+
self._config_class = CoreConfig
|
|
223
|
+
self._config = self.create_config()
|
|
224
|
+
self._init()
|
|
225
|
+
|
|
226
|
+
def create_config(self) -> CoreConfig:
|
|
227
|
+
return CoreConfig.from_dict(self._kwargs)
|
|
228
|
+
|
|
229
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
230
|
+
return self._config.to_dict()
|
|
231
|
+
|
|
232
|
+
def _init(self):
|
|
233
|
+
raise NotImplementedError
|