metaflow 2.11.16__py2.py3-none-any.whl → 2.12.0__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 (46) hide show
  1. metaflow/__init__.py +5 -0
  2. metaflow/_vendor/importlib_metadata/__init__.py +1063 -0
  3. metaflow/_vendor/importlib_metadata/_adapters.py +68 -0
  4. metaflow/_vendor/importlib_metadata/_collections.py +30 -0
  5. metaflow/_vendor/importlib_metadata/_compat.py +71 -0
  6. metaflow/_vendor/importlib_metadata/_functools.py +104 -0
  7. metaflow/_vendor/importlib_metadata/_itertools.py +73 -0
  8. metaflow/_vendor/importlib_metadata/_meta.py +48 -0
  9. metaflow/_vendor/importlib_metadata/_text.py +99 -0
  10. metaflow/_vendor/importlib_metadata/py.typed +0 -0
  11. metaflow/_vendor/typeguard/__init__.py +48 -0
  12. metaflow/_vendor/typeguard/_checkers.py +906 -0
  13. metaflow/_vendor/typeguard/_config.py +108 -0
  14. metaflow/_vendor/typeguard/_decorators.py +237 -0
  15. metaflow/_vendor/typeguard/_exceptions.py +42 -0
  16. metaflow/_vendor/typeguard/_functions.py +307 -0
  17. metaflow/_vendor/typeguard/_importhook.py +213 -0
  18. metaflow/_vendor/typeguard/_memo.py +48 -0
  19. metaflow/_vendor/typeguard/_pytest_plugin.py +100 -0
  20. metaflow/_vendor/typeguard/_suppression.py +88 -0
  21. metaflow/_vendor/typeguard/_transformer.py +1193 -0
  22. metaflow/_vendor/typeguard/_union_transformer.py +54 -0
  23. metaflow/_vendor/typeguard/_utils.py +169 -0
  24. metaflow/_vendor/typeguard/py.typed +0 -0
  25. metaflow/_vendor/typing_extensions.py +3053 -0
  26. metaflow/cli.py +48 -36
  27. metaflow/cmd/develop/stubs.py +2 -0
  28. metaflow/extension_support/__init__.py +2 -0
  29. metaflow/parameters.py +1 -0
  30. metaflow/plugins/aws/batch/batch_decorator.py +3 -3
  31. metaflow/plugins/kubernetes/kubernetes_job.py +0 -5
  32. metaflow/runner/__init__.py +0 -0
  33. metaflow/runner/click_api.py +406 -0
  34. metaflow/runner/metaflow_runner.py +452 -0
  35. metaflow/runner/nbrun.py +246 -0
  36. metaflow/runner/subprocess_manager.py +552 -0
  37. metaflow/vendor.py +0 -1
  38. metaflow/version.py +1 -1
  39. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/METADATA +2 -2
  40. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/RECORD +45 -17
  41. metaflow/_vendor/v3_7/__init__.py +0 -1
  42. /metaflow/_vendor/{v3_7/zipp.py → zipp.py} +0 -0
  43. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/LICENSE +0 -0
  44. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/WHEEL +0 -0
  45. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/entry_points.txt +0 -0
  46. {metaflow-2.11.16.dist-info → metaflow-2.12.0.dist-info}/top_level.txt +0 -0
metaflow/cli.py CHANGED
@@ -3,39 +3,16 @@ import sys
3
3
  import traceback
4
4
  from datetime import datetime
5
5
  from functools import wraps
6
- import metaflow.tracing as tracing
7
6
 
7
+ import metaflow.tracing as tracing
8
8
  from metaflow._vendor import click
9
9
 
10
- from . import lint
11
- from . import plugins
12
- from . import parameters
13
- from . import decorators
14
- from . import metaflow_version
15
- from . import namespace
16
- from .metaflow_current import current
10
+ from . import decorators, lint, metaflow_version, namespace, parameters, plugins
17
11
  from .cli_args import cli_args
18
- from .tagging_util import validate_tags
19
- from .util import (
20
- resolve_identity,
21
- decompress_list,
22
- write_latest_run_id,
23
- get_latest_run_id,
24
- )
25
- from .task import MetaflowTask
12
+ from .client.core import get_metadata
13
+ from .datastore import FlowDataStore, TaskDataStore, TaskDataStoreSet
26
14
  from .exception import CommandException, MetaflowException
27
15
  from .graph import FlowGraph
28
- from .datastore import FlowDataStore, TaskDataStoreSet, TaskDataStore
29
-
30
- from .runtime import NativeRuntime
31
- from .package import MetaflowPackage
32
- from .plugins import (
33
- DATASTORES,
34
- ENVIRONMENTS,
35
- LOGGING_SIDECARS,
36
- METADATA_PROVIDERS,
37
- MONITOR_SIDECARS,
38
- )
39
16
  from .metaflow_config import (
40
17
  DEFAULT_DATASTORE,
41
18
  DEFAULT_ENVIRONMENT,
@@ -44,12 +21,29 @@ from .metaflow_config import (
44
21
  DEFAULT_MONITOR,
45
22
  DEFAULT_PACKAGE_SUFFIXES,
46
23
  )
24
+ from .metaflow_current import current
47
25
  from .metaflow_environment import MetaflowEnvironment
26
+ from .mflog import LOG_SOURCES, mflog
27
+ from .package import MetaflowPackage
28
+ from .plugins import (
29
+ DATASTORES,
30
+ ENVIRONMENTS,
31
+ LOGGING_SIDECARS,
32
+ METADATA_PROVIDERS,
33
+ MONITOR_SIDECARS,
34
+ )
48
35
  from .pylint_wrapper import PyLint
49
- from .R import use_r, metaflow_r_version
50
- from .mflog import mflog, LOG_SOURCES
36
+ from .R import metaflow_r_version, use_r
37
+ from .runtime import NativeRuntime
38
+ from .tagging_util import validate_tags
39
+ from .task import MetaflowTask
51
40
  from .unbounded_foreach import UBF_CONTROL, UBF_TASK
52
-
41
+ from .util import (
42
+ decompress_list,
43
+ get_latest_run_id,
44
+ resolve_identity,
45
+ write_latest_run_id,
46
+ )
53
47
 
54
48
  ERASE_TO_EOL = "\033[K"
55
49
  HIGHLIGHT = "red"
@@ -557,6 +551,13 @@ def common_run_options(func):
557
551
  type=str,
558
552
  help="Write the ID of this run to the file specified.",
559
553
  )
554
+ @click.option(
555
+ "--runner-attribute-file",
556
+ default=None,
557
+ show_default=True,
558
+ type=str,
559
+ help="Write the metadata and pathspec of this run to the file specified. Used internally for Metaflow's Runner API.",
560
+ )
560
561
  @wraps(func)
561
562
  def wrapper(*args, **kwargs):
562
563
  return func(*args, **kwargs)
@@ -615,6 +616,7 @@ def resume(
615
616
  decospecs=None,
616
617
  run_id_file=None,
617
618
  resume_identifier=None,
619
+ runner_attribute_file=None,
618
620
  ):
619
621
  before_run(obj, tags, decospecs + obj.environment.decospecs())
620
622
 
@@ -670,9 +672,14 @@ def resume(
670
672
  max_log_size=max_log_size * 1024 * 1024,
671
673
  resume_identifier=resume_identifier,
672
674
  )
673
- write_run_id(run_id_file, runtime.run_id)
675
+ write_file(run_id_file, runtime.run_id)
674
676
  runtime.print_workflow_info()
677
+
675
678
  runtime.persist_constants()
679
+ write_file(
680
+ runner_attribute_file,
681
+ "%s:%s" % (get_metadata(), "/".join((obj.flow.name, runtime.run_id))),
682
+ )
676
683
  if clone_only:
677
684
  runtime.clone_original_run()
678
685
  else:
@@ -703,6 +710,7 @@ def run(
703
710
  max_log_size=None,
704
711
  decospecs=None,
705
712
  run_id_file=None,
713
+ runner_attribute_file=None,
706
714
  user_namespace=None,
707
715
  **kwargs
708
716
  ):
@@ -726,18 +734,22 @@ def run(
726
734
  max_log_size=max_log_size * 1024 * 1024,
727
735
  )
728
736
  write_latest_run_id(obj, runtime.run_id)
729
- write_run_id(run_id_file, runtime.run_id)
737
+ write_file(run_id_file, runtime.run_id)
730
738
 
731
739
  obj.flow._set_constants(obj.graph, kwargs)
732
740
  runtime.print_workflow_info()
733
741
  runtime.persist_constants()
742
+ write_file(
743
+ runner_attribute_file,
744
+ "%s:%s" % (get_metadata(), "/".join((obj.flow.name, runtime.run_id))),
745
+ )
734
746
  runtime.execute()
735
747
 
736
748
 
737
- def write_run_id(run_id_file, run_id):
738
- if run_id_file is not None:
739
- with open(run_id_file, "w") as f:
740
- f.write(str(run_id))
749
+ def write_file(file_path, content):
750
+ if file_path is not None:
751
+ with open(file_path, "w") as f:
752
+ f.write(str(content))
741
753
 
742
754
 
743
755
  def before_run(obj, tags, decospecs):
@@ -23,6 +23,8 @@ def _check_stubs_supported():
23
23
  if _py_ver >= (3, 4):
24
24
  if _py_ver >= (3, 8):
25
25
  from importlib import metadata
26
+ elif _py_ver >= (3, 7):
27
+ from metaflow._vendor import importlib_metadata as metadata
26
28
  elif _py_ver >= (3, 6):
27
29
  from metaflow._vendor.v3_6 import importlib_metadata as metadata
28
30
  else:
@@ -262,6 +262,8 @@ if _py_ver >= (3, 4):
262
262
 
263
263
  if _py_ver >= (3, 8):
264
264
  from importlib import metadata
265
+ elif _py_ver >= (3, 7):
266
+ from metaflow._vendor import importlib_metadata as metadata
265
267
  elif _py_ver >= (3, 6):
266
268
  from metaflow._vendor.v3_6 import importlib_metadata as metadata
267
269
  else:
metaflow/parameters.py CHANGED
@@ -388,6 +388,7 @@ def add_custom_parameters(deploy_mode=False):
388
388
  # deploy_mode determines whether deploy-time functions should or should
389
389
  # not be evaluated for this command
390
390
  def wrapper(cmd):
391
+ cmd.has_flow_params = True
391
392
  # Iterate over parameters in reverse order so cmd.params lists options
392
393
  # in the order they are defined in the FlowSpec subclass
393
394
  for arg in parameters[::-1]:
@@ -88,15 +88,15 @@ class BatchDecorator(StepDecorator):
88
88
  Alias for inferentia. Use only one of the two.
89
89
  efa : int, default 0
90
90
  Number of elastic fabric adapter network devices to attach to container
91
- ephemeral_storage: int, default None
92
- The total amount, in GiB, of ephemeral storage to set for the task (21-200)
91
+ ephemeral_storage : int, default None
92
+ The total amount, in GiB, of ephemeral storage to set for the task, 21-200GiB.
93
93
  This is only relevant for Fargate compute environments
94
94
  log_driver: str, optional, default None
95
95
  The log driver to use for the Amazon ECS container.
96
96
  log_options: List[str], optional, default None
97
97
  List of strings containing options for the chosen log driver. The configurable values
98
98
  depend on the `log driver` chosen. Validation of these options is not supported yet.
99
- Example usage: ["awslogs-group:aws/batch/job"]
99
+ Example: [`awslogs-group:aws/batch/job`]
100
100
  """
101
101
 
102
102
  name = "batch"
@@ -275,11 +275,6 @@ class KubernetesJob(object):
275
275
  # (unique UID) per Metaflow task attempt.
276
276
  client = self._client.get()
277
277
 
278
- # tmpfs variables
279
- use_tmpfs = self._kwargs["use_tmpfs"]
280
- tmpfs_size = self._kwargs["tmpfs_size"]
281
- tmpfs_enabled = use_tmpfs or (tmpfs_size and not use_tmpfs)
282
-
283
278
  self._job = client.V1Job(
284
279
  api_version="batch/v1",
285
280
  kind="Job",
File without changes
@@ -0,0 +1,406 @@
1
+ import sys
2
+
3
+ if sys.version_info < (3, 7):
4
+ raise RuntimeError(
5
+ """
6
+ The Metaflow Programmatic API is not supported for versions of Python less than 3.7
7
+ """
8
+ )
9
+
10
+ import datetime
11
+ import importlib
12
+ import inspect
13
+ import itertools
14
+ import uuid
15
+ from collections import OrderedDict
16
+ from typing import Any, Callable, Dict, List, Optional
17
+ from typing import OrderedDict as TOrderedDict
18
+ from typing import Union
19
+
20
+ from metaflow import FlowSpec, Parameter
21
+ from metaflow._vendor import click
22
+ from metaflow._vendor.click.types import (
23
+ BoolParamType,
24
+ Choice,
25
+ DateTime,
26
+ File,
27
+ FloatParamType,
28
+ IntParamType,
29
+ Path,
30
+ StringParamType,
31
+ Tuple,
32
+ UUIDParameterType,
33
+ )
34
+ from metaflow._vendor.typeguard import TypeCheckError, check_type
35
+ from metaflow.cli import start
36
+ from metaflow.includefile import FilePathClass
37
+ from metaflow.parameters import JSONTypeClass
38
+
39
+ click_to_python_types = {
40
+ StringParamType: str,
41
+ IntParamType: int,
42
+ FloatParamType: float,
43
+ BoolParamType: bool,
44
+ UUIDParameterType: uuid.UUID,
45
+ Path: str,
46
+ DateTime: datetime.datetime,
47
+ Tuple: tuple,
48
+ Choice: str,
49
+ File: str,
50
+ JSONTypeClass: str,
51
+ FilePathClass: str,
52
+ }
53
+
54
+
55
+ def _method_sanity_check(
56
+ possible_arg_params: TOrderedDict[str, click.Argument],
57
+ possible_opt_params: TOrderedDict[str, click.Option],
58
+ annotations: TOrderedDict[str, Any],
59
+ defaults: TOrderedDict[str, Any],
60
+ **kwargs
61
+ ) -> Dict[str, Any]:
62
+ method_params = {"args": {}, "options": {}}
63
+
64
+ possible_params = OrderedDict()
65
+ possible_params.update(possible_arg_params)
66
+ possible_params.update(possible_opt_params)
67
+
68
+ # supplied kwargs
69
+ for supplied_k, supplied_v in kwargs.items():
70
+ if supplied_k not in possible_params:
71
+ raise ValueError(
72
+ "Unknown argument: '%s', possible args are: %s"
73
+ % (supplied_k, ", ".join(possible_params.keys()))
74
+ )
75
+
76
+ try:
77
+ check_type(supplied_v, annotations[supplied_k])
78
+ except TypeCheckError:
79
+ raise TypeError(
80
+ "Invalid type for '%s', expected: '%s', default is '%s'"
81
+ % (supplied_k, annotations[supplied_k], defaults[supplied_k])
82
+ )
83
+
84
+ if supplied_k in possible_arg_params:
85
+ cli_name = possible_arg_params[supplied_k].opts[0].strip("-")
86
+ method_params["args"][cli_name] = supplied_v
87
+ elif supplied_k in possible_opt_params:
88
+ if possible_opt_params[supplied_k].is_bool_flag:
89
+ # it is a boolean flag..
90
+ if supplied_v == True:
91
+ cli_name = possible_opt_params[supplied_k].opts[0].strip("-")
92
+ elif supplied_v == False:
93
+ if possible_opt_params[supplied_k].secondary_opts:
94
+ cli_name = (
95
+ possible_opt_params[supplied_k].secondary_opts[0].strip("-")
96
+ )
97
+ else:
98
+ continue
99
+ supplied_v = "flag"
100
+ else:
101
+ cli_name = possible_opt_params[supplied_k].opts[0].strip("-")
102
+ method_params["options"][cli_name] = supplied_v
103
+
104
+ # possible kwargs
105
+ for _, possible_v in possible_params.items():
106
+ cli_name = possible_v.opts[0].strip("-")
107
+ if (
108
+ (cli_name not in method_params["args"])
109
+ and (cli_name not in method_params["options"])
110
+ ) and possible_v.required:
111
+ raise ValueError("Missing argument: %s is required." % cli_name)
112
+
113
+ return method_params
114
+
115
+
116
+ def get_annotation(param: Union[click.Argument, click.Option]):
117
+ py_type = click_to_python_types[type(param.type)]
118
+ if not param.required:
119
+ if param.multiple or param.nargs == -1:
120
+ return Optional[List[py_type]]
121
+ else:
122
+ return Optional[py_type]
123
+ else:
124
+ if param.multiple or param.nargs == -1:
125
+ return List[py_type]
126
+ else:
127
+ return py_type
128
+
129
+
130
+ def get_inspect_param_obj(p: Union[click.Argument, click.Option], kind: str):
131
+ return inspect.Parameter(
132
+ name=p.name,
133
+ kind=kind,
134
+ default=p.default,
135
+ annotation=get_annotation(p),
136
+ )
137
+
138
+
139
+ # Cache to store already loaded modules
140
+ loaded_modules = {}
141
+
142
+
143
+ def extract_flowspec_params(flow_file: str) -> List[Parameter]:
144
+ # Check if the module has already been loaded
145
+ if flow_file in loaded_modules:
146
+ module = loaded_modules[flow_file]
147
+ else:
148
+ # Load the module if it's not already loaded
149
+ spec = importlib.util.spec_from_file_location("module", flow_file)
150
+ module = importlib.util.module_from_spec(spec)
151
+ spec.loader.exec_module(module)
152
+ # Cache the loaded module
153
+ loaded_modules[flow_file] = module
154
+ classes = inspect.getmembers(module, inspect.isclass)
155
+
156
+ parameters = []
157
+ for _, kls in classes:
158
+ if kls != FlowSpec and issubclass(kls, FlowSpec):
159
+ for _, obj in inspect.getmembers(kls):
160
+ if isinstance(obj, Parameter):
161
+ parameters.append(obj)
162
+
163
+ return parameters
164
+
165
+
166
+ class MetaflowAPI(object):
167
+ def __init__(self, parent=None, **kwargs):
168
+ self._parent = parent
169
+ self._chain = [{self._API_NAME: kwargs}]
170
+
171
+ @property
172
+ def parent(self):
173
+ if self._parent:
174
+ return self._parent
175
+ return None
176
+
177
+ @property
178
+ def chain(self):
179
+ return self._chain
180
+
181
+ @classmethod
182
+ def from_cli(cls, flow_file: str, cli_collection: Callable) -> Callable:
183
+ flow_parameters = extract_flowspec_params(flow_file)
184
+ class_dict = {"__module__": "metaflow", "_API_NAME": flow_file}
185
+ command_groups = cli_collection.sources
186
+ for each_group in command_groups:
187
+ for _, cmd_obj in each_group.commands.items():
188
+ if isinstance(cmd_obj, click.Group):
189
+ # TODO: possibly check for fake groups with cmd_obj.name in ["cli", "main"]
190
+ class_dict[cmd_obj.name] = extract_group(cmd_obj, flow_parameters)
191
+ elif isinstance(cmd_obj, click.Command):
192
+ class_dict[cmd_obj.name] = extract_command(cmd_obj, flow_parameters)
193
+ else:
194
+ raise RuntimeError(
195
+ "Cannot handle %s of type %s" % (cmd_obj.name, type(cmd_obj))
196
+ )
197
+
198
+ to_return = type(flow_file, (MetaflowAPI,), class_dict)
199
+ to_return.__name__ = flow_file
200
+
201
+ (
202
+ params_sigs,
203
+ possible_arg_params,
204
+ possible_opt_params,
205
+ annotations,
206
+ defaults,
207
+ ) = extract_all_params(cli_collection)
208
+
209
+ def _method(_self, **kwargs):
210
+ method_params = _method_sanity_check(
211
+ possible_arg_params,
212
+ possible_opt_params,
213
+ annotations,
214
+ defaults,
215
+ **kwargs,
216
+ )
217
+ return to_return(parent=None, **method_params)
218
+
219
+ m = _method
220
+ m.__name__ = cmd_obj.name
221
+ m.__doc__ = getattr(cmd_obj, "help", None)
222
+ m.__signature__ = inspect.signature(_method).replace(
223
+ parameters=params_sigs.values()
224
+ )
225
+ m.__annotations__ = annotations
226
+ m.__defaults__ = tuple(defaults.values())
227
+
228
+ return m
229
+
230
+ def execute(self) -> List[str]:
231
+ parents = []
232
+ current = self
233
+ while current.parent:
234
+ parents.append(current.parent)
235
+ current = current.parent
236
+
237
+ parents.reverse()
238
+
239
+ final_chain = list(itertools.chain.from_iterable([p.chain for p in parents]))
240
+ final_chain.extend(self.chain)
241
+
242
+ components = []
243
+ for each_cmd in final_chain:
244
+ for cmd, params in each_cmd.items():
245
+ components.append(cmd)
246
+ args = params.pop("args", {})
247
+ options = params.pop("options", {})
248
+
249
+ for _, v in args.items():
250
+ if isinstance(v, list):
251
+ for i in v:
252
+ components.append(i)
253
+ else:
254
+ components.append(v)
255
+ for k, v in options.items():
256
+ if isinstance(v, list):
257
+ for i in v:
258
+ components.append("--%s" % k)
259
+ components.append(str(i))
260
+ else:
261
+ components.append("--%s" % k)
262
+ if v != "flag":
263
+ components.append(str(v))
264
+
265
+ return components
266
+
267
+
268
+ def extract_all_params(cmd_obj: Union[click.Command, click.Group]):
269
+ arg_params_sigs = OrderedDict()
270
+ opt_params_sigs = OrderedDict()
271
+ params_sigs = OrderedDict()
272
+
273
+ arg_parameters = OrderedDict()
274
+ opt_parameters = OrderedDict()
275
+ annotations = OrderedDict()
276
+ defaults = OrderedDict()
277
+
278
+ for each_param in cmd_obj.params:
279
+ if isinstance(each_param, click.Argument):
280
+ arg_params_sigs[each_param.name] = get_inspect_param_obj(
281
+ each_param, inspect.Parameter.POSITIONAL_ONLY
282
+ )
283
+ arg_parameters[each_param.name] = each_param
284
+ elif isinstance(each_param, click.Option):
285
+ opt_params_sigs[each_param.name] = get_inspect_param_obj(
286
+ each_param, inspect.Parameter.KEYWORD_ONLY
287
+ )
288
+ opt_parameters[each_param.name] = each_param
289
+
290
+ annotations[each_param.name] = get_annotation(each_param)
291
+ defaults[each_param.name] = each_param.default
292
+
293
+ # first, fill in positional arguments
294
+ for name, each_arg_param in arg_params_sigs.items():
295
+ params_sigs[name] = each_arg_param
296
+ # then, fill in keyword arguments
297
+ for name, each_opt_param in opt_params_sigs.items():
298
+ params_sigs[name] = each_opt_param
299
+
300
+ return params_sigs, arg_parameters, opt_parameters, annotations, defaults
301
+
302
+
303
+ def extract_group(cmd_obj: click.Group, flow_parameters: List[Parameter]) -> Callable:
304
+ class_dict = {"__module__": "metaflow", "_API_NAME": cmd_obj.name}
305
+ for _, sub_cmd_obj in cmd_obj.commands.items():
306
+ if isinstance(sub_cmd_obj, click.Group):
307
+ # recursion
308
+ class_dict[sub_cmd_obj.name] = extract_group(sub_cmd_obj, flow_parameters)
309
+ elif isinstance(sub_cmd_obj, click.Command):
310
+ class_dict[sub_cmd_obj.name] = extract_command(sub_cmd_obj, flow_parameters)
311
+ else:
312
+ raise RuntimeError(
313
+ "Cannot handle %s of type %s" % (sub_cmd_obj.name, type(sub_cmd_obj))
314
+ )
315
+
316
+ resulting_class = type(cmd_obj.name, (MetaflowAPI,), class_dict)
317
+ resulting_class.__name__ = cmd_obj.name
318
+
319
+ (
320
+ params_sigs,
321
+ possible_arg_params,
322
+ possible_opt_params,
323
+ annotations,
324
+ defaults,
325
+ ) = extract_all_params(cmd_obj)
326
+
327
+ def _method(_self, **kwargs):
328
+ method_params = _method_sanity_check(
329
+ possible_arg_params, possible_opt_params, annotations, defaults, **kwargs
330
+ )
331
+ return resulting_class(parent=_self, **method_params)
332
+
333
+ m = _method
334
+ m.__name__ = cmd_obj.name
335
+ m.__doc__ = getattr(cmd_obj, "help", None)
336
+ m.__signature__ = inspect.signature(_method).replace(
337
+ parameters=params_sigs.values()
338
+ )
339
+ m.__annotations__ = annotations
340
+ m.__defaults__ = tuple(defaults.values())
341
+
342
+ return m
343
+
344
+
345
+ def extract_command(
346
+ cmd_obj: click.Command, flow_parameters: List[Parameter]
347
+ ) -> Callable:
348
+ if getattr(cmd_obj, "has_flow_params", False):
349
+ for p in flow_parameters[::-1]:
350
+ cmd_obj.params.insert(0, click.Option(("--" + p.name,), **p.kwargs))
351
+
352
+ (
353
+ params_sigs,
354
+ possible_arg_params,
355
+ possible_opt_params,
356
+ annotations,
357
+ defaults,
358
+ ) = extract_all_params(cmd_obj)
359
+
360
+ def _method(_self, **kwargs):
361
+ method_params = _method_sanity_check(
362
+ possible_arg_params, possible_opt_params, annotations, defaults, **kwargs
363
+ )
364
+ _self._chain.append({cmd_obj.name: method_params})
365
+ return _self.execute()
366
+
367
+ m = _method
368
+ m.__name__ = cmd_obj.name
369
+ m.__doc__ = getattr(cmd_obj, "help", None)
370
+ m.__signature__ = inspect.signature(_method).replace(
371
+ parameters=params_sigs.values()
372
+ )
373
+ m.__annotations__ = annotations
374
+ m.__defaults__ = tuple(defaults.values())
375
+
376
+ return m
377
+
378
+
379
+ if __name__ == "__main__":
380
+ api = MetaflowAPI.from_cli("../try.py", start)
381
+
382
+ command = api(metadata="local").run(
383
+ tags=["abc", "def"],
384
+ decospecs=["kubernetes"],
385
+ max_workers=5,
386
+ alpha=3,
387
+ myfile="path/to/file",
388
+ )
389
+ print(" ".join(command))
390
+
391
+ command = (
392
+ api(metadata="local")
393
+ .kubernetes()
394
+ .step(
395
+ step_name="process",
396
+ code_package_sha="some_sha",
397
+ code_package_url="some_url",
398
+ )
399
+ )
400
+ print(" ".join(command))
401
+
402
+ command = api().tag().add(tags=["abc", "def"])
403
+ print(" ".join(command))
404
+
405
+ command = getattr(api(decospecs=["retry"]), "argo-workflows")().create()
406
+ print(" ".join(command))