metaflow 2.16.6__py2.py3-none-any.whl → 2.16.8__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/_vendor/click/core.py +3 -4
- metaflow/_vendor/imghdr/__init__.py +11 -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/cli.py +11 -2
- metaflow/client/core.py +6 -1
- metaflow/extension_support/__init__.py +4 -3
- metaflow/metaflow_environment.py +14 -6
- metaflow/package/__init__.py +18 -9
- metaflow/packaging_sys/__init__.py +53 -43
- metaflow/packaging_sys/backend.py +21 -6
- metaflow/packaging_sys/tar_backend.py +16 -3
- metaflow/packaging_sys/v1.py +21 -21
- metaflow/plugins/argo/argo_workflows.py +60 -2
- metaflow/plugins/argo/argo_workflows_deployer_objects.py +37 -0
- metaflow/plugins/aws/step_functions/step_functions_deployer_objects.py +16 -0
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +7 -1
- metaflow/plugins/kubernetes/kubernetes_jobsets.py +26 -28
- metaflow/plugins/pypi/conda_decorator.py +4 -2
- metaflow/runner/click_api.py +14 -7
- metaflow/runner/deployer.py +77 -0
- metaflow/runner/subprocess_manager.py +20 -12
- metaflow/vendor.py +23 -6
- metaflow/version.py +1 -1
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/METADATA +2 -2
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/RECORD +48 -31
- {metaflow-2.16.6.data → metaflow-2.16.8.data}/data/share/metaflow/devtools/Makefile +0 -0
- {metaflow-2.16.6.data → metaflow-2.16.8.data}/data/share/metaflow/devtools/Tiltfile +0 -0
- {metaflow-2.16.6.data → metaflow-2.16.8.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/WHEEL +0 -0
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/entry_points.txt +0 -0
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/licenses/LICENSE +0 -0
- {metaflow-2.16.6.dist-info → metaflow-2.16.8.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
import tarfile
|
2
2
|
|
3
3
|
from io import BytesIO
|
4
|
-
from typing import IO, List, Optional, Union
|
4
|
+
from typing import Any, IO, List, Optional, Union
|
5
5
|
|
6
6
|
from .backend import PackagingBackend
|
7
7
|
|
@@ -56,6 +56,13 @@ class TarPackagingBackend(PackagingBackend):
|
|
56
56
|
def cls_open(cls, content: IO[bytes]) -> tarfile.TarFile:
|
57
57
|
return tarfile.open(fileobj=content, mode="r:gz")
|
58
58
|
|
59
|
+
@classmethod
|
60
|
+
def cls_member_name(cls, member: Union[tarfile.TarInfo, str]) -> str:
|
61
|
+
"""
|
62
|
+
Returns the name of the member as a string.
|
63
|
+
"""
|
64
|
+
return member.name if isinstance(member, tarfile.TarInfo) else member
|
65
|
+
|
59
66
|
@classmethod
|
60
67
|
def cls_has_member(cls, archive: tarfile.TarFile, name: str) -> bool:
|
61
68
|
try:
|
@@ -76,11 +83,17 @@ class TarPackagingBackend(PackagingBackend):
|
|
76
83
|
def cls_extract_members(
|
77
84
|
cls,
|
78
85
|
archive: tarfile.TarFile,
|
79
|
-
members: Optional[List[
|
86
|
+
members: Optional[List[Any]] = None,
|
80
87
|
dest_dir: str = ".",
|
81
88
|
) -> None:
|
82
89
|
archive.extractall(path=dest_dir, members=members)
|
83
90
|
|
84
91
|
@classmethod
|
85
|
-
def cls_list_members(
|
92
|
+
def cls_list_members(
|
93
|
+
cls, archive: tarfile.TarFile
|
94
|
+
) -> Optional[List[tarfile.TarInfo]]:
|
95
|
+
return archive.getmembers() or None
|
96
|
+
|
97
|
+
@classmethod
|
98
|
+
def cls_list_names(cls, archive: tarfile.TarFile) -> Optional[List[str]]:
|
86
99
|
return archive.getnames() or None
|
metaflow/packaging_sys/v1.py
CHANGED
@@ -61,23 +61,25 @@ class MetaflowCodeContentV1(MetaflowCodeContentV1Base):
|
|
61
61
|
else:
|
62
62
|
new_modules = []
|
63
63
|
|
64
|
-
self._modules = {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
64
|
+
self._modules = {} # type: Dict[str, _ModuleInfo]
|
65
|
+
# We do this explicitly module by module to harden it against misbehaving
|
66
|
+
# modules like the one in:
|
67
|
+
# https://github.com/Netflix/metaflow/issues/2512
|
68
|
+
# We will silently ignore modules that are not well built.
|
69
|
+
for name, mod in new_modules:
|
70
|
+
try:
|
71
|
+
minfo = _ModuleInfo(
|
72
|
+
name,
|
73
|
+
set(
|
74
|
+
Path(p).resolve().as_posix()
|
75
|
+
for p in getattr(mod, "__path__", [mod.__file__])
|
76
|
+
),
|
77
|
+
mod,
|
78
|
+
True, # This is a Metaflow module (see filter below)
|
79
|
+
)
|
80
|
+
except:
|
81
|
+
continue
|
82
|
+
self._modules[name] = minfo
|
81
83
|
|
82
84
|
# Contain metadata information regarding the distributions packaged.
|
83
85
|
# This allows Metaflow to "fake" distribution information when packaged
|
@@ -355,16 +357,14 @@ class MetaflowCodeContentV1(MetaflowCodeContentV1Base):
|
|
355
357
|
)
|
356
358
|
yield json.dumps(self.create_mfcontent_info()).encode(
|
357
359
|
"utf-8"
|
358
|
-
),
|
360
|
+
), MFCONTENT_MARKER
|
359
361
|
else:
|
360
362
|
for k in self._other_content.keys():
|
361
363
|
yield "<generated %s content>" % (os.path.basename(k)), k
|
362
364
|
yield "<generated %s content>" % (
|
363
365
|
os.path.basename(self._dist_info_file)
|
364
366
|
), os.path.join(self._other_dir, self._dist_info_file)
|
365
|
-
yield "<generated %s content>" % MFCONTENT_MARKER,
|
366
|
-
self._code_dir, MFCONTENT_MARKER
|
367
|
-
)
|
367
|
+
yield "<generated %s content>" % MFCONTENT_MARKER, MFCONTENT_MARKER
|
368
368
|
|
369
369
|
def _metaflow_distribution_files(self) -> Generator[Tuple[str, str], None, None]:
|
370
370
|
debug.package_exec("Including Metaflow from '%s'" % self._metaflow_root)
|
@@ -3226,8 +3226,8 @@ class ArgoWorkflows(object):
|
|
3226
3226
|
Trigger().template(
|
3227
3227
|
TriggerTemplate(self.name)
|
3228
3228
|
# Trigger a deployed workflow template
|
3229
|
-
.
|
3230
|
-
|
3229
|
+
.k8s_trigger(
|
3230
|
+
StandardK8STrigger()
|
3231
3231
|
.source(
|
3232
3232
|
{
|
3233
3233
|
"resource": {
|
@@ -4205,6 +4205,10 @@ class TriggerTemplate(object):
|
|
4205
4205
|
self.payload = tree()
|
4206
4206
|
self.payload["name"] = name
|
4207
4207
|
|
4208
|
+
def k8s_trigger(self, k8s_trigger):
|
4209
|
+
self.payload["k8s"] = k8s_trigger.to_json()
|
4210
|
+
return self
|
4211
|
+
|
4208
4212
|
def argo_workflow_trigger(self, argo_workflow_trigger):
|
4209
4213
|
self.payload["argoWorkflow"] = argo_workflow_trigger.to_json()
|
4210
4214
|
return self
|
@@ -4279,3 +4283,57 @@ class TriggerParameter(object):
|
|
4279
4283
|
|
4280
4284
|
def __str__(self):
|
4281
4285
|
return json.dumps(self.payload, indent=4)
|
4286
|
+
|
4287
|
+
|
4288
|
+
class StandardK8STrigger(object):
|
4289
|
+
# https://pkg.go.dev/github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1#StandardK8STrigger
|
4290
|
+
|
4291
|
+
def __init__(self):
|
4292
|
+
tree = lambda: defaultdict(tree)
|
4293
|
+
self.payload = tree()
|
4294
|
+
self.payload["operation"] = "create"
|
4295
|
+
|
4296
|
+
def operation(self, operation):
|
4297
|
+
self.payload["operation"] = operation
|
4298
|
+
return self
|
4299
|
+
|
4300
|
+
def group(self, group):
|
4301
|
+
self.payload["group"] = group
|
4302
|
+
return self
|
4303
|
+
|
4304
|
+
def version(self, version):
|
4305
|
+
self.payload["version"] = version
|
4306
|
+
return self
|
4307
|
+
|
4308
|
+
def resource(self, resource):
|
4309
|
+
self.payload["resource"] = resource
|
4310
|
+
return self
|
4311
|
+
|
4312
|
+
def namespace(self, namespace):
|
4313
|
+
self.payload["namespace"] = namespace
|
4314
|
+
return self
|
4315
|
+
|
4316
|
+
def source(self, source):
|
4317
|
+
self.payload["source"] = source
|
4318
|
+
return self
|
4319
|
+
|
4320
|
+
def parameters(self, trigger_parameters):
|
4321
|
+
if "parameters" not in self.payload:
|
4322
|
+
self.payload["parameters"] = []
|
4323
|
+
for trigger_parameter in trigger_parameters:
|
4324
|
+
self.payload["parameters"].append(trigger_parameter.to_json())
|
4325
|
+
return self
|
4326
|
+
|
4327
|
+
def live_object(self, live_object=True):
|
4328
|
+
self.payload["liveObject"] = live_object
|
4329
|
+
return self
|
4330
|
+
|
4331
|
+
def patch_strategy(self, patch_strategy):
|
4332
|
+
self.payload["patchStrategy"] = patch_strategy
|
4333
|
+
return self
|
4334
|
+
|
4335
|
+
def to_json(self):
|
4336
|
+
return self.payload
|
4337
|
+
|
4338
|
+
def __str__(self):
|
4339
|
+
return json.dumps(self.payload, indent=4)
|
@@ -310,6 +310,43 @@ class ArgoWorkflowsDeployedFlow(DeployedFlow):
|
|
310
310
|
|
311
311
|
return cls(deployer=d)
|
312
312
|
|
313
|
+
@classmethod
|
314
|
+
def get_triggered_run(
|
315
|
+
cls, identifier: str, run_id: str, metadata: Optional[str] = None
|
316
|
+
):
|
317
|
+
"""
|
318
|
+
Retrieves a `ArgoWorkflowsTriggeredRun` object from an identifier, a run id and
|
319
|
+
optional metadata.
|
320
|
+
|
321
|
+
Parameters
|
322
|
+
----------
|
323
|
+
identifier : str
|
324
|
+
Deployer specific identifier for the workflow to retrieve
|
325
|
+
run_id : str
|
326
|
+
Run ID for the which to fetch the triggered run object
|
327
|
+
metadata : str, optional, default None
|
328
|
+
Optional deployer specific metadata.
|
329
|
+
|
330
|
+
Returns
|
331
|
+
-------
|
332
|
+
ArgoWorkflowsTriggeredRun
|
333
|
+
A `ArgoWorkflowsTriggeredRun` object representing the
|
334
|
+
triggered run on argo workflows.
|
335
|
+
"""
|
336
|
+
deployed_flow_obj = cls.from_deployment(identifier, metadata)
|
337
|
+
return ArgoWorkflowsTriggeredRun(
|
338
|
+
deployer=deployed_flow_obj.deployer,
|
339
|
+
content=json.dumps(
|
340
|
+
{
|
341
|
+
"metadata": deployed_flow_obj.deployer.metadata,
|
342
|
+
"pathspec": "/".join(
|
343
|
+
(deployed_flow_obj.deployer.flow_name, run_id)
|
344
|
+
),
|
345
|
+
"name": run_id,
|
346
|
+
}
|
347
|
+
),
|
348
|
+
)
|
349
|
+
|
313
350
|
@property
|
314
351
|
def production_token(self) -> Optional[str]:
|
315
352
|
"""
|
@@ -84,6 +84,22 @@ class StepFunctionsDeployedFlow(DeployedFlow):
|
|
84
84
|
"from_deployment is not implemented for StepFunctions"
|
85
85
|
)
|
86
86
|
|
87
|
+
@classmethod
|
88
|
+
def get_triggered_run(
|
89
|
+
cls, identifier: str, run_id: str, metadata: Optional[str] = None
|
90
|
+
):
|
91
|
+
"""
|
92
|
+
This method is not currently implemented for Step Functions.
|
93
|
+
|
94
|
+
Raises
|
95
|
+
------
|
96
|
+
NotImplementedError
|
97
|
+
This method is not implemented for Step Functions.
|
98
|
+
"""
|
99
|
+
raise NotImplementedError(
|
100
|
+
"get_triggered_run is not implemented for StepFunctions"
|
101
|
+
)
|
102
|
+
|
87
103
|
@property
|
88
104
|
def production_token(self: DeployedFlow) -> Optional[str]:
|
89
105
|
"""
|
@@ -146,7 +146,13 @@ class TaskToDict:
|
|
146
146
|
# Python 3.13 removes the standard ``imghdr`` module. Metaflow
|
147
147
|
# vendors a copy so we can keep using ``what`` to detect image
|
148
148
|
# formats irrespective of the Python version.
|
149
|
-
|
149
|
+
import warnings
|
150
|
+
|
151
|
+
with warnings.catch_warnings():
|
152
|
+
warnings.filterwarnings(
|
153
|
+
"ignore", category=DeprecationWarning, module="imghdr"
|
154
|
+
)
|
155
|
+
from metaflow._vendor import imghdr
|
150
156
|
|
151
157
|
resp = imghdr.what(None, h=data_object)
|
152
158
|
# Only accept types supported on the web
|
@@ -6,6 +6,7 @@ from collections import namedtuple
|
|
6
6
|
from metaflow.exception import MetaflowException
|
7
7
|
from metaflow.metaflow_config import KUBERNETES_JOBSET_GROUP, KUBERNETES_JOBSET_VERSION
|
8
8
|
from metaflow.tracing import inject_tracing_vars
|
9
|
+
from metaflow._vendor import yaml
|
9
10
|
|
10
11
|
from .kube_utils import qos_requests_and_limits
|
11
12
|
|
@@ -1025,34 +1026,32 @@ class KubernetesArgoJobSet(object):
|
|
1025
1026
|
|
1026
1027
|
def dump(self):
|
1027
1028
|
client = self._kubernetes_sdk
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
),
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
),
|
1052
|
-
status=None,
|
1053
|
-
)
|
1029
|
+
js_dict = client.ApiClient().sanitize_for_serialization(
|
1030
|
+
dict(
|
1031
|
+
apiVersion=self._group + "/" + self._version,
|
1032
|
+
kind="JobSet",
|
1033
|
+
metadata=client.api_client.ApiClient().sanitize_for_serialization(
|
1034
|
+
client.V1ObjectMeta(
|
1035
|
+
name=self.name,
|
1036
|
+
labels=self._labels,
|
1037
|
+
annotations=self._annotations,
|
1038
|
+
)
|
1039
|
+
),
|
1040
|
+
spec=dict(
|
1041
|
+
replicatedJobs=[self.control.dump(), self.worker.dump()],
|
1042
|
+
suspend=False,
|
1043
|
+
startupPolicy=None,
|
1044
|
+
successPolicy=None,
|
1045
|
+
# The Failure Policy helps setting the number of retries for the jobset.
|
1046
|
+
# but we don't rely on it and instead rely on either the local scheduler
|
1047
|
+
# or the Argo Workflows to handle retries.
|
1048
|
+
failurePolicy=None,
|
1049
|
+
network=None,
|
1050
|
+
),
|
1051
|
+
status=None,
|
1054
1052
|
)
|
1055
1053
|
)
|
1054
|
+
data = yaml.dump(js_dict, default_flow_style=False, indent=2)
|
1056
1055
|
# The values we populate in the Jobset manifest (for Argo Workflows) piggybacks on the Argo Workflow's templating engine.
|
1057
1056
|
# Even though Argo Workflows's templating helps us constructing all the necessary IDs and populating the fields
|
1058
1057
|
# required by Metaflow, we run into one glitch. When we construct JSON/YAML serializable objects,
|
@@ -1067,7 +1066,6 @@ class KubernetesArgoJobSet(object):
|
|
1067
1066
|
# Since the value of `num_parallel` can be dynamic and can change from run to run, we need to ensure that the
|
1068
1067
|
# value can be passed-down dynamically and is **explicitly set as a integer** in the Jobset Manifest submitted as a
|
1069
1068
|
# part of the Argo Workflow
|
1070
|
-
|
1071
|
-
quoted_substring = '"{{=asInt(inputs.parameters.workerCount)}}"'
|
1069
|
+
quoted_substring = "'{{=asInt(inputs.parameters.workerCount)}}'"
|
1072
1070
|
unquoted_substring = "{{=asInt(inputs.parameters.workerCount)}}"
|
1073
1071
|
return data.replace(quoted_substring, unquoted_substring)
|
@@ -243,9 +243,11 @@ class CondaStepDecorator(StepDecorator):
|
|
243
243
|
# Ensure local installation of Metaflow is visible to user code
|
244
244
|
python_path = self.__class__._metaflow_home.name
|
245
245
|
addl_env_vars = {}
|
246
|
-
if self.__class__._addl_env_vars
|
246
|
+
if self.__class__._addl_env_vars:
|
247
247
|
for key, value in self.__class__._addl_env_vars.items():
|
248
|
-
if key
|
248
|
+
if key.endswith(":"):
|
249
|
+
addl_env_vars[key[:-1]] = value
|
250
|
+
elif key == "PYTHONPATH":
|
249
251
|
addl_env_vars[key] = os.pathsep.join([value, python_path])
|
250
252
|
else:
|
251
253
|
addl_env_vars[key] = value
|
metaflow/runner/click_api.py
CHANGED
@@ -43,6 +43,7 @@ from metaflow._vendor.click.types import (
|
|
43
43
|
)
|
44
44
|
from metaflow.decorators import add_decorator_options
|
45
45
|
from metaflow.exception import MetaflowException
|
46
|
+
from metaflow.flowspec import _FlowState
|
46
47
|
from metaflow.includefile import FilePathClass
|
47
48
|
from metaflow.metaflow_config import CLICK_API_PROCESS_CONFIG
|
48
49
|
from metaflow.parameters import JSONTypeClass, flow_context
|
@@ -171,7 +172,6 @@ def _lazy_load_command(
|
|
171
172
|
_self,
|
172
173
|
name: str,
|
173
174
|
):
|
174
|
-
|
175
175
|
# Context is not used in get_command so we can pass None. Since we pin click,
|
176
176
|
# this won't change from under us.
|
177
177
|
|
@@ -516,6 +516,11 @@ class MetaflowAPI(object):
|
|
516
516
|
# Note that if CLICK_API_PROCESS_CONFIG is False, we still do this because
|
517
517
|
# it will init all parameters (config_options will be None)
|
518
518
|
# We ignore any errors if we don't check the configs in the click API.
|
519
|
+
|
520
|
+
# Init all values in the flow mutators and then process them
|
521
|
+
for decorator in self._flow_cls._flow_state.get(_FlowState.FLOW_MUTATORS, []):
|
522
|
+
decorator.external_init()
|
523
|
+
|
519
524
|
new_cls = self._flow_cls._process_config_decorators(
|
520
525
|
config_options, process_configs=CLICK_API_PROCESS_CONFIG
|
521
526
|
)
|
@@ -541,14 +546,16 @@ def extract_all_params(cmd_obj: Union[click.Command, click.Group]):
|
|
541
546
|
|
542
547
|
for each_param in cmd_obj.params:
|
543
548
|
if isinstance(each_param, click.Argument):
|
544
|
-
|
545
|
-
|
546
|
-
|
549
|
+
(
|
550
|
+
arg_params_sigs[each_param.name],
|
551
|
+
annotations[each_param.name],
|
552
|
+
) = get_inspect_param_obj(each_param, inspect.Parameter.POSITIONAL_ONLY)
|
547
553
|
arg_parameters[each_param.name] = each_param
|
548
554
|
elif isinstance(each_param, click.Option):
|
549
|
-
|
550
|
-
|
551
|
-
|
555
|
+
(
|
556
|
+
opt_params_sigs[each_param.name],
|
557
|
+
annotations[each_param.name],
|
558
|
+
) = get_inspect_param_obj(each_param, inspect.Parameter.KEYWORD_ONLY)
|
552
559
|
opt_parameters[each_param.name] = each_param
|
553
560
|
|
554
561
|
defaults[each_param.name] = each_param.default
|
metaflow/runner/deployer.py
CHANGED
@@ -231,6 +231,67 @@ class DeployedFlowMeta(type):
|
|
231
231
|
}
|
232
232
|
)
|
233
233
|
|
234
|
+
def _get_triggered_run_injected_method():
|
235
|
+
def f(
|
236
|
+
cls,
|
237
|
+
identifier: str,
|
238
|
+
run_id: str,
|
239
|
+
metadata: Optional[str] = None,
|
240
|
+
impl: str = DEFAULT_FROM_DEPLOYMENT_IMPL.replace("-", "_"),
|
241
|
+
) -> "TriggeredRun":
|
242
|
+
"""
|
243
|
+
Retrieves a `TriggeredRun` object from an identifier, a run id and optional
|
244
|
+
metadata. The `impl` parameter specifies the deployer implementation
|
245
|
+
to use (like `argo-workflows`).
|
246
|
+
|
247
|
+
Parameters
|
248
|
+
----------
|
249
|
+
identifier : str
|
250
|
+
Deployer specific identifier for the workflow to retrieve
|
251
|
+
run_id : str
|
252
|
+
Run ID for the which to fetch the triggered run object
|
253
|
+
metadata : str, optional, default None
|
254
|
+
Optional deployer specific metadata.
|
255
|
+
impl : str, optional, default given by METAFLOW_DEFAULT_FROM_DEPLOYMENT_IMPL
|
256
|
+
The default implementation to use if not specified
|
257
|
+
|
258
|
+
Returns
|
259
|
+
-------
|
260
|
+
TriggeredRun
|
261
|
+
A `TriggeredRun` object representing the triggered run corresponding
|
262
|
+
to the identifier and the run id.
|
263
|
+
"""
|
264
|
+
if impl in allowed_providers:
|
265
|
+
return (
|
266
|
+
allowed_providers[impl]
|
267
|
+
.deployed_flow_type()
|
268
|
+
.get_triggered_run(identifier, run_id, metadata)
|
269
|
+
)
|
270
|
+
else:
|
271
|
+
raise ValueError(
|
272
|
+
f"No deployer '{impl}' exists; valid deployers are: "
|
273
|
+
f"{list(allowed_providers.keys())}"
|
274
|
+
)
|
275
|
+
|
276
|
+
f.__name__ = "get_triggered_run"
|
277
|
+
return f
|
278
|
+
|
279
|
+
def _per_type_get_triggered_run_injected_method(method_name, impl):
|
280
|
+
def f(
|
281
|
+
cls,
|
282
|
+
identifier: str,
|
283
|
+
run_id: str,
|
284
|
+
metadata: Optional[str] = None,
|
285
|
+
):
|
286
|
+
return (
|
287
|
+
allowed_providers[impl]
|
288
|
+
.deployed_flow_type()
|
289
|
+
.get_triggered_run(identifier, run_id, metadata)
|
290
|
+
)
|
291
|
+
|
292
|
+
f.__name__ = method_name
|
293
|
+
return f
|
294
|
+
|
234
295
|
def _from_deployment_injected_method():
|
235
296
|
def f(
|
236
297
|
cls,
|
@@ -347,10 +408,16 @@ class DeployedFlowMeta(type):
|
|
347
408
|
"list_deployed_flows",
|
348
409
|
classmethod(_list_deployed_flows_injected_method()),
|
349
410
|
)
|
411
|
+
setattr(
|
412
|
+
cls,
|
413
|
+
"get_triggered_run",
|
414
|
+
classmethod(_get_triggered_run_injected_method()),
|
415
|
+
)
|
350
416
|
|
351
417
|
for impl in allowed_providers:
|
352
418
|
from_deployment_method_name = f"from_{impl}"
|
353
419
|
list_deployed_flows_method_name = f"list_{impl}"
|
420
|
+
get_triggered_run_method_name = f"get_triggered_{impl}_run"
|
354
421
|
|
355
422
|
setattr(
|
356
423
|
cls,
|
@@ -372,6 +439,16 @@ class DeployedFlowMeta(type):
|
|
372
439
|
),
|
373
440
|
)
|
374
441
|
|
442
|
+
setattr(
|
443
|
+
cls,
|
444
|
+
get_triggered_run_method_name,
|
445
|
+
classmethod(
|
446
|
+
_per_type_get_triggered_run_injected_method(
|
447
|
+
get_triggered_run_method_name, impl
|
448
|
+
)
|
449
|
+
),
|
450
|
+
)
|
451
|
+
|
375
452
|
return cls
|
376
453
|
|
377
454
|
|
@@ -152,12 +152,20 @@ class SubprocessManager(object):
|
|
152
152
|
int
|
153
153
|
The process ID of the subprocess.
|
154
154
|
"""
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
155
|
+
env = env or {}
|
156
|
+
installed_root = os.environ.get("METAFLOW_EXTRACTED_ROOT", get_metaflow_root())
|
157
|
+
|
158
|
+
for k, v in MetaflowCodeContent.get_env_vars_for_packaged_metaflow(
|
159
|
+
installed_root
|
160
|
+
).items():
|
161
|
+
if k.endswith(":"):
|
162
|
+
# Override
|
163
|
+
env[k[:-1]] = v
|
164
|
+
elif k in env:
|
165
|
+
env[k] = "%s:%s" % (v, env[k])
|
166
|
+
else:
|
167
|
+
env[k] = v
|
168
|
+
|
161
169
|
command_obj = CommandManager(command, env, cwd)
|
162
170
|
pid = command_obj.run(show_output=show_output)
|
163
171
|
self.commands[pid] = command_obj
|
@@ -188,12 +196,12 @@ class SubprocessManager(object):
|
|
188
196
|
int
|
189
197
|
The process ID of the subprocess.
|
190
198
|
"""
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
env =
|
196
|
-
|
199
|
+
env = env or {}
|
200
|
+
if "PYTHONPATH" in env:
|
201
|
+
env["PYTHONPATH"] = "%s:%s" % (get_metaflow_root(), env["PYTHONPATH"])
|
202
|
+
else:
|
203
|
+
env["PYTHONPATH"] = get_metaflow_root()
|
204
|
+
|
197
205
|
command_obj = CommandManager(command, env, cwd)
|
198
206
|
pid = await command_obj.async_run()
|
199
207
|
self.commands[pid] = command_obj
|
metaflow/vendor.py
CHANGED
@@ -63,14 +63,29 @@ def find_vendored_libs(vendor_dir, whitelist, whitelist_dirs):
|
|
63
63
|
return vendored_libs, paths
|
64
64
|
|
65
65
|
|
66
|
-
def fetch_licenses(*
|
67
|
-
for
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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:
|
72
78
|
continue
|
73
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
|
+
|
74
89
|
|
75
90
|
def vendor(vendor_dir):
|
76
91
|
# remove everything
|
@@ -108,6 +123,8 @@ def vendor(vendor_dir):
|
|
108
123
|
"-r",
|
109
124
|
"_vendor/vendor_%s.txt" % subdir,
|
110
125
|
"--no-compile",
|
126
|
+
"--no-binary",
|
127
|
+
":all:",
|
111
128
|
]
|
112
129
|
)
|
113
130
|
|
metaflow/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
metaflow_version = "2.16.
|
1
|
+
metaflow_version = "2.16.8"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: metaflow
|
3
|
-
Version: 2.16.
|
3
|
+
Version: 2.16.8
|
4
4
|
Summary: Metaflow: More AI and ML, Less Engineering
|
5
5
|
Author: Metaflow Developers
|
6
6
|
Author-email: help@metaflow.org
|
@@ -26,7 +26,7 @@ License-File: LICENSE
|
|
26
26
|
Requires-Dist: requests
|
27
27
|
Requires-Dist: boto3
|
28
28
|
Provides-Extra: stubs
|
29
|
-
Requires-Dist: metaflow-stubs==2.16.
|
29
|
+
Requires-Dist: metaflow-stubs==2.16.8; extra == "stubs"
|
30
30
|
Dynamic: author
|
31
31
|
Dynamic: author-email
|
32
32
|
Dynamic: classifier
|