ob-metaflow-extensions 1.1.151__py2.py3-none-any.whl → 1.6.2__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.
Files changed (92) hide show
  1. metaflow_extensions/outerbounds/__init__.py +1 -1
  2. metaflow_extensions/outerbounds/plugins/__init__.py +24 -3
  3. metaflow_extensions/outerbounds/plugins/apps/app_cli.py +0 -0
  4. metaflow_extensions/outerbounds/plugins/apps/core/__init__.py +16 -0
  5. metaflow_extensions/outerbounds/plugins/apps/core/_state_machine.py +506 -0
  6. metaflow_extensions/outerbounds/plugins/apps/core/_vendor/__init__.py +0 -0
  7. metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/__init__.py +4 -0
  8. metaflow_extensions/outerbounds/plugins/apps/core/_vendor/spinner/spinners.py +478 -0
  9. metaflow_extensions/outerbounds/plugins/apps/core/app_config.py +128 -0
  10. metaflow_extensions/outerbounds/plugins/apps/core/app_deploy_decorator.py +333 -0
  11. metaflow_extensions/outerbounds/plugins/apps/core/artifacts.py +0 -0
  12. metaflow_extensions/outerbounds/plugins/apps/core/capsule.py +1029 -0
  13. metaflow_extensions/outerbounds/plugins/apps/core/click_importer.py +24 -0
  14. metaflow_extensions/outerbounds/plugins/apps/core/code_package/__init__.py +3 -0
  15. metaflow_extensions/outerbounds/plugins/apps/core/code_package/code_packager.py +618 -0
  16. metaflow_extensions/outerbounds/plugins/apps/core/code_package/examples.py +125 -0
  17. metaflow_extensions/outerbounds/plugins/apps/core/config/__init__.py +15 -0
  18. metaflow_extensions/outerbounds/plugins/apps/core/config/cli_generator.py +165 -0
  19. metaflow_extensions/outerbounds/plugins/apps/core/config/config_utils.py +966 -0
  20. metaflow_extensions/outerbounds/plugins/apps/core/config/schema_export.py +299 -0
  21. metaflow_extensions/outerbounds/plugins/apps/core/config/typed_configs.py +233 -0
  22. metaflow_extensions/outerbounds/plugins/apps/core/config/typed_init_generator.py +537 -0
  23. metaflow_extensions/outerbounds/plugins/apps/core/config/unified_config.py +1125 -0
  24. metaflow_extensions/outerbounds/plugins/apps/core/config_schema.yaml +337 -0
  25. metaflow_extensions/outerbounds/plugins/apps/core/dependencies.py +115 -0
  26. metaflow_extensions/outerbounds/plugins/apps/core/deployer.py +1300 -0
  27. metaflow_extensions/outerbounds/plugins/apps/core/exceptions.py +341 -0
  28. metaflow_extensions/outerbounds/plugins/apps/core/experimental/__init__.py +89 -0
  29. metaflow_extensions/outerbounds/plugins/apps/core/perimeters.py +123 -0
  30. metaflow_extensions/outerbounds/plugins/apps/core/secrets.py +164 -0
  31. metaflow_extensions/outerbounds/plugins/apps/core/utils.py +233 -0
  32. metaflow_extensions/outerbounds/plugins/apps/core/validations.py +17 -0
  33. metaflow_extensions/outerbounds/plugins/aws/__init__.py +4 -0
  34. metaflow_extensions/outerbounds/plugins/aws/assume_role.py +3 -0
  35. metaflow_extensions/outerbounds/plugins/aws/assume_role_decorator.py +118 -0
  36. metaflow_extensions/outerbounds/plugins/checkpoint_datastores/coreweave.py +9 -77
  37. metaflow_extensions/outerbounds/plugins/checkpoint_datastores/external_chckpt.py +85 -0
  38. metaflow_extensions/outerbounds/plugins/checkpoint_datastores/nebius.py +7 -78
  39. metaflow_extensions/outerbounds/plugins/fast_bakery/baker.py +119 -0
  40. metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py +17 -3
  41. metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py +1 -0
  42. metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py +18 -44
  43. metaflow_extensions/outerbounds/plugins/kubernetes/pod_killer.py +374 -0
  44. metaflow_extensions/outerbounds/plugins/nim/card.py +1 -6
  45. metaflow_extensions/outerbounds/plugins/nim/{__init__.py → nim_decorator.py} +13 -49
  46. metaflow_extensions/outerbounds/plugins/nim/nim_manager.py +294 -233
  47. metaflow_extensions/outerbounds/plugins/nim/utils.py +36 -0
  48. metaflow_extensions/outerbounds/plugins/nvcf/constants.py +2 -2
  49. metaflow_extensions/outerbounds/plugins/nvct/nvct_decorator.py +32 -8
  50. metaflow_extensions/outerbounds/plugins/nvct/nvct_runner.py +1 -1
  51. metaflow_extensions/outerbounds/plugins/ollama/__init__.py +171 -16
  52. metaflow_extensions/outerbounds/plugins/ollama/constants.py +1 -0
  53. metaflow_extensions/outerbounds/plugins/ollama/exceptions.py +22 -0
  54. metaflow_extensions/outerbounds/plugins/ollama/ollama.py +1710 -114
  55. metaflow_extensions/outerbounds/plugins/ollama/status_card.py +292 -0
  56. metaflow_extensions/outerbounds/plugins/optuna/__init__.py +49 -0
  57. metaflow_extensions/outerbounds/plugins/profilers/simple_card_decorator.py +96 -0
  58. metaflow_extensions/outerbounds/plugins/s3_proxy/__init__.py +7 -0
  59. metaflow_extensions/outerbounds/plugins/s3_proxy/binary_caller.py +132 -0
  60. metaflow_extensions/outerbounds/plugins/s3_proxy/constants.py +11 -0
  61. metaflow_extensions/outerbounds/plugins/s3_proxy/exceptions.py +13 -0
  62. metaflow_extensions/outerbounds/plugins/s3_proxy/proxy_bootstrap.py +59 -0
  63. metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_api.py +93 -0
  64. metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_decorator.py +250 -0
  65. metaflow_extensions/outerbounds/plugins/s3_proxy/s3_proxy_manager.py +225 -0
  66. metaflow_extensions/outerbounds/plugins/snowflake/snowflake.py +37 -7
  67. metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py +18 -8
  68. metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py +6 -0
  69. metaflow_extensions/outerbounds/plugins/snowpark/snowpark_client.py +45 -18
  70. metaflow_extensions/outerbounds/plugins/snowpark/snowpark_decorator.py +18 -9
  71. metaflow_extensions/outerbounds/plugins/snowpark/snowpark_job.py +10 -4
  72. metaflow_extensions/outerbounds/plugins/torchtune/__init__.py +163 -0
  73. metaflow_extensions/outerbounds/plugins/vllm/__init__.py +255 -0
  74. metaflow_extensions/outerbounds/plugins/vllm/constants.py +1 -0
  75. metaflow_extensions/outerbounds/plugins/vllm/exceptions.py +1 -0
  76. metaflow_extensions/outerbounds/plugins/vllm/status_card.py +352 -0
  77. metaflow_extensions/outerbounds/plugins/vllm/vllm_manager.py +621 -0
  78. metaflow_extensions/outerbounds/remote_config.py +46 -9
  79. metaflow_extensions/outerbounds/toplevel/apps/__init__.py +9 -0
  80. metaflow_extensions/outerbounds/toplevel/apps/exceptions.py +11 -0
  81. metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py +86 -2
  82. metaflow_extensions/outerbounds/toplevel/ob_internal.py +4 -0
  83. metaflow_extensions/outerbounds/toplevel/plugins/optuna/__init__.py +1 -0
  84. metaflow_extensions/outerbounds/toplevel/plugins/torchtune/__init__.py +1 -0
  85. metaflow_extensions/outerbounds/toplevel/plugins/vllm/__init__.py +1 -0
  86. metaflow_extensions/outerbounds/toplevel/s3_proxy.py +88 -0
  87. {ob_metaflow_extensions-1.1.151.dist-info → ob_metaflow_extensions-1.6.2.dist-info}/METADATA +2 -2
  88. ob_metaflow_extensions-1.6.2.dist-info/RECORD +136 -0
  89. metaflow_extensions/outerbounds/plugins/nim/utilities.py +0 -5
  90. ob_metaflow_extensions-1.1.151.dist-info/RECORD +0 -74
  91. {ob_metaflow_extensions-1.1.151.dist-info → ob_metaflow_extensions-1.6.2.dist-info}/WHEEL +0 -0
  92. {ob_metaflow_extensions-1.1.151.dist-info → ob_metaflow_extensions-1.6.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,333 @@
1
+ from typing import List, Optional
2
+ from metaflow.exception import MetaflowException
3
+ from metaflow.decorators import StepDecorator, FlowDecorator
4
+ from metaflow import current
5
+ from metaflow.metaflow_config import KUBERNETES_CONTAINER_IMAGE
6
+ from .deployer import AppDeployer, DeployedApp, PackagedCode
7
+ from .perimeters import PerimeterExtractor
8
+ import os
9
+
10
+
11
+ class AppDeployFlowDecorator(FlowDecorator):
12
+ """
13
+ Deploy and manage Outerbounds Apps from within a Metaflow flow.
14
+
15
+ This decorator enables deploying apps during flow execution, automatically
16
+ tagging them with Metaflow metadata (flow name, run ID, step, etc.) for
17
+ easy tracking and management.
18
+
19
+ When applied to a flow, it exposes `current.apps` which provides:
20
+ - Access to the flow's code package and image
21
+ - Ability to list apps deployed in the current run
22
+ - Automatic tagging with Metaflow context
23
+
24
+ Examples
25
+ --------
26
+
27
+ ```python
28
+ from metaflow import FlowSpec, step, current, app_deploy
29
+ from metaflow.apps import AppDeployer
30
+
31
+ @app_deploy
32
+ class MyFlow(FlowSpec):
33
+
34
+ @step
35
+ def start(self):
36
+ # Deploy an app using the flow's code package
37
+ deployer = AppDeployer(
38
+ name="my-service",
39
+ port=8000,
40
+ image=current.apps.current_image,
41
+ code_package=current.apps.metaflow_code_package,
42
+ commands=["python server.py"],
43
+ )
44
+ self.app = deployer.deploy()
45
+ self.next(self.end)
46
+
47
+ @step
48
+ def end(self):
49
+ # List all apps deployed in this run
50
+ apps = current.apps.list()
51
+ print(f"Deployed {len(apps)} app(s)")
52
+ ```
53
+
54
+
55
+ MF Add To Current
56
+ -----------------
57
+ apps -> metaflow_extensions.outerbounds.plugins.apps.core.app_deploy_decorator.FlowAppManager
58
+
59
+ @@ Returns
60
+ ----------
61
+ FlowAppManager
62
+ """
63
+
64
+ name = "app_deploy"
65
+ defaults = {}
66
+
67
+ def __init__(self, attributes=None, statically_defined=False, inserted_by=None):
68
+ self._attributes_with_user_values = (
69
+ set(attributes.keys()) if attributes is not None else set()
70
+ )
71
+
72
+ super().__init__(attributes, statically_defined, inserted_by)
73
+
74
+ def flow_init(
75
+ self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
76
+ ):
77
+
78
+ from metaflow import decorators
79
+
80
+ decorators._attach_decorators(flow, ["app_deploy_internal"])
81
+ decorators._process_late_attached_decorator(
82
+ ["app_deploy_internal"],
83
+ flow,
84
+ graph,
85
+ environment,
86
+ flow_datastore,
87
+ logger,
88
+ )
89
+
90
+
91
+ class AppDeployInternalDecorator(StepDecorator):
92
+
93
+ name = "app_deploy_internal"
94
+ defaults = {}
95
+
96
+ packaged_code = None
97
+
98
+ package_url = None
99
+ package_sha = None
100
+
101
+ MAX_ENTROPY = 6
102
+ MAX_NAME_LENGTH = 150
103
+
104
+ def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
105
+ self.logger = logger
106
+ self.environment = environment
107
+ self.step = step
108
+ self.flow_datastore = flow_datastore
109
+
110
+ def _resolve_package_url_and_sha(self):
111
+ return os.environ.get("METAFLOW_CODE_URL", self.package_url), os.environ.get(
112
+ "METAFLOW_CODE_SHA", self.package_sha
113
+ )
114
+
115
+ def _extract_project_info(self):
116
+ project = current.get("project_name")
117
+ branch = current.get("branch_name")
118
+ is_production = current.get("is_production")
119
+ return project, branch, is_production
120
+
121
+ def task_pre_step(
122
+ self,
123
+ step_name,
124
+ task_datastore,
125
+ metadata,
126
+ run_id,
127
+ task_id,
128
+ flow,
129
+ graph,
130
+ retry_count,
131
+ max_user_code_retries,
132
+ ubf_context,
133
+ inputs,
134
+ ):
135
+ perimeter, api_server = PerimeterExtractor.during_programmatic_access()
136
+ package_url, package_sha = self._resolve_package_url_and_sha()
137
+ if package_url is None or package_sha is None:
138
+ # TODO: Think through if we need this abstraction
139
+ raise MetaflowException(
140
+ "METAFLOW_CODE_URL or METAFLOW_CODE_SHA is not set. "
141
+ "Please set METAFLOW_CODE_URL and METAFLOW_CODE_SHA in your environment."
142
+ )
143
+ self.packaged_code = PackagedCode(package_url, package_sha)
144
+ image = os.environ.get("FASTBAKERY_IMAGE", None)
145
+
146
+ project, branch, is_production = self._extract_project_info()
147
+
148
+ project_info = {}
149
+ if project is not None:
150
+ project_info["metaflow/project"] = project
151
+ project_info["metaflow/branch"] = branch
152
+ project_info["metaflow/is_production"] = is_production
153
+
154
+ default_tags = {
155
+ "metaflow/flow_name": flow.name,
156
+ "metaflow/step_name": step_name,
157
+ "metaflow/run_id": run_id,
158
+ "metaflow/task_id": task_id,
159
+ "metaflow/retry_count": retry_count,
160
+ "metaflow/pathspec": current.pathspec,
161
+ **project_info,
162
+ }
163
+
164
+ # Set state on AppDeployer using the new API
165
+ AppDeployer._set_state("perimeter", perimeter)
166
+ AppDeployer._set_state("api_url", api_server)
167
+ AppDeployer._set_state(
168
+ "default_tags", [{k: str(v)} for k, v in default_tags.items()]
169
+ )
170
+
171
+ current._update_env(
172
+ {
173
+ "apps": FlowAppManager(
174
+ flow.name,
175
+ run_id,
176
+ self.packaged_code,
177
+ image,
178
+ )
179
+ }
180
+ )
181
+
182
+ def task_post_step(
183
+ self, step_name, flow, graph, retry_count, max_user_code_retries
184
+ ):
185
+ pass
186
+
187
+ def runtime_init(self, flow, graph, package, run_id):
188
+ # Set some more internal state.
189
+ self.flow = flow
190
+ self.graph = graph
191
+ self.package = package
192
+ self.run_id = run_id
193
+
194
+ def runtime_task_created(
195
+ self, task_datastore, task_id, split_index, input_paths, is_cloned, ubf_context
196
+ ):
197
+ # To execute the Kubernetes job, the job container needs to have
198
+ # access to the code package. We store the package in the datastore
199
+ # which the pod is able to download as part of it's entrypoint.
200
+ if not is_cloned:
201
+ self._save_package_once(self.flow_datastore, self.package)
202
+
203
+ @classmethod
204
+ def _save_package_once(cls, flow_datastore, package):
205
+ if cls.packaged_code is None:
206
+ cls.package_url, cls.package_sha = flow_datastore.save_data(
207
+ [package.blob], len_hint=1
208
+ )[0]
209
+ cls.packaged_code = PackagedCode(cls.package_url, cls.package_sha)
210
+ os.environ["METAFLOW_CODE_URL"] = cls.package_url
211
+ os.environ["METAFLOW_CODE_SHA"] = cls.package_sha
212
+
213
+
214
+ class FlowAppManager:
215
+ """
216
+ Manager for apps deployed within a Metaflow flow execution.
217
+
218
+ Accessible via `current.apps` when using the `@app_deploy` decorator.
219
+ Provides access to the flow's code package, container image, and
220
+ methods to list apps deployed in the current run.
221
+
222
+ Attributes
223
+ ----------
224
+ metaflow_code_package : PackagedCode
225
+ The code package for the current flow, ready to use with AppDeployer.
226
+ current_image : str
227
+ The container image used by the current task (from fast_bakery or similar).
228
+ default_image : str
229
+ The default Kubernetes container image from Metaflow config.
230
+
231
+ Examples
232
+ --------
233
+
234
+ ```python
235
+ # python myflow.py --environment=fast-bakery run --with kubernetes
236
+ from metaflow.apps import AppDeployer
237
+
238
+ @pypi(packages={"flask": ">=2.0", "requests": ">=2.28"})
239
+ @step
240
+ def deploy_step(self):
241
+ image = current.apps.current_image
242
+ if image is None:
243
+ image = current.apps.default_image
244
+ # Use the flow's code package directly
245
+ deployer = AppDeployer(
246
+ name="my-app",
247
+ port=8000,
248
+ image=image,
249
+ code_package=current.apps.metaflow_code_package,
250
+ commands=["python app.py"],
251
+ )
252
+ deployed = deployer.deploy()
253
+
254
+ # List apps from this run
255
+ apps = current.apps.list()
256
+ ```
257
+ """
258
+
259
+ def __init__(
260
+ self,
261
+ flow_name: str,
262
+ run_id: str,
263
+ package: PackagedCode,
264
+ image: Optional[str] = None,
265
+ ) -> None:
266
+ self._package = package
267
+ self._image = image
268
+ self._runid = run_id
269
+ self._flowname = flow_name
270
+
271
+ @property
272
+ def metaflow_code_package(self) -> PackagedCode:
273
+ """
274
+ The flow's code package for use with AppDeployer.
275
+
276
+ Returns
277
+ -------
278
+ PackagedCode
279
+ A namedtuple with `url` and `key` fields pointing to the
280
+ packaged metaflow's code package stored in the datastore.
281
+ """
282
+ return self._package
283
+
284
+ @property
285
+ def current_image(self) -> str:
286
+ """
287
+ The container image for the current task.
288
+
289
+ Returns
290
+ -------
291
+ str
292
+ Image URI from fast bakery image or None if not set.
293
+ """
294
+ return self._image
295
+
296
+ @property
297
+ def default_image(self) -> str:
298
+ """
299
+ The default Kubernetes container image from Metaflow config.
300
+
301
+ Returns
302
+ -------
303
+ str
304
+ The KUBERNETES_CONTAINER_IMAGE from Metaflow configuration.
305
+ """
306
+ return KUBERNETES_CONTAINER_IMAGE
307
+
308
+ def list(self) -> List["DeployedApp"]:
309
+ """
310
+ List apps deployed in the current Metaflow run.
311
+
312
+ Returns apps tagged with this flow's name and run ID.
313
+
314
+ Returns
315
+ -------
316
+ List[DeployedApp]
317
+ Apps deployed during this flow execution.
318
+
319
+ Examples
320
+ --------
321
+
322
+ ```python
323
+ apps = current.apps.list()
324
+ for app in apps:
325
+ print(f"{app.name}: {app.public_url}")
326
+ ```
327
+ """
328
+ return AppDeployer.list_deployments(
329
+ tags=[
330
+ {"metaflow/run_id": self._runid},
331
+ {"metaflow/flow_name": self._flowname},
332
+ ]
333
+ )