ob-metaflow-extensions 1.2.2rc0__py2.py3-none-any.whl → 1.2.4__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/plugins/apps/app_deploy_decorator.py +41 -7
- metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py +4 -0
- metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +16 -1
- metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +1 -1
- metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +14 -3
- metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +194 -17
- {ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/METADATA +2 -2
- {ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/RECORD +10 -10
- {ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/WHEEL +0 -0
- {ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/top_level.txt +0 -0
|
@@ -26,6 +26,9 @@ class AppDeployDecorator(StepDecorator):
|
|
|
26
26
|
package_url = None
|
|
27
27
|
package_sha = None
|
|
28
28
|
|
|
29
|
+
MAX_ENTROPY = 6
|
|
30
|
+
MAX_NAME_LENGTH = 15 - MAX_ENTROPY - 1 # -1 for the hyphen
|
|
31
|
+
|
|
29
32
|
def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
|
|
30
33
|
self.logger = logger
|
|
31
34
|
self.environment = environment
|
|
@@ -37,6 +40,23 @@ class AppDeployDecorator(StepDecorator):
|
|
|
37
40
|
"METAFLOW_CODE_SHA", self.package_sha
|
|
38
41
|
)
|
|
39
42
|
|
|
43
|
+
def _extract_project_info(self):
|
|
44
|
+
project = current.get("project_name")
|
|
45
|
+
branch = current.get("branch_name")
|
|
46
|
+
is_production = current.get("is_production")
|
|
47
|
+
return project, branch, is_production
|
|
48
|
+
|
|
49
|
+
def _resolve_default_image(self, flow):
|
|
50
|
+
# TODO : Resolve the default image over here.
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
def _resolve_default_name_prefix(self, flow, step_name):
|
|
54
|
+
# TODO: Only tweek MAX_NAME_LENGTH as backend support allows longer names.
|
|
55
|
+
base_prefix = (flow.name + "-" + step_name).lower()
|
|
56
|
+
if len(base_prefix) > self.MAX_NAME_LENGTH:
|
|
57
|
+
base_prefix = "mf-app"
|
|
58
|
+
return base_prefix
|
|
59
|
+
|
|
40
60
|
def task_pre_step(
|
|
41
61
|
self,
|
|
42
62
|
step_name,
|
|
@@ -58,22 +78,36 @@ class AppDeployDecorator(StepDecorator):
|
|
|
58
78
|
"METAFLOW_CODE_URL or METAFLOW_CODE_SHA is not set. "
|
|
59
79
|
"Please set METAFLOW_CODE_URL and METAFLOW_CODE_SHA in your environment."
|
|
60
80
|
)
|
|
61
|
-
default_name = "-".join(current.pathspec.split("/")).lower()
|
|
62
81
|
image = os.environ.get("FASTBAKERY_IMAGE", None)
|
|
63
82
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
# TODO [Apps] - This is temporary. Backend will support longer names in the future.
|
|
84
|
+
default_name = self._resolve_default_name_prefix(flow, step_name)
|
|
85
|
+
project, branch, is_production = self._extract_project_info()
|
|
86
|
+
project_info = {}
|
|
87
|
+
if project is not None:
|
|
88
|
+
project_info["metaflow/project"] = project
|
|
89
|
+
project_info["metaflow/branch"] = branch
|
|
90
|
+
project_info["metaflow/is_production"] = is_production
|
|
91
|
+
|
|
92
|
+
default_tags = {
|
|
93
|
+
"metaflow/flow_name": flow.name,
|
|
94
|
+
"metaflow/step_name": step_name,
|
|
95
|
+
"metaflow/run_id": run_id,
|
|
96
|
+
"metaflow/task_id": task_id,
|
|
97
|
+
"metaflow/retry_count": retry_count,
|
|
98
|
+
"metaflow/pathspec": current.pathspec,
|
|
99
|
+
**project_info,
|
|
100
|
+
}
|
|
69
101
|
|
|
70
102
|
AppDeployer._set_state(
|
|
71
103
|
perimeter,
|
|
72
104
|
api_server,
|
|
73
105
|
code_package_url=package_url,
|
|
74
106
|
code_package_key=package_sha,
|
|
75
|
-
|
|
107
|
+
name_prefix=default_name,
|
|
76
108
|
image=image,
|
|
109
|
+
max_entropy=self.MAX_ENTROPY,
|
|
110
|
+
default_tags=[{k: str(v)} for k, v in default_tags.items()],
|
|
77
111
|
)
|
|
78
112
|
current._update_env(
|
|
79
113
|
{
|
|
@@ -189,6 +189,10 @@ class CurrentWorkerInfo(TypedDict):
|
|
|
189
189
|
crashlooping: int
|
|
190
190
|
|
|
191
191
|
|
|
192
|
+
class LogLine(TypedDict):
|
|
193
|
+
message: str
|
|
194
|
+
|
|
195
|
+
|
|
192
196
|
class DEPLOYMENT_READY_CONDITIONS:
|
|
193
197
|
"""
|
|
194
198
|
Deployment ready conditions define what is considered a successful completion of the current deployment instance.
|
|
@@ -18,6 +18,7 @@ from ._state_machine import (
|
|
|
18
18
|
WorkerStatus,
|
|
19
19
|
CapsuleStatus,
|
|
20
20
|
DEPLOYMENT_READY_CONDITIONS,
|
|
21
|
+
LogLine,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
|
|
@@ -508,7 +509,7 @@ class CapsuleApi:
|
|
|
508
509
|
|
|
509
510
|
def logs(
|
|
510
511
|
self, capsule_id: str, worker_id: str, previous: bool = False
|
|
511
|
-
) -> List[
|
|
512
|
+
) -> List[LogLine]:
|
|
512
513
|
_url = os.path.join(self._base_url, capsule_id, "workers", worker_id, "logs")
|
|
513
514
|
options = None
|
|
514
515
|
if previous:
|
|
@@ -530,6 +531,20 @@ class CapsuleApi:
|
|
|
530
531
|
message="Capsule JSON decode failed",
|
|
531
532
|
)
|
|
532
533
|
|
|
534
|
+
def patch(self, capsule_id: str, patch_input: dict):
|
|
535
|
+
capsule_response = self.get(capsule_id)
|
|
536
|
+
if "spec" not in capsule_response or len(capsule_response.get("spec", {})) == 0:
|
|
537
|
+
raise CapsuleApiException(
|
|
538
|
+
self._base_url,
|
|
539
|
+
"patch",
|
|
540
|
+
403,
|
|
541
|
+
"Capsule response of incorrect format",
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
spec = capsule_response.get("spec")
|
|
545
|
+
spec.update(patch_input)
|
|
546
|
+
return self.create(spec)
|
|
547
|
+
|
|
533
548
|
|
|
534
549
|
def list_and_filter_capsules(
|
|
535
550
|
capsule_api: CapsuleApi, project, branch, name, tags, auth_type, capsule_id
|
|
@@ -527,6 +527,10 @@ class PackageConfig(metaclass=ConfigMeta):
|
|
|
527
527
|
)
|
|
528
528
|
|
|
529
529
|
|
|
530
|
+
def everything_is_string(*args):
|
|
531
|
+
return all(isinstance(arg, str) for arg in args)
|
|
532
|
+
|
|
533
|
+
|
|
530
534
|
class BasicAppValidations:
|
|
531
535
|
@staticmethod
|
|
532
536
|
def name(name):
|
|
@@ -534,7 +538,7 @@ class BasicAppValidations:
|
|
|
534
538
|
return True
|
|
535
539
|
regex = r"^[a-z0-9-]+$" # Only allow lowercase letters, numbers, and hyphens
|
|
536
540
|
validator = BasicValidations(CoreConfig, "name")
|
|
537
|
-
return validator.length_validation(
|
|
541
|
+
return validator.length_validation(15, name) and validator.regex_validation(
|
|
538
542
|
regex, name
|
|
539
543
|
)
|
|
540
544
|
|
|
@@ -548,12 +552,19 @@ class BasicAppValidations:
|
|
|
548
552
|
def tags(tags):
|
|
549
553
|
if tags is None:
|
|
550
554
|
return True
|
|
551
|
-
if not all(
|
|
555
|
+
if not all(
|
|
556
|
+
isinstance(tag, dict)
|
|
557
|
+
and len(tag) == 1
|
|
558
|
+
and all(
|
|
559
|
+
[everything_is_string(*tag.keys()), everything_is_string(*tag.values())]
|
|
560
|
+
)
|
|
561
|
+
for tag in tags
|
|
562
|
+
):
|
|
552
563
|
raise ConfigValidationFailedException(
|
|
553
564
|
field_name="tags",
|
|
554
565
|
field_info=CoreConfig._get_field(CoreConfig, "tags"), # type: ignore
|
|
555
566
|
current_value=tags,
|
|
556
|
-
message="Tags must be a list of dictionaries with one key. Currently they are set to %s "
|
|
567
|
+
message="Tags must be a list of dictionaries with one key and the value must be a string. Currently they are set to %s "
|
|
557
568
|
% (str(tags)),
|
|
558
569
|
)
|
|
559
570
|
return True
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
from .config import TypedCoreConfig
|
|
2
|
-
|
|
3
|
-
from .
|
|
1
|
+
from .config import TypedCoreConfig, TypedDict
|
|
2
|
+
from .perimeters import PerimeterExtractor
|
|
3
|
+
from .capsule import CapsuleApi
|
|
4
|
+
import json
|
|
5
|
+
from ._state_machine import DEPLOYMENT_READY_CONDITIONS, LogLine
|
|
4
6
|
from .app_config import AppConfig, AppConfigError
|
|
5
7
|
from .capsule import CapsuleDeployer, list_and_filter_capsules
|
|
6
8
|
from functools import partial
|
|
7
9
|
import sys
|
|
8
|
-
|
|
10
|
+
import uuid
|
|
11
|
+
from typing import Type, Dict, List
|
|
12
|
+
from datetime import datetime
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
class AppDeployer(TypedCoreConfig):
|
|
@@ -17,8 +21,18 @@ class AppDeployer(TypedCoreConfig):
|
|
|
17
21
|
|
|
18
22
|
_state = {}
|
|
19
23
|
|
|
24
|
+
__state_items = [
|
|
25
|
+
"perimeter",
|
|
26
|
+
"api_url",
|
|
27
|
+
"code_package_url",
|
|
28
|
+
"code_package_key",
|
|
29
|
+
"image",
|
|
30
|
+
"project",
|
|
31
|
+
"branch",
|
|
32
|
+
]
|
|
33
|
+
|
|
20
34
|
@property
|
|
21
|
-
def
|
|
35
|
+
def _deploy_config(self) -> AppConfig:
|
|
22
36
|
if not hasattr(self, "_app_config"):
|
|
23
37
|
self._app_config = AppConfig(self._config)
|
|
24
38
|
return self._app_config
|
|
@@ -31,15 +45,27 @@ class AppDeployer(TypedCoreConfig):
|
|
|
31
45
|
api_url: str,
|
|
32
46
|
code_package_url: str = None,
|
|
33
47
|
code_package_key: str = None,
|
|
34
|
-
|
|
48
|
+
name_prefix: str = None,
|
|
35
49
|
image: str = None,
|
|
50
|
+
max_entropy: int = 4,
|
|
51
|
+
default_tags: List[Dict[str, str]] = None,
|
|
52
|
+
project: str = None,
|
|
53
|
+
branch: str = None,
|
|
36
54
|
):
|
|
37
55
|
cls._state["perimeter"] = perimeter
|
|
38
56
|
cls._state["api_url"] = api_url
|
|
39
57
|
cls._state["code_package_url"] = code_package_url
|
|
40
58
|
cls._state["code_package_key"] = code_package_key
|
|
41
|
-
cls._state["
|
|
59
|
+
cls._state["name_prefix"] = name_prefix
|
|
42
60
|
cls._state["image"] = image
|
|
61
|
+
cls._state["max_entropy"] = max_entropy
|
|
62
|
+
cls._state["default_tags"] = default_tags
|
|
63
|
+
cls._state["project"] = project
|
|
64
|
+
cls._state["branch"] = branch
|
|
65
|
+
|
|
66
|
+
assert (
|
|
67
|
+
max_entropy > 0
|
|
68
|
+
), "max_entropy must be greater than 0. Since AppDeployer's deploy fn can be called many time inside a step itself."
|
|
43
69
|
|
|
44
70
|
def deploy(
|
|
45
71
|
self,
|
|
@@ -50,20 +76,29 @@ class AppDeployer(TypedCoreConfig):
|
|
|
50
76
|
status_file=None,
|
|
51
77
|
no_loader=False,
|
|
52
78
|
**kwargs,
|
|
53
|
-
):
|
|
79
|
+
) -> "DeployedApp":
|
|
80
|
+
|
|
54
81
|
# Name setting from top level if none is set in the code
|
|
55
|
-
if self.
|
|
56
|
-
|
|
82
|
+
if self._deploy_config._core_config.name is None:
|
|
83
|
+
name = self._state[
|
|
84
|
+
"name_prefix"
|
|
85
|
+
] # for now the name-prefix cannot be very large.
|
|
86
|
+
entropy = uuid.uuid4().hex[: self._state["max_entropy"]]
|
|
87
|
+
self._deploy_config._core_config.name = f"{name}-{entropy}"
|
|
57
88
|
|
|
58
|
-
self.
|
|
89
|
+
if len(self._state["default_tags"]) > 0:
|
|
90
|
+
self._deploy_config._core_config.tags = (
|
|
91
|
+
self._deploy_config._core_config.tags or []
|
|
92
|
+
) + self._state["default_tags"]
|
|
59
93
|
|
|
94
|
+
self._deploy_config.commit()
|
|
60
95
|
# Set any state that might have been passed down from the top level
|
|
61
|
-
for k
|
|
62
|
-
if self.
|
|
63
|
-
self.
|
|
96
|
+
for k in self.__state_items:
|
|
97
|
+
if self._deploy_config.get_state(k) is None:
|
|
98
|
+
self._deploy_config.set_state(k, self._state[k])
|
|
64
99
|
|
|
65
100
|
capsule = CapsuleDeployer(
|
|
66
|
-
self.
|
|
101
|
+
self._deploy_config,
|
|
67
102
|
self._state["api_url"],
|
|
68
103
|
create_timeout=max_wait_time,
|
|
69
104
|
debug_dir=None,
|
|
@@ -82,7 +117,7 @@ class AppDeployer(TypedCoreConfig):
|
|
|
82
117
|
None,
|
|
83
118
|
)
|
|
84
119
|
|
|
85
|
-
force_upgrade = self.
|
|
120
|
+
force_upgrade = self._deploy_config.get_state("force_upgrade", False)
|
|
86
121
|
|
|
87
122
|
if len(currently_present_capsules) > 0:
|
|
88
123
|
# Only update the capsule if there is no upgrade in progress
|
|
@@ -112,7 +147,149 @@ class AppDeployer(TypedCoreConfig):
|
|
|
112
147
|
|
|
113
148
|
capsule.create()
|
|
114
149
|
final_status = capsule.wait_for_terminal_state()
|
|
115
|
-
return
|
|
150
|
+
return DeployedApp(
|
|
151
|
+
final_status["id"],
|
|
152
|
+
final_status["auth_type"],
|
|
153
|
+
final_status["public_url"],
|
|
154
|
+
final_status["available_replicas"],
|
|
155
|
+
final_status["name"],
|
|
156
|
+
final_status["deployed_version"],
|
|
157
|
+
final_status["deployed_at"],
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class DeployedApp:
|
|
162
|
+
def __init__(
|
|
163
|
+
self,
|
|
164
|
+
_id: str,
|
|
165
|
+
capsule_type: str,
|
|
166
|
+
public_url: str,
|
|
167
|
+
available_replicas: int,
|
|
168
|
+
name: str,
|
|
169
|
+
deployed_version: str,
|
|
170
|
+
deployed_at: str,
|
|
171
|
+
):
|
|
172
|
+
self._id = _id
|
|
173
|
+
self._capsule_type = capsule_type
|
|
174
|
+
self._public_url = public_url
|
|
175
|
+
self._available_replicas = available_replicas
|
|
176
|
+
self._name = name
|
|
177
|
+
self._deployed_version = deployed_version
|
|
178
|
+
self._deployed_at = deployed_at
|
|
179
|
+
|
|
180
|
+
def _get_capsule_api(self) -> CapsuleApi:
|
|
181
|
+
perimeter, api_server = PerimeterExtractor.during_metaflow_execution()
|
|
182
|
+
return CapsuleApi(api_server, perimeter)
|
|
183
|
+
|
|
184
|
+
def logs(self, previous=False) -> Dict[str, List[LogLine]]:
|
|
185
|
+
"""
|
|
186
|
+
Returns a dictionary of worker_id to logs.
|
|
187
|
+
If `previous` is True, it will return the logs from the previous execution of the workers. Useful when debugging a crashlooping worker.
|
|
188
|
+
"""
|
|
189
|
+
capsule_api = self._get_capsule_api()
|
|
190
|
+
# extract workers from capsule
|
|
191
|
+
workers = capsule_api.get_workers(self._id)
|
|
192
|
+
# get logs from workers
|
|
193
|
+
logs = {
|
|
194
|
+
# worker_id: logs
|
|
195
|
+
}
|
|
196
|
+
for worker in workers:
|
|
197
|
+
# TODO: Handle exceptions better over here.
|
|
198
|
+
logs[worker["workerId"]] = capsule_api.logs(
|
|
199
|
+
self._id, worker["workerId"], previous=previous
|
|
200
|
+
)
|
|
201
|
+
return logs
|
|
202
|
+
|
|
203
|
+
def info(self) -> dict:
|
|
204
|
+
"""
|
|
205
|
+
Returns a dictionary representing the deployed app.
|
|
206
|
+
"""
|
|
207
|
+
capsule_api = self._get_capsule_api()
|
|
208
|
+
capsule = capsule_api.get(self._id)
|
|
209
|
+
return capsule
|
|
210
|
+
|
|
211
|
+
def scale_to_zero(self):
|
|
212
|
+
"""
|
|
213
|
+
Scales the DeployedApp to 0 replicas.
|
|
214
|
+
"""
|
|
215
|
+
capsule_api = self._get_capsule_api()
|
|
216
|
+
return capsule_api.patch(
|
|
217
|
+
self._id,
|
|
218
|
+
{
|
|
219
|
+
"autoscalingConfig": {
|
|
220
|
+
"minReplicas": 0,
|
|
221
|
+
"maxReplicas": 0,
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def delete(self):
|
|
227
|
+
"""
|
|
228
|
+
Deletes the DeployedApp.
|
|
229
|
+
"""
|
|
230
|
+
capsule_api = self._get_capsule_api()
|
|
231
|
+
return capsule_api.delete(self._id)
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def id(self) -> str:
|
|
235
|
+
return self._id
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def auth_style(self) -> str:
|
|
239
|
+
# TODO : Fix naming here.
|
|
240
|
+
return self._capsule_type
|
|
241
|
+
|
|
242
|
+
@property
|
|
243
|
+
def public_url(self) -> str:
|
|
244
|
+
return self._public_url
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def available_replicas(self) -> int:
|
|
248
|
+
return self._available_replicas
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def name(self) -> str:
|
|
252
|
+
return self._name
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def deployed_version(self) -> str:
|
|
256
|
+
return self._deployed_version
|
|
257
|
+
|
|
258
|
+
def to_dict(self) -> dict:
|
|
259
|
+
return {
|
|
260
|
+
"id": self._id,
|
|
261
|
+
"auth_style": self.auth_style, # TODO : Fix naming here.
|
|
262
|
+
"public_url": self._public_url,
|
|
263
|
+
"available_replicas": self._available_replicas,
|
|
264
|
+
"name": self._name,
|
|
265
|
+
"deployed_version": self._deployed_version,
|
|
266
|
+
"deployed_at": self._deployed_at,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
@classmethod
|
|
270
|
+
def from_dict(cls, data: dict):
|
|
271
|
+
return cls(
|
|
272
|
+
_id=data["id"],
|
|
273
|
+
capsule_type=data["capsule_type"],
|
|
274
|
+
public_url=data["public_url"],
|
|
275
|
+
available_replicas=data["available_replicas"],
|
|
276
|
+
name=data["name"],
|
|
277
|
+
deployed_version=data["deployed_version"],
|
|
278
|
+
deployed_at=data["deployed_at"],
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
@property
|
|
282
|
+
def deployed_at(self) -> datetime:
|
|
283
|
+
return datetime.fromisoformat(self._deployed_at)
|
|
284
|
+
|
|
285
|
+
def __repr__(self) -> str:
|
|
286
|
+
return (
|
|
287
|
+
f"DeployedApp(id='{self._id}', "
|
|
288
|
+
f"name='{self._name}', "
|
|
289
|
+
f"public_url='{self._public_url}', "
|
|
290
|
+
f"available_replicas={self._available_replicas}, "
|
|
291
|
+
f"deployed_version='{self._deployed_version}')"
|
|
292
|
+
)
|
|
116
293
|
|
|
117
294
|
|
|
118
295
|
class apps:
|
{ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/METADATA
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ob-metaflow-extensions
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Outerbounds Platform Extensions for Metaflow
|
|
5
5
|
Author: Outerbounds, Inc.
|
|
6
6
|
License: Commercial
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: boto3
|
|
9
9
|
Requires-Dist: kubernetes
|
|
10
|
-
Requires-Dist: ob-metaflow (==2.16.
|
|
10
|
+
Requires-Dist: ob-metaflow (==2.16.1.1)
|
|
11
11
|
|
|
12
12
|
# Outerbounds platform package
|
|
13
13
|
|
|
@@ -6,21 +6,21 @@ metaflow_extensions/outerbounds/plugins/auth_server.py,sha256=_Q9_2EL0Xy77bCRphk
|
|
|
6
6
|
metaflow_extensions/outerbounds/plugins/perimeters.py,sha256=QXh3SFP7GQbS-RAIxUOPbhPzQ7KDFVxZkTdKqFKgXjI,2697
|
|
7
7
|
metaflow_extensions/outerbounds/plugins/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
metaflow_extensions/outerbounds/plugins/apps/app_cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
metaflow_extensions/outerbounds/plugins/apps/app_deploy_decorator.py,sha256=
|
|
9
|
+
metaflow_extensions/outerbounds/plugins/apps/app_deploy_decorator.py,sha256=WWFvyl0EDUbp_UwmWjXBqlLfPEZ-lq98NJ5F5skBDKU,4901
|
|
10
10
|
metaflow_extensions/outerbounds/plugins/apps/app_utils.py,sha256=sw9whU17lAzlD2K2kEDNjlk1Ib-2xE2UNhJkmzD8Qv8,8543
|
|
11
11
|
metaflow_extensions/outerbounds/plugins/apps/consts.py,sha256=iHsyqbUg9k-rgswCs1Jxf5QZIxR1V-peCDRjgr9kdBM,177
|
|
12
12
|
metaflow_extensions/outerbounds/plugins/apps/deploy_decorator.py,sha256=VkmiMdNYHhNdt-Qm9AVv7aE2LWFsIFEc16YcOYjwF6Q,8568
|
|
13
13
|
metaflow_extensions/outerbounds/plugins/apps/supervisord_utils.py,sha256=GQoN2gyPClcpR9cLldJmbCfqXnoAHxp8xUnY7vzaYtY,9026
|
|
14
14
|
metaflow_extensions/outerbounds/plugins/apps/core/__init__.py,sha256=c6uCgKlgEkTmM9BVdAO-m3vZvUpK2KW_AZZ2236now4,237
|
|
15
|
-
metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py,sha256=
|
|
15
|
+
metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py,sha256=8z4MnPeat3Vm8ekLIMJj8vVsvUAQ__i8daf-9UItUIQ,19926
|
|
16
16
|
metaflow_extensions/outerbounds/plugins/apps/core/app_cli.py,sha256=9YyvOQzPNlpxA2K9AZ4jYpfDWpLSp66u_NotGGE5DHg,42155
|
|
17
17
|
metaflow_extensions/outerbounds/plugins/apps/core/app_config.py,sha256=PHt-HdNfTHIuhY-eB5vkRMp1RKQNWJ4DKdgZWyYgUuc,4167
|
|
18
18
|
metaflow_extensions/outerbounds/plugins/apps/core/artifacts.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
|
-
metaflow_extensions/outerbounds/plugins/apps/core/capsule.py,sha256=
|
|
19
|
+
metaflow_extensions/outerbounds/plugins/apps/core/capsule.py,sha256=9_LrpZcDg3w0FZvs9h_6Mmiy5YTYLCLnEu8wnNau24E,34445
|
|
20
20
|
metaflow_extensions/outerbounds/plugins/apps/core/click_importer.py,sha256=kgoPQmK_-8PSSTc3QMSaynCLQ5VWTkKFOC69FPURyXA,998
|
|
21
21
|
metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml,sha256=iTThO2vNQrFWe9nYfjiOcMf6FOQ6vU_1ZhXhUAr0L24,8142
|
|
22
22
|
metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py,sha256=HDPj7rDARcsKeex5GwH0IP8rOXMH6YdOufgXDknP1S8,4006
|
|
23
|
-
metaflow_extensions/outerbounds/plugins/apps/core/deployer.py,sha256=
|
|
23
|
+
metaflow_extensions/outerbounds/plugins/apps/core/deployer.py,sha256=VkYe8mK_VOr-bAiR2RohhKeLf8Z3gHZw7RoRBSCu2FA,9765
|
|
24
24
|
metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py,sha256=jeFGAUnFQkBFiOMp_Ls7Ofb80Qogh509suam5sMucYU,3030
|
|
25
25
|
metaflow_extensions/outerbounds/plugins/apps/core/secrets.py,sha256=aWzcAayQEJghQgFP_qp9w6jyvan_hoL4_ceqZ0ZjLd4,6126
|
|
26
26
|
metaflow_extensions/outerbounds/plugins/apps/core/utils.py,sha256=RLO6p25Fzq4olLFtQmfSl9LT0NPDfUosxPrsjO9sczo,7897
|
|
@@ -31,13 +31,13 @@ metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/spinners.py,sh
|
|
|
31
31
|
metaflow_extensions/outerbounds/plugins/apps/core/code_package/__init__.py,sha256=8McF7pgx8ghvjRnazp2Qktlxi9yYwNiwESSQrk-2oW8,68
|
|
32
32
|
metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py,sha256=wrGKpsg9pBU2rvhIveJ3kzc5ODUTtzciybcGHyi7pR8,22815
|
|
33
33
|
metaflow_extensions/outerbounds/plugins/apps/core/code_package/examples.py,sha256=aF8qKIJxCVv_ugcShQjqUsXKKKMsm1oMkQIl8w3QKuw,4016
|
|
34
|
-
metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py,sha256=
|
|
34
|
+
metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py,sha256=ZgC9U4NFu7TNngUuUMzt69PmjMENXb6eUK2HCSroIDo,393
|
|
35
35
|
metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py,sha256=0R0-wy7RxAMR9doVRvuluRYxAYgyjZXlTIkOeYGyz7M,5350
|
|
36
36
|
metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py,sha256=bozzUR8rbfOnb5M532RZxB5QNvVgEC1gnVjfCvQ82Yk,34053
|
|
37
37
|
metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py,sha256=tigPtb0we-urwbmctG1GbaQ9NKRKZn4KBbJKmaEntCg,9501
|
|
38
38
|
metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py,sha256=bAC2lV1xWtcw0r2LPlqDrggeXPLOyrtZha2KDpm_Vx0,4454
|
|
39
39
|
metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py,sha256=KiJ1eiwtBR5eWdBzWqvO6KlqJ2qzjJvl3w4c1uJ3g0Y,13419
|
|
40
|
-
metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py,sha256=
|
|
40
|
+
metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py,sha256=f_Qxy-pJoyGq_tUYr_gHmS7INEivLqv4QbOJljIwECA,35837
|
|
41
41
|
metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py,sha256=rd4qGTkHndKYfJmoAKZWiY0KK4j5BK6RBrtle-it1Mg,2746
|
|
42
42
|
metaflow_extensions/outerbounds/plugins/aws/__init__.py,sha256=VBGdjNKeFLXGZuqh4jVk8cFtO1AWof73a6k_cnbAOYA,145
|
|
43
43
|
metaflow_extensions/outerbounds/plugins/aws/assume_role.py,sha256=mBewNlnSYsR2rFXFkX-DUH6ku01h2yOcMcLHoCL7eyI,161
|
|
@@ -115,7 +115,7 @@ metaflow_extensions/outerbounds/toplevel/plugins/ollama/__init__.py,sha256=GRSz2
|
|
|
115
115
|
metaflow_extensions/outerbounds/toplevel/plugins/snowflake/__init__.py,sha256=LptpH-ziXHrednMYUjIaosS1SXD3sOtF_9_eRqd8SJw,50
|
|
116
116
|
metaflow_extensions/outerbounds/toplevel/plugins/torchtune/__init__.py,sha256=uTVkdSk3xZ7hEKYfdlyVteWj5KeDwaM1hU9WT-_YKfI,50
|
|
117
117
|
metaflow_extensions/outerbounds/toplevel/plugins/vllm/__init__.py,sha256=ekcgD3KVydf-a0xMI60P4uy6ePkSEoFHiGnDq1JM940,45
|
|
118
|
-
ob_metaflow_extensions-1.2.
|
|
119
|
-
ob_metaflow_extensions-1.2.
|
|
120
|
-
ob_metaflow_extensions-1.2.
|
|
121
|
-
ob_metaflow_extensions-1.2.
|
|
118
|
+
ob_metaflow_extensions-1.2.4.dist-info/METADATA,sha256=zLo5imOFamNDf-Dd5Uql7yobbwMilB9p5AWXNfrYpUQ,518
|
|
119
|
+
ob_metaflow_extensions-1.2.4.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
|
120
|
+
ob_metaflow_extensions-1.2.4.dist-info/top_level.txt,sha256=NwG0ukwjygtanDETyp_BUdtYtqIA_lOjzFFh1TsnxvI,20
|
|
121
|
+
ob_metaflow_extensions-1.2.4.dist-info/RECORD,,
|
|
File without changes
|
{ob_metaflow_extensions-1.2.2rc0.dist-info → ob_metaflow_extensions-1.2.4.dist-info}/top_level.txt
RENAMED
|
File without changes
|