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.

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