ob-metaflow 2.15.13.1__py2.py3-none-any.whl → 2.19.7.1rc0__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.
- metaflow/__init__.py +10 -3
- metaflow/_vendor/imghdr/__init__.py +186 -0
- metaflow/_vendor/yaml/__init__.py +427 -0
- metaflow/_vendor/yaml/composer.py +139 -0
- metaflow/_vendor/yaml/constructor.py +748 -0
- metaflow/_vendor/yaml/cyaml.py +101 -0
- metaflow/_vendor/yaml/dumper.py +62 -0
- metaflow/_vendor/yaml/emitter.py +1137 -0
- metaflow/_vendor/yaml/error.py +75 -0
- metaflow/_vendor/yaml/events.py +86 -0
- metaflow/_vendor/yaml/loader.py +63 -0
- metaflow/_vendor/yaml/nodes.py +49 -0
- metaflow/_vendor/yaml/parser.py +589 -0
- metaflow/_vendor/yaml/reader.py +185 -0
- metaflow/_vendor/yaml/representer.py +389 -0
- metaflow/_vendor/yaml/resolver.py +227 -0
- metaflow/_vendor/yaml/scanner.py +1435 -0
- metaflow/_vendor/yaml/serializer.py +111 -0
- metaflow/_vendor/yaml/tokens.py +104 -0
- metaflow/cards.py +4 -0
- metaflow/cli.py +125 -21
- metaflow/cli_components/init_cmd.py +1 -0
- metaflow/cli_components/run_cmds.py +204 -40
- metaflow/cli_components/step_cmd.py +160 -4
- metaflow/client/__init__.py +1 -0
- metaflow/client/core.py +198 -130
- metaflow/client/filecache.py +59 -32
- metaflow/cmd/code/__init__.py +2 -1
- metaflow/cmd/develop/stub_generator.py +49 -18
- metaflow/cmd/develop/stubs.py +9 -27
- metaflow/cmd/make_wrapper.py +30 -0
- metaflow/datastore/__init__.py +1 -0
- metaflow/datastore/content_addressed_store.py +40 -9
- metaflow/datastore/datastore_set.py +10 -1
- metaflow/datastore/flow_datastore.py +124 -4
- metaflow/datastore/spin_datastore.py +91 -0
- metaflow/datastore/task_datastore.py +92 -6
- metaflow/debug.py +5 -0
- metaflow/decorators.py +331 -82
- metaflow/extension_support/__init__.py +414 -356
- metaflow/extension_support/_empty_file.py +2 -2
- metaflow/flowspec.py +322 -82
- metaflow/graph.py +178 -15
- metaflow/includefile.py +25 -3
- metaflow/lint.py +94 -3
- metaflow/meta_files.py +13 -0
- metaflow/metadata_provider/metadata.py +13 -2
- metaflow/metaflow_config.py +66 -4
- metaflow/metaflow_environment.py +91 -25
- metaflow/metaflow_profile.py +18 -0
- metaflow/metaflow_version.py +16 -1
- metaflow/package/__init__.py +673 -0
- metaflow/packaging_sys/__init__.py +880 -0
- metaflow/packaging_sys/backend.py +128 -0
- metaflow/packaging_sys/distribution_support.py +153 -0
- metaflow/packaging_sys/tar_backend.py +99 -0
- metaflow/packaging_sys/utils.py +54 -0
- metaflow/packaging_sys/v1.py +527 -0
- metaflow/parameters.py +6 -2
- metaflow/plugins/__init__.py +6 -0
- metaflow/plugins/airflow/airflow.py +11 -1
- metaflow/plugins/airflow/airflow_cli.py +16 -5
- metaflow/plugins/argo/argo_client.py +42 -20
- metaflow/plugins/argo/argo_events.py +6 -6
- metaflow/plugins/argo/argo_workflows.py +1023 -344
- metaflow/plugins/argo/argo_workflows_cli.py +396 -94
- metaflow/plugins/argo/argo_workflows_decorator.py +9 -0
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +75 -49
- metaflow/plugins/argo/capture_error.py +5 -2
- metaflow/plugins/argo/conditional_input_paths.py +35 -0
- metaflow/plugins/argo/exit_hooks.py +209 -0
- metaflow/plugins/argo/param_val.py +19 -0
- metaflow/plugins/aws/aws_client.py +6 -0
- metaflow/plugins/aws/aws_utils.py +33 -1
- metaflow/plugins/aws/batch/batch.py +72 -5
- metaflow/plugins/aws/batch/batch_cli.py +24 -3
- metaflow/plugins/aws/batch/batch_decorator.py +57 -6
- metaflow/plugins/aws/step_functions/step_functions.py +28 -3
- metaflow/plugins/aws/step_functions/step_functions_cli.py +49 -4
- metaflow/plugins/aws/step_functions/step_functions_deployer.py +3 -0
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +30 -0
- metaflow/plugins/cards/card_cli.py +20 -1
- metaflow/plugins/cards/card_creator.py +24 -1
- metaflow/plugins/cards/card_datastore.py +21 -49
- metaflow/plugins/cards/card_decorator.py +58 -6
- metaflow/plugins/cards/card_modules/basic.py +38 -9
- metaflow/plugins/cards/card_modules/bundle.css +1 -1
- metaflow/plugins/cards/card_modules/chevron/renderer.py +1 -1
- metaflow/plugins/cards/card_modules/components.py +592 -3
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +34 -5
- metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
- metaflow/plugins/cards/card_modules/main.css +1 -0
- metaflow/plugins/cards/card_modules/main.js +56 -41
- metaflow/plugins/cards/card_modules/test_cards.py +22 -6
- metaflow/plugins/cards/component_serializer.py +1 -8
- metaflow/plugins/cards/metadata.py +22 -0
- metaflow/plugins/catch_decorator.py +9 -0
- metaflow/plugins/datastores/local_storage.py +12 -6
- metaflow/plugins/datastores/spin_storage.py +12 -0
- metaflow/plugins/datatools/s3/s3.py +49 -17
- metaflow/plugins/datatools/s3/s3op.py +113 -66
- metaflow/plugins/env_escape/client_modules.py +102 -72
- metaflow/plugins/events_decorator.py +127 -121
- metaflow/plugins/exit_hook/__init__.py +0 -0
- metaflow/plugins/exit_hook/exit_hook_decorator.py +46 -0
- metaflow/plugins/exit_hook/exit_hook_script.py +52 -0
- metaflow/plugins/kubernetes/kubernetes.py +12 -1
- metaflow/plugins/kubernetes/kubernetes_cli.py +11 -0
- metaflow/plugins/kubernetes/kubernetes_decorator.py +25 -6
- metaflow/plugins/kubernetes/kubernetes_job.py +12 -4
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +31 -30
- metaflow/plugins/metadata_providers/local.py +76 -82
- metaflow/plugins/metadata_providers/service.py +13 -9
- metaflow/plugins/metadata_providers/spin.py +16 -0
- metaflow/plugins/package_cli.py +36 -24
- metaflow/plugins/parallel_decorator.py +11 -2
- metaflow/plugins/parsers.py +16 -0
- metaflow/plugins/pypi/bootstrap.py +7 -1
- metaflow/plugins/pypi/conda_decorator.py +41 -82
- metaflow/plugins/pypi/conda_environment.py +14 -6
- metaflow/plugins/pypi/micromamba.py +9 -1
- metaflow/plugins/pypi/pip.py +41 -5
- metaflow/plugins/pypi/pypi_decorator.py +4 -4
- metaflow/plugins/pypi/utils.py +22 -0
- metaflow/plugins/secrets/__init__.py +3 -0
- metaflow/plugins/secrets/secrets_decorator.py +14 -178
- metaflow/plugins/secrets/secrets_func.py +49 -0
- metaflow/plugins/secrets/secrets_spec.py +101 -0
- metaflow/plugins/secrets/utils.py +74 -0
- metaflow/plugins/test_unbounded_foreach_decorator.py +2 -2
- metaflow/plugins/timeout_decorator.py +0 -1
- metaflow/plugins/uv/bootstrap.py +29 -1
- metaflow/plugins/uv/uv_environment.py +5 -3
- metaflow/pylint_wrapper.py +5 -1
- metaflow/runner/click_api.py +79 -26
- metaflow/runner/deployer.py +208 -6
- metaflow/runner/deployer_impl.py +32 -12
- metaflow/runner/metaflow_runner.py +266 -33
- metaflow/runner/subprocess_manager.py +21 -1
- metaflow/runner/utils.py +27 -16
- metaflow/runtime.py +660 -66
- metaflow/task.py +255 -26
- metaflow/user_configs/config_options.py +33 -21
- metaflow/user_configs/config_parameters.py +220 -58
- metaflow/user_decorators/__init__.py +0 -0
- metaflow/user_decorators/common.py +144 -0
- metaflow/user_decorators/mutable_flow.py +512 -0
- metaflow/user_decorators/mutable_step.py +424 -0
- metaflow/user_decorators/user_flow_decorator.py +264 -0
- metaflow/user_decorators/user_step_decorator.py +749 -0
- metaflow/util.py +197 -7
- metaflow/vendor.py +23 -7
- metaflow/version.py +1 -1
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Makefile +13 -2
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Tiltfile +107 -7
- {ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/pick_services.sh +1 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/METADATA +2 -3
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/RECORD +162 -121
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/WHEEL +1 -1
- metaflow/_vendor/v3_5/__init__.py +0 -1
- metaflow/_vendor/v3_5/importlib_metadata/__init__.py +0 -644
- metaflow/_vendor/v3_5/importlib_metadata/_compat.py +0 -152
- metaflow/_vendor/v3_5/zipp.py +0 -329
- metaflow/info_file.py +0 -25
- metaflow/package.py +0 -203
- metaflow/user_configs/config_decorators.py +0 -568
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/entry_points.txt +0 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/licenses/LICENSE +0 -0
- {ob_metaflow-2.15.13.1.dist-info → ob_metaflow-2.19.7.1rc0.dist-info}/top_level.txt +0 -0
metaflow/util.py
CHANGED
|
@@ -4,12 +4,13 @@ import sys
|
|
|
4
4
|
import tempfile
|
|
5
5
|
import zlib
|
|
6
6
|
import base64
|
|
7
|
+
import re
|
|
8
|
+
|
|
7
9
|
from functools import wraps
|
|
8
10
|
from io import BytesIO
|
|
9
11
|
from itertools import takewhile
|
|
10
|
-
import
|
|
12
|
+
from typing import Dict, Any, Tuple, Optional, List, Generator
|
|
11
13
|
|
|
12
|
-
from metaflow.exception import MetaflowUnknownUser, MetaflowInternalError
|
|
13
14
|
|
|
14
15
|
try:
|
|
15
16
|
# python2
|
|
@@ -162,6 +163,8 @@ def get_username():
|
|
|
162
163
|
|
|
163
164
|
|
|
164
165
|
def resolve_identity_as_tuple():
|
|
166
|
+
from metaflow.exception import MetaflowUnknownUser
|
|
167
|
+
|
|
165
168
|
prod_token = os.environ.get("METAFLOW_PRODUCTION_TOKEN")
|
|
166
169
|
if prod_token:
|
|
167
170
|
return "production", prod_token
|
|
@@ -177,6 +180,119 @@ def resolve_identity():
|
|
|
177
180
|
return "%s:%s" % (identity_type, identity_value)
|
|
178
181
|
|
|
179
182
|
|
|
183
|
+
def parse_spin_pathspec(pathspec: str, flow_name: str) -> Tuple:
|
|
184
|
+
"""
|
|
185
|
+
Parse various pathspec formats for the spin command.
|
|
186
|
+
|
|
187
|
+
Parameters
|
|
188
|
+
----------
|
|
189
|
+
pathspec : str
|
|
190
|
+
The pathspec string in one of the following formats:
|
|
191
|
+
- step_name (e.g., 'start')
|
|
192
|
+
- run_id/step_name (e.g., '221165/start')
|
|
193
|
+
- run_id/step_name/task_id (e.g., '221165/start/1350987')
|
|
194
|
+
- flow_name/run_id/step_name (e.g., 'ScalableFlow/221165/start')
|
|
195
|
+
- flow_name/run_id/step_name/task_id (e.g., 'ScalableFlow/221165/start/1350987')
|
|
196
|
+
flow_name : str
|
|
197
|
+
The name of the current flow.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
Tuple
|
|
202
|
+
A tuple of (step_name, full_pathspec_or_none)
|
|
203
|
+
|
|
204
|
+
Raises
|
|
205
|
+
------
|
|
206
|
+
CommandException
|
|
207
|
+
If the pathspec format is invalid or flow name doesn't match.
|
|
208
|
+
"""
|
|
209
|
+
from .exception import CommandException
|
|
210
|
+
|
|
211
|
+
parts = pathspec.split("/")
|
|
212
|
+
|
|
213
|
+
if len(parts) == 1:
|
|
214
|
+
# Just step name: 'start'
|
|
215
|
+
step_name = parts[0]
|
|
216
|
+
parsed_pathspec = None
|
|
217
|
+
elif len(parts) == 2:
|
|
218
|
+
# run_id/step_name: '221165/start'
|
|
219
|
+
run_id, step_name = parts
|
|
220
|
+
parsed_pathspec = f"{flow_name}/{run_id}/{step_name}"
|
|
221
|
+
elif len(parts) == 3:
|
|
222
|
+
# Could be run_id/step_name/task_id or flow_name/run_id/step_name
|
|
223
|
+
if parts[0] == flow_name:
|
|
224
|
+
# flow_name/run_id/step_name
|
|
225
|
+
_, run_id, step_name = parts
|
|
226
|
+
parsed_pathspec = f"{flow_name}/{run_id}/{step_name}"
|
|
227
|
+
else:
|
|
228
|
+
# run_id/step_name/task_id
|
|
229
|
+
run_id, step_name, task_id = parts
|
|
230
|
+
parsed_pathspec = f"{flow_name}/{run_id}/{step_name}/{task_id}"
|
|
231
|
+
elif len(parts) == 4:
|
|
232
|
+
# flow_name/run_id/step_name/task_id
|
|
233
|
+
parsed_flow_name, run_id, step_name, task_id = parts
|
|
234
|
+
if parsed_flow_name != flow_name:
|
|
235
|
+
raise CommandException(
|
|
236
|
+
f"Flow name '{parsed_flow_name}' in pathspec does not match current flow '{flow_name}'."
|
|
237
|
+
)
|
|
238
|
+
parsed_pathspec = pathspec
|
|
239
|
+
else:
|
|
240
|
+
raise CommandException(
|
|
241
|
+
f"Invalid pathspec format: '{pathspec}'. \n"
|
|
242
|
+
"Expected formats:\n"
|
|
243
|
+
" - step_name (e.g., 'start')\n"
|
|
244
|
+
" - run_id/step_name (e.g., '221165/start')\n"
|
|
245
|
+
" - run_id/step_name/task_id (e.g., '221165/start/1350987')\n"
|
|
246
|
+
" - flow_name/run_id/step_name (e.g., 'ScalableFlow/221165/start')\n"
|
|
247
|
+
" - flow_name/run_id/step_name/task_id (e.g., 'ScalableFlow/221165/start/1350987')"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
return step_name, parsed_pathspec
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def get_latest_task_pathspec(
|
|
254
|
+
flow_name: str, step_name: str, run_id: str = None
|
|
255
|
+
) -> "metaflow.Task":
|
|
256
|
+
"""
|
|
257
|
+
Returns a task pathspec from the latest run (or specified run) of the flow for the queried step.
|
|
258
|
+
If the queried step has several tasks, the task pathspec of the first task is returned.
|
|
259
|
+
|
|
260
|
+
Parameters
|
|
261
|
+
----------
|
|
262
|
+
flow_name : str
|
|
263
|
+
The name of the flow.
|
|
264
|
+
step_name : str
|
|
265
|
+
The name of the step.
|
|
266
|
+
run_id : str, optional
|
|
267
|
+
The run ID to use. If None, uses the latest run.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
Task
|
|
272
|
+
A Metaflow Task instance containing the latest task for the queried step.
|
|
273
|
+
|
|
274
|
+
Raises
|
|
275
|
+
------
|
|
276
|
+
MetaflowNotFound
|
|
277
|
+
If no task or run is found for the queried step.
|
|
278
|
+
"""
|
|
279
|
+
from metaflow import Flow, Step
|
|
280
|
+
from metaflow.exception import MetaflowNotFound
|
|
281
|
+
|
|
282
|
+
if not run_id:
|
|
283
|
+
flow = Flow(flow_name)
|
|
284
|
+
run = flow.latest_run
|
|
285
|
+
if run is None:
|
|
286
|
+
raise MetaflowNotFound(f"No run found for flow {flow_name}")
|
|
287
|
+
run_id = run.id
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
task = Step(f"{flow_name}/{run_id}/{step_name}").task
|
|
291
|
+
return task
|
|
292
|
+
except:
|
|
293
|
+
raise MetaflowNotFound(f"No task found for step {step_name} in run {run_id}")
|
|
294
|
+
|
|
295
|
+
|
|
180
296
|
def get_latest_run_id(echo, flow_name):
|
|
181
297
|
from metaflow.plugins.datastores.local_storage import LocalStorage
|
|
182
298
|
|
|
@@ -236,6 +352,8 @@ def get_object_package_version(obj):
|
|
|
236
352
|
|
|
237
353
|
|
|
238
354
|
def compress_list(lst, separator=",", rangedelim=":", zlibmarker="!", zlibmin=500):
|
|
355
|
+
from metaflow.exception import MetaflowInternalError
|
|
356
|
+
|
|
239
357
|
bad_items = [x for x in lst if separator in x or rangedelim in x or zlibmarker in x]
|
|
240
358
|
if bad_items:
|
|
241
359
|
raise MetaflowInternalError(
|
|
@@ -418,7 +536,7 @@ def to_pascalcase(obj):
|
|
|
418
536
|
if isinstance(obj, dict):
|
|
419
537
|
res = obj.__class__()
|
|
420
538
|
for k in obj:
|
|
421
|
-
res[re.sub("([a-zA-Z])", lambda x: x.groups()[0].upper(), k, 1)] = (
|
|
539
|
+
res[re.sub("([a-zA-Z])", lambda x: x.groups()[0].upper(), k, count=1)] = (
|
|
422
540
|
to_pascalcase(obj[k])
|
|
423
541
|
)
|
|
424
542
|
elif isinstance(obj, (list, set, tuple)):
|
|
@@ -467,7 +585,79 @@ def to_pod(value):
|
|
|
467
585
|
return str(value)
|
|
468
586
|
|
|
469
587
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
588
|
+
from metaflow._vendor.packaging.version import parse as version_parse
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
def read_artifacts_module(file_path: str) -> Dict[str, Any]:
|
|
592
|
+
"""
|
|
593
|
+
Read a Python module from the given file path and return its ARTIFACTS variable.
|
|
594
|
+
|
|
595
|
+
Parameters
|
|
596
|
+
----------
|
|
597
|
+
file_path : str
|
|
598
|
+
The path to the Python file containing the ARTIFACTS variable.
|
|
599
|
+
|
|
600
|
+
Returns
|
|
601
|
+
-------
|
|
602
|
+
Dict[str, Any]
|
|
603
|
+
A dictionary containing the ARTIFACTS variable from the module.
|
|
604
|
+
|
|
605
|
+
Raises
|
|
606
|
+
-------
|
|
607
|
+
MetaflowInternalError
|
|
608
|
+
If the file cannot be read or does not contain the ARTIFACTS variable.
|
|
609
|
+
"""
|
|
610
|
+
import importlib.util
|
|
611
|
+
import os
|
|
612
|
+
|
|
613
|
+
try:
|
|
614
|
+
module_name = os.path.splitext(os.path.basename(file_path))[0]
|
|
615
|
+
spec = importlib.util.spec_from_file_location(module_name, file_path)
|
|
616
|
+
module = importlib.util.module_from_spec(spec)
|
|
617
|
+
spec.loader.exec_module(module)
|
|
618
|
+
variables = vars(module)
|
|
619
|
+
if "ARTIFACTS" not in variables:
|
|
620
|
+
raise MetaflowInternalError(
|
|
621
|
+
f"Module {file_path} does not contain ARTIFACTS variable"
|
|
622
|
+
)
|
|
623
|
+
return variables.get("ARTIFACTS")
|
|
624
|
+
except Exception as e:
|
|
625
|
+
raise MetaflowInternalError(f"Error reading file {file_path}") from e
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
# this is os.walk(follow_symlinks=True) with cycle detection
|
|
629
|
+
def walk_without_cycles(
|
|
630
|
+
top_root: str,
|
|
631
|
+
exclude_dirs: Optional[List[str]] = None,
|
|
632
|
+
) -> Generator[Tuple[str, List[str], List[str]], None, None]:
|
|
633
|
+
seen = set()
|
|
634
|
+
|
|
635
|
+
default_skip_dirs = ["__pycache__"]
|
|
636
|
+
|
|
637
|
+
def _recurse(root, skip_dirs):
|
|
638
|
+
for parent, dirs, files in os.walk(root):
|
|
639
|
+
dirs[:] = [d for d in dirs if d not in skip_dirs]
|
|
640
|
+
for d in dirs:
|
|
641
|
+
path = os.path.join(parent, d)
|
|
642
|
+
if os.path.islink(path):
|
|
643
|
+
# Breaking loops: never follow the same symlink twice
|
|
644
|
+
#
|
|
645
|
+
# NOTE: this also means that links to sibling links are
|
|
646
|
+
# not followed. In this case:
|
|
647
|
+
#
|
|
648
|
+
# x -> y
|
|
649
|
+
# y -> oo
|
|
650
|
+
# oo/real_file
|
|
651
|
+
#
|
|
652
|
+
# real_file is only included twice, not three times
|
|
653
|
+
reallink = os.path.realpath(path)
|
|
654
|
+
if reallink not in seen:
|
|
655
|
+
seen.add(reallink)
|
|
656
|
+
for x in _recurse(path, default_skip_dirs):
|
|
657
|
+
yield x
|
|
658
|
+
yield parent, dirs, files
|
|
659
|
+
|
|
660
|
+
skip_dirs = set(default_skip_dirs + (exclude_dirs or []))
|
|
661
|
+
for x in _recurse(top_root, skip_dirs):
|
|
662
|
+
skip_dirs = default_skip_dirs
|
|
663
|
+
yield x
|
metaflow/vendor.py
CHANGED
|
@@ -11,7 +11,6 @@ WHITELIST = {
|
|
|
11
11
|
"README.txt",
|
|
12
12
|
"__init__.py",
|
|
13
13
|
"vendor_any.txt",
|
|
14
|
-
"vendor_v3_5.txt",
|
|
15
14
|
"vendor_v3_6.txt",
|
|
16
15
|
"vendor_v3_7.txt",
|
|
17
16
|
"pip.LICENSE",
|
|
@@ -64,14 +63,29 @@ def find_vendored_libs(vendor_dir, whitelist, whitelist_dirs):
|
|
|
64
63
|
return vendored_libs, paths
|
|
65
64
|
|
|
66
65
|
|
|
67
|
-
def fetch_licenses(*
|
|
68
|
-
for
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
def fetch_licenses(*info_dirs, vendor_dir):
|
|
67
|
+
for dist_info in info_dirs:
|
|
68
|
+
metadata_file = dist_info / "METADATA"
|
|
69
|
+
if not metadata_file.exists():
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
project_name = None
|
|
73
|
+
for line in metadata_file.read_text("utf-8").splitlines():
|
|
74
|
+
if line.startswith("Name: "):
|
|
75
|
+
project_name = line.split("Name: ", 1)[1].strip()
|
|
76
|
+
break
|
|
77
|
+
if not project_name:
|
|
73
78
|
continue
|
|
74
79
|
|
|
80
|
+
for item in dist_info.iterdir():
|
|
81
|
+
if item.is_file() and re.search(r"(LICENSE|COPYING)", item.name, re.I):
|
|
82
|
+
shutil.copy(item, vendor_dir / f"{project_name}.LICENSE")
|
|
83
|
+
elif item.is_dir() and item.name.lower() == "licenses":
|
|
84
|
+
for license_file in item.iterdir():
|
|
85
|
+
if license_file.is_file():
|
|
86
|
+
dest_name = f"{project_name}.{license_file.name}"
|
|
87
|
+
shutil.copy(license_file, vendor_dir / dest_name)
|
|
88
|
+
|
|
75
89
|
|
|
76
90
|
def vendor(vendor_dir):
|
|
77
91
|
# remove everything
|
|
@@ -109,6 +123,8 @@ def vendor(vendor_dir):
|
|
|
109
123
|
"-r",
|
|
110
124
|
"_vendor/vendor_%s.txt" % subdir,
|
|
111
125
|
"--no-compile",
|
|
126
|
+
"--no-binary",
|
|
127
|
+
":all:",
|
|
112
128
|
]
|
|
113
129
|
)
|
|
114
130
|
|
metaflow/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
metaflow_version = "2.
|
|
1
|
+
metaflow_version = "2.19.7.1rc0"
|
{ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Makefile
RENAMED
|
@@ -31,6 +31,7 @@ MAKE_CMD := $(MAKE) -f "$(MKFILE_PATH)"
|
|
|
31
31
|
MINIKUBE_CPUS ?= 4
|
|
32
32
|
MINIKUBE_MEMORY ?= 6144
|
|
33
33
|
MINIKUBE_DISK_SIZE ?= 20g
|
|
34
|
+
WAIT_TIMEOUT ?= 300
|
|
34
35
|
|
|
35
36
|
ifeq ($(shell uname), Darwin)
|
|
36
37
|
minikube_os = darwin
|
|
@@ -257,10 +258,11 @@ shell: setup-tilt
|
|
|
257
258
|
echo "🔎 Using $$user_shell for interactive session."; \
|
|
258
259
|
echo "🐍 If you installed Metaflow in a virtual environment, activate it now."; \
|
|
259
260
|
if [ -f "$(DEVTOOLS_DIR)/aws_config" ]; then \
|
|
260
|
-
env
|
|
261
|
+
env -u AWS_PROFILE \
|
|
262
|
+
-u AWS_SHARED_CREDENTIALS_FILE \
|
|
263
|
+
METAFLOW_HOME="$(DEVTOOLS_DIR)" \
|
|
261
264
|
METAFLOW_PROFILE=local \
|
|
262
265
|
AWS_CONFIG_FILE="$(DEVTOOLS_DIR)/aws_config" \
|
|
263
|
-
AWS_SHARED_CREDENTIALS_FILE= \
|
|
264
266
|
"$$user_shell" -i; \
|
|
265
267
|
else \
|
|
266
268
|
env METAFLOW_HOME="$(DEVTOOLS_DIR)" \
|
|
@@ -268,6 +270,15 @@ shell: setup-tilt
|
|
|
268
270
|
"$$user_shell" -i; \
|
|
269
271
|
fi'
|
|
270
272
|
|
|
273
|
+
wait-until-ready:
|
|
274
|
+
@echo "Waiting for infrastructure to be ready. Timing out in $(WAIT_TIMEOUT) seconds..."
|
|
275
|
+
@timeout $(WAIT_TIMEOUT) bash -c 'while [ ! -f $(DEVTOOLS_DIR)/start.sh ]; do sleep 10; done; echo "Infra is Ready"' || (echo "Waiting for infra timed out"&&exit 1)
|
|
276
|
+
# buffer to get the tilt api running
|
|
277
|
+
@timeout 120 bash -c 'while ! $(TILT) get session; do sleep 3;done'
|
|
278
|
+
@echo "Waiting for services to be ready. Timing out in $(WAIT_TIMEOUT) seconds..."
|
|
279
|
+
# Need to wait for Tiltfile first, as other resources return 404 otherwise
|
|
280
|
+
@$(TILT) wait --for=condition=Ready "uiresource/(Tiltfile)" --timeout=$(WAIT_TIMEOUT)s
|
|
281
|
+
@$(TILT) wait --for=condition=Ready uiresource/generate-configs --timeout=$(WAIT_TIMEOUT)s
|
|
271
282
|
|
|
272
283
|
# @echo '$(MAKE_CMD) create-dev-shell' >> $(DEVTOOLS_DIR)/start.sh
|
|
273
284
|
# @echo 'rm -f /tmp/metaflow-devshell-*' >> $(DEVTOOLS_DIR)/start.sh
|
{ob_metaflow-2.15.13.1.data → ob_metaflow-2.19.7.1rc0.data}/data/share/metaflow/devtools/Tiltfile
RENAMED
|
@@ -14,6 +14,17 @@
|
|
|
14
14
|
version_settings(constraint='>=0.22.2')
|
|
15
15
|
allow_k8s_contexts('minikube')
|
|
16
16
|
|
|
17
|
+
# Version configuration for components
|
|
18
|
+
JOBSET_VERSION = os.getenv("JOBSET_VERSION", "v0.8.2")
|
|
19
|
+
|
|
20
|
+
# Argo Workflows versions
|
|
21
|
+
ARGO_WORKFLOWS_HELM_CHART_VERSION = os.getenv("ARGO_WORKFLOWS_HELM_CHART_VERSION", "0.45.2") # Helm chart version
|
|
22
|
+
ARGO_WORKFLOWS_IMAGE_TAG = os.getenv("ARGO_WORKFLOWS_IMAGE_TAG", "v3.6.0") # Argo Workflows application version
|
|
23
|
+
|
|
24
|
+
# Argo Events versions
|
|
25
|
+
ARGO_EVENTS_HELM_CHART_VERSION = os.getenv("ARGO_EVENTS_HELM_CHART_VERSION", "2.4.8") # Helm chart version
|
|
26
|
+
ARGO_EVENTS_IMAGE_TAG = os.getenv("ARGO_EVENTS_IMAGE_TAG", "v1.9.2") # Argo Events application version
|
|
27
|
+
|
|
17
28
|
components = {
|
|
18
29
|
"metadata-service": ["postgresql"],
|
|
19
30
|
"ui": ["postgresql", "minio"],
|
|
@@ -21,9 +32,10 @@ components = {
|
|
|
21
32
|
"postgresql": [],
|
|
22
33
|
"argo-workflows": [],
|
|
23
34
|
"argo-events": ["argo-workflows"],
|
|
35
|
+
"jobset": [],
|
|
24
36
|
}
|
|
25
37
|
|
|
26
|
-
services_env = os.getenv("SERVICES", "").strip().lower()
|
|
38
|
+
services_env = os.getenv("SERVICES", "all").strip().lower()
|
|
27
39
|
|
|
28
40
|
if services_env:
|
|
29
41
|
if services_env == "all":
|
|
@@ -172,6 +184,7 @@ if "postgresql" in enabled_components:
|
|
|
172
184
|
'auth.username=metaflow',
|
|
173
185
|
'auth.password=metaflow123',
|
|
174
186
|
'auth.database=metaflow',
|
|
187
|
+
'image.repository=bitnamilegacy/postgresql',
|
|
175
188
|
'primary.persistence.enabled=false',
|
|
176
189
|
'primary.resources.requests.memory=128Mi',
|
|
177
190
|
'primary.resources.requests.cpu=50m',
|
|
@@ -205,6 +218,7 @@ if "postgresql" in enabled_components:
|
|
|
205
218
|
if "argo-workflows" in enabled_components:
|
|
206
219
|
helm_remote(
|
|
207
220
|
'argo-workflows',
|
|
221
|
+
version=ARGO_WORKFLOWS_HELM_CHART_VERSION,
|
|
208
222
|
repo_name='argo',
|
|
209
223
|
repo_url='https://argoproj.github.io/argo-helm',
|
|
210
224
|
set=[
|
|
@@ -220,10 +234,25 @@ if "argo-workflows" in enabled_components:
|
|
|
220
234
|
'controller.resources.requests.memory=128Mi',
|
|
221
235
|
'controller.resources.requests.cpu=50m',
|
|
222
236
|
'controller.resources.limits.memory=256Mi',
|
|
223
|
-
'controller.resources.limits.cpu=100m'
|
|
237
|
+
'controller.resources.limits.cpu=100m',
|
|
238
|
+
# Image version overrides
|
|
239
|
+
'images.tag=%s' % ARGO_WORKFLOWS_IMAGE_TAG,
|
|
224
240
|
]
|
|
225
241
|
)
|
|
226
242
|
|
|
243
|
+
# This fixes issue described in: https://github.com/argoproj/argo-workflows/issues/10340
|
|
244
|
+
k8s_yaml(encode_yaml({
|
|
245
|
+
'apiVersion': 'v1',
|
|
246
|
+
'kind': 'Secret',
|
|
247
|
+
'metadata': {
|
|
248
|
+
'name': 'default.service-account-token',
|
|
249
|
+
'annotations': {
|
|
250
|
+
'kubernetes.io/service-account.name': 'default'
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
'type': 'kubernetes.io/service-account-token'
|
|
254
|
+
}))
|
|
255
|
+
|
|
227
256
|
k8s_yaml(encode_yaml({
|
|
228
257
|
'apiVersion': 'rbac.authorization.k8s.io/v1',
|
|
229
258
|
'kind': 'Role',
|
|
@@ -231,11 +260,23 @@ if "argo-workflows" in enabled_components:
|
|
|
231
260
|
'name': 'argo-workflowtaskresults-role',
|
|
232
261
|
'namespace': 'default'
|
|
233
262
|
},
|
|
234
|
-
'rules': [
|
|
263
|
+
'rules': [
|
|
264
|
+
{
|
|
235
265
|
'apiGroups': ['argoproj.io'],
|
|
236
266
|
'resources': ['workflowtaskresults'],
|
|
237
267
|
'verbs': ['create', 'patch', 'get', 'list']
|
|
238
|
-
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
'apiGroups': ['argoproj.io'],
|
|
271
|
+
'resources': ['workflowtasksets'],
|
|
272
|
+
'verbs': ['watch', 'list']
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
'apiGroups': ['argoproj.io'],
|
|
276
|
+
'resources': ['workflowtasksets/status'],
|
|
277
|
+
'verbs': ['patch']
|
|
278
|
+
},
|
|
279
|
+
]
|
|
239
280
|
}))
|
|
240
281
|
|
|
241
282
|
k8s_yaml(encode_yaml({
|
|
@@ -282,6 +323,7 @@ if "argo-workflows" in enabled_components:
|
|
|
282
323
|
if "argo-events" in enabled_components:
|
|
283
324
|
helm_remote(
|
|
284
325
|
'argo-events',
|
|
326
|
+
version=ARGO_EVENTS_HELM_CHART_VERSION,
|
|
285
327
|
repo_name='argo',
|
|
286
328
|
repo_url='https://argoproj.github.io/argo-helm',
|
|
287
329
|
set=[
|
|
@@ -309,6 +351,8 @@ if "argo-events" in enabled_components:
|
|
|
309
351
|
'configs.jetstream.versions[1].natsImage=nats:2.9.15',
|
|
310
352
|
'configs.jetstream.versions[1].startCommand=/nats-server',
|
|
311
353
|
'configs.jetstream.versions[1].version=2.9.15',
|
|
354
|
+
# Image version overrides
|
|
355
|
+
'global.image.tag=%s' % ARGO_EVENTS_IMAGE_TAG,
|
|
312
356
|
]
|
|
313
357
|
)
|
|
314
358
|
|
|
@@ -516,6 +560,62 @@ if "argo-events" in enabled_components:
|
|
|
516
560
|
config_resources.append('argo-events-controller-manager')
|
|
517
561
|
config_resources.append('argo-events-webhook-eventsource-svc')
|
|
518
562
|
|
|
563
|
+
#################################################
|
|
564
|
+
# JOBSET
|
|
565
|
+
#################################################
|
|
566
|
+
if "jobset" in enabled_components:
|
|
567
|
+
# Apply JobSet manifests directly from GitHub releases
|
|
568
|
+
jobset_manifest_url = "https://github.com/kubernetes-sigs/jobset/releases/download/%s/manifests.yaml" % JOBSET_VERSION
|
|
569
|
+
|
|
570
|
+
cmd = "curl -sSL %s" % (jobset_manifest_url)
|
|
571
|
+
k8s_yaml(
|
|
572
|
+
local(
|
|
573
|
+
cmd,
|
|
574
|
+
)
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
k8s_resource(
|
|
578
|
+
'jobset-controller-manager',
|
|
579
|
+
labels=['jobset'],
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
metaflow_config["METAFLOW_KUBERNETES_JOBSET_ENABLED"] = "true"
|
|
583
|
+
|
|
584
|
+
config_resources.append('jobset-controller-manager')
|
|
585
|
+
|
|
586
|
+
# ClusterRole for jobset operations
|
|
587
|
+
k8s_yaml(encode_yaml({
|
|
588
|
+
'apiVersion': 'rbac.authorization.k8s.io/v1',
|
|
589
|
+
'kind': 'ClusterRole',
|
|
590
|
+
'metadata': {
|
|
591
|
+
'name': 'jobset-full-access'
|
|
592
|
+
},
|
|
593
|
+
'rules': [{
|
|
594
|
+
'apiGroups': ['jobset.x-k8s.io'],
|
|
595
|
+
'resources': ['jobsets'],
|
|
596
|
+
'verbs': ['*']
|
|
597
|
+
}]
|
|
598
|
+
}))
|
|
599
|
+
|
|
600
|
+
# ClusterRoleBinding for default service account to access jobsets
|
|
601
|
+
k8s_yaml(encode_yaml({
|
|
602
|
+
'apiVersion': 'rbac.authorization.k8s.io/v1',
|
|
603
|
+
'kind': 'ClusterRoleBinding',
|
|
604
|
+
'metadata': {
|
|
605
|
+
'name': 'default-jobset-binding'
|
|
606
|
+
},
|
|
607
|
+
'subjects': [{
|
|
608
|
+
'kind': 'ServiceAccount',
|
|
609
|
+
'name': 'default',
|
|
610
|
+
'namespace': 'default'
|
|
611
|
+
}],
|
|
612
|
+
'roleRef': {
|
|
613
|
+
'kind': 'ClusterRole',
|
|
614
|
+
'name': 'jobset-full-access',
|
|
615
|
+
'apiGroup': 'rbac.authorization.k8s.io'
|
|
616
|
+
}
|
|
617
|
+
}))
|
|
618
|
+
|
|
519
619
|
#################################################
|
|
520
620
|
# METADATA SERVICE
|
|
521
621
|
#################################################
|
|
@@ -530,7 +630,7 @@ if "metadata-service" in enabled_components:
|
|
|
530
630
|
'metadatadb.database=metaflow',
|
|
531
631
|
'metadatadb.host=postgresql',
|
|
532
632
|
'image.repository=public.ecr.aws/outerbounds/metaflow_metadata_service',
|
|
533
|
-
'image.tag=2.
|
|
633
|
+
'image.tag=2.5.0',
|
|
534
634
|
'resources.requests.cpu=25m',
|
|
535
635
|
'resources.requests.memory=64Mi',
|
|
536
636
|
'resources.limits.cpu=50m',
|
|
@@ -568,7 +668,7 @@ if "ui" in enabled_components:
|
|
|
568
668
|
'uiBackend.metaflowDatastoreSysRootS3=s3://metaflow-test',
|
|
569
669
|
'uiBackend.metaflowS3EndpointURL=http://minio.default.svc.cluster.local:9000',
|
|
570
670
|
'uiBackend.image.name=public.ecr.aws/outerbounds/metaflow_metadata_service',
|
|
571
|
-
'uiBackend.image.tag=2.
|
|
671
|
+
'uiBackend.image.tag=2.5.0',
|
|
572
672
|
'uiBackend.env[0].name=AWS_ACCESS_KEY_ID',
|
|
573
673
|
'uiBackend.env[0].value=rootuser',
|
|
574
674
|
'uiBackend.env[1].name=AWS_SECRET_ACCESS_KEY',
|
|
@@ -578,7 +678,7 @@ if "ui" in enabled_components:
|
|
|
578
678
|
'uiBackend.resources.requests.memory=256Mi',
|
|
579
679
|
'uiStatic.metaflowUIBackendURL=http://localhost:8083/api',
|
|
580
680
|
'uiStatic.image.name=public.ecr.aws/outerbounds/metaflow_ui',
|
|
581
|
-
'uiStatic.image.tag=v1.3.
|
|
681
|
+
'uiStatic.image.tag=v1.3.14',
|
|
582
682
|
'uiStatic.resources.requests.cpu=25m',
|
|
583
683
|
'uiStatic.resources.requests.memory=64Mi',
|
|
584
684
|
'uiStatic.resources.limits.cpu=50m',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ob-metaflow
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.19.7.1rc0
|
|
4
4
|
Summary: Metaflow: More AI and ML, Less Engineering
|
|
5
5
|
Author: Netflix, Outerbounds & the Metaflow Community
|
|
6
6
|
Author-email: help@outerbounds.co
|
|
@@ -12,7 +12,7 @@ Requires-Dist: boto3
|
|
|
12
12
|
Requires-Dist: pylint
|
|
13
13
|
Requires-Dist: kubernetes
|
|
14
14
|
Provides-Extra: stubs
|
|
15
|
-
Requires-Dist: metaflow-stubs==2.
|
|
15
|
+
Requires-Dist: metaflow-stubs==2.19.7.1rc0; extra == "stubs"
|
|
16
16
|
Dynamic: author
|
|
17
17
|
Dynamic: author-email
|
|
18
18
|
Dynamic: description
|
|
@@ -85,4 +85,3 @@ We'd love to hear from you. Join our community [Slack workspace](http://slack.ou
|
|
|
85
85
|
|
|
86
86
|
## Contributing
|
|
87
87
|
We welcome contributions to Metaflow. Please see our [contribution guide](https://docs.metaflow.org/introduction/contributing-to-metaflow) for more details.
|
|
88
|
-
|