metaflow 2.12.7__py2.py3-none-any.whl → 2.12.9__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 (40) hide show
  1. metaflow/__init__.py +2 -0
  2. metaflow/cli.py +12 -4
  3. metaflow/extension_support/plugins.py +1 -0
  4. metaflow/flowspec.py +8 -1
  5. metaflow/lint.py +13 -0
  6. metaflow/metaflow_current.py +0 -8
  7. metaflow/plugins/__init__.py +12 -0
  8. metaflow/plugins/argo/argo_workflows.py +462 -42
  9. metaflow/plugins/argo/argo_workflows_cli.py +60 -3
  10. metaflow/plugins/argo/argo_workflows_decorator.py +38 -7
  11. metaflow/plugins/argo/argo_workflows_deployer.py +290 -0
  12. metaflow/plugins/argo/jobset_input_paths.py +16 -0
  13. metaflow/plugins/aws/batch/batch_decorator.py +16 -13
  14. metaflow/plugins/aws/step_functions/step_functions_cli.py +45 -3
  15. metaflow/plugins/aws/step_functions/step_functions_deployer.py +251 -0
  16. metaflow/plugins/cards/card_cli.py +1 -1
  17. metaflow/plugins/kubernetes/kubernetes.py +279 -52
  18. metaflow/plugins/kubernetes/kubernetes_cli.py +26 -8
  19. metaflow/plugins/kubernetes/kubernetes_client.py +0 -1
  20. metaflow/plugins/kubernetes/kubernetes_decorator.py +56 -44
  21. metaflow/plugins/kubernetes/kubernetes_job.py +6 -6
  22. metaflow/plugins/kubernetes/kubernetes_jobsets.py +510 -272
  23. metaflow/plugins/parallel_decorator.py +108 -8
  24. metaflow/plugins/pypi/bootstrap.py +1 -1
  25. metaflow/plugins/pypi/micromamba.py +1 -1
  26. metaflow/plugins/secrets/secrets_decorator.py +12 -3
  27. metaflow/plugins/test_unbounded_foreach_decorator.py +39 -4
  28. metaflow/runner/deployer.py +386 -0
  29. metaflow/runner/metaflow_runner.py +1 -20
  30. metaflow/runner/nbdeploy.py +130 -0
  31. metaflow/runner/nbrun.py +4 -28
  32. metaflow/runner/utils.py +49 -0
  33. metaflow/runtime.py +246 -134
  34. metaflow/version.py +1 -1
  35. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/METADATA +2 -2
  36. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/RECORD +40 -34
  37. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/WHEEL +1 -1
  38. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/LICENSE +0 -0
  39. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/entry_points.txt +0 -0
  40. {metaflow-2.12.7.dist-info → metaflow-2.12.9.dist-info}/top_level.txt +0 -0
@@ -2,33 +2,14 @@ import importlib
2
2
  import os
3
3
  import sys
4
4
  import tempfile
5
- import time
6
5
  from typing import Dict, Iterator, Optional, Tuple
7
6
 
8
7
  from metaflow import Run, metadata
9
8
 
9
+ from .utils import clear_and_set_os_environ, read_from_file_when_ready
10
10
  from .subprocess_manager import CommandManager, SubprocessManager
11
11
 
12
12
 
13
- def clear_and_set_os_environ(env: Dict):
14
- os.environ.clear()
15
- os.environ.update(env)
16
-
17
-
18
- def read_from_file_when_ready(file_path: str, timeout: float = 5):
19
- start_time = time.time()
20
- with open(file_path, "r", encoding="utf-8") as file_pointer:
21
- content = file_pointer.read()
22
- while not content:
23
- if time.time() - start_time > timeout:
24
- raise TimeoutError(
25
- "Timeout while waiting for file content from '%s'" % file_path
26
- )
27
- time.sleep(0.1)
28
- content = file_pointer.read()
29
- return content
30
-
31
-
32
13
  class ExecutingRun(object):
33
14
  """
34
15
  This class contains a reference to a `metaflow.Run` object representing
@@ -0,0 +1,130 @@
1
+ import os
2
+ import tempfile
3
+ from typing import Dict, Optional
4
+
5
+ from metaflow import Deployer
6
+ from metaflow.runner.utils import get_current_cell, format_flowfile
7
+
8
+ DEFAULT_DIR = tempfile.gettempdir()
9
+
10
+
11
+ class NBDeployerInitializationError(Exception):
12
+ """Custom exception for errors during NBDeployer initialization."""
13
+
14
+ pass
15
+
16
+
17
+ class NBDeployer(object):
18
+ """
19
+ A wrapper over `Deployer` for deploying flows defined in a Jupyter
20
+ notebook cell.
21
+
22
+ Instantiate this class on the last line of a notebook cell where
23
+ a `flow` is defined. In contrast to `Deployer`, this class is not
24
+ meant to be used in a context manager.
25
+
26
+ ```python
27
+ deployer = NBDeployer(FlowName)
28
+ ar = deployer.argo_workflows(name="madhur")
29
+ ar_obj = ar.create()
30
+ result = ar_obj.trigger(alpha=300)
31
+ print(result.status)
32
+ print(result.run)
33
+ result.terminate()
34
+ ```
35
+
36
+ Parameters
37
+ ----------
38
+ flow : FlowSpec
39
+ Flow defined in the same cell
40
+ show_output : bool, default True
41
+ Show the 'stdout' and 'stderr' to the console by default,
42
+ profile : Optional[str], default None
43
+ Metaflow profile to use to deploy this run. If not specified, the default
44
+ profile is used (or the one already set using `METAFLOW_PROFILE`)
45
+ env : Optional[Dict[str, str]], default None
46
+ Additional environment variables to set. This overrides the
47
+ environment set for this process.
48
+ base_dir : Optional[str], default None
49
+ The directory to run the subprocess in; if not specified, a temporary
50
+ directory is used.
51
+ **kwargs : Any
52
+ Additional arguments that you would pass to `python myflow.py` i.e. options
53
+ listed in `python myflow.py --help`
54
+
55
+ """
56
+
57
+ def __init__(
58
+ self,
59
+ flow,
60
+ show_output: bool = True,
61
+ profile: Optional[str] = None,
62
+ env: Optional[Dict] = None,
63
+ base_dir: str = DEFAULT_DIR,
64
+ **kwargs,
65
+ ):
66
+ try:
67
+ from IPython import get_ipython
68
+
69
+ ipython = get_ipython()
70
+ except ModuleNotFoundError:
71
+ raise NBDeployerInitializationError(
72
+ "'NBDeployer' requires an interactive Python environment (such as Jupyter)"
73
+ )
74
+
75
+ self.cell = get_current_cell(ipython)
76
+ self.flow = flow
77
+ self.show_output = show_output
78
+ self.profile = profile
79
+ self.env = env
80
+ self.cwd = base_dir
81
+ self.top_level_kwargs = kwargs
82
+
83
+ self.env_vars = os.environ.copy()
84
+ self.env_vars.update(env or {})
85
+ # clears the Jupyter parent process ID environment variable
86
+ # prevents server from interfering with Metaflow
87
+ self.env_vars.update({"JPY_PARENT_PID": ""})
88
+
89
+ if self.profile:
90
+ self.env_vars["METAFLOW_PROFILE"] = self.profile
91
+
92
+ if not self.cell:
93
+ raise ValueError("Couldn't find a cell.")
94
+
95
+ self.tmp_flow_file = tempfile.NamedTemporaryFile(
96
+ prefix=self.flow.__name__,
97
+ suffix=".py",
98
+ mode="w",
99
+ dir=self.cwd,
100
+ delete=False,
101
+ )
102
+
103
+ self.tmp_flow_file.write(format_flowfile(self.cell))
104
+ self.tmp_flow_file.flush()
105
+ self.tmp_flow_file.close()
106
+
107
+ self.flow_file = self.tmp_flow_file.name
108
+
109
+ self.deployer = Deployer(
110
+ flow_file=self.flow_file,
111
+ show_output=self.show_output,
112
+ profile=self.profile,
113
+ env=self.env_vars,
114
+ cwd=self.cwd,
115
+ **kwargs,
116
+ )
117
+
118
+ from metaflow.plugins import DEPLOYER_IMPL_PROVIDERS
119
+
120
+ for provider_class in DEPLOYER_IMPL_PROVIDERS:
121
+ method_name = provider_class.TYPE.replace("-", "_")
122
+ setattr(
123
+ NBDeployer, method_name, self.deployer.__make_function(provider_class)
124
+ )
125
+
126
+ def cleanup(self):
127
+ """
128
+ Delete any temporary files created during execution.
129
+ """
130
+ os.remove(self.flow_file)
metaflow/runner/nbrun.py CHANGED
@@ -1,9 +1,9 @@
1
- import ast
2
1
  import os
3
2
  import tempfile
4
3
  from typing import Dict, Optional
5
4
 
6
5
  from metaflow import Runner
6
+ from metaflow.runner.utils import get_current_cell, format_flowfile
7
7
 
8
8
  DEFAULT_DIR = tempfile.gettempdir()
9
9
 
@@ -14,32 +14,6 @@ class NBRunnerInitializationError(Exception):
14
14
  pass
15
15
 
16
16
 
17
- def get_current_cell(ipython):
18
- if ipython:
19
- return ipython.history_manager.input_hist_raw[-1]
20
- return None
21
-
22
-
23
- def format_flowfile(cell):
24
- """
25
- Formats the given cell content to create a valid Python script that can be executed as a Metaflow flow.
26
- """
27
- flowspec = [
28
- x
29
- for x in ast.parse(cell).body
30
- if isinstance(x, ast.ClassDef) and any(b.id == "FlowSpec" for b in x.bases)
31
- ]
32
-
33
- if not flowspec:
34
- raise ModuleNotFoundError(
35
- "The cell doesn't contain any class that inherits from 'FlowSpec'"
36
- )
37
-
38
- lines = cell.splitlines()[: flowspec[0].end_lineno]
39
- lines += ["if __name__ == '__main__':", f" {flowspec[0].name}()"]
40
- return "\n".join(lines)
41
-
42
-
43
17
  class NBRunner(object):
44
18
  """
45
19
  A wrapper over `Runner` for executing flows defined in a Jupyter
@@ -47,7 +21,7 @@ class NBRunner(object):
47
21
 
48
22
  Instantiate this class on the last line of a notebook cell where
49
23
  a `flow` is defined. In contrast to `Runner`, this class is not
50
- meant to be used a context manager. Instead, use a blocking helper
24
+ meant to be used in a context manager. Instead, use a blocking helper
51
25
  function like `nbrun` (which calls `cleanup()` internally) or call
52
26
  `cleanup()` explictly when using non-blocking APIs.
53
27
 
@@ -101,6 +75,8 @@ class NBRunner(object):
101
75
 
102
76
  self.env_vars = os.environ.copy()
103
77
  self.env_vars.update(env or {})
78
+ # clears the Jupyter parent process ID environment variable
79
+ # prevents server from interfering with Metaflow
104
80
  self.env_vars.update({"JPY_PARENT_PID": ""})
105
81
  if profile:
106
82
  self.env_vars["METAFLOW_PROFILE"] = profile
@@ -0,0 +1,49 @@
1
+ import os
2
+ import ast
3
+ import time
4
+ from typing import Dict
5
+
6
+
7
+ def get_current_cell(ipython):
8
+ if ipython:
9
+ return ipython.history_manager.input_hist_raw[-1]
10
+ return None
11
+
12
+
13
+ def format_flowfile(cell):
14
+ """
15
+ Formats the given cell content to create a valid Python script that can be executed as a Metaflow flow.
16
+ """
17
+ flowspec = [
18
+ x
19
+ for x in ast.parse(cell).body
20
+ if isinstance(x, ast.ClassDef) and any(b.id == "FlowSpec" for b in x.bases)
21
+ ]
22
+
23
+ if not flowspec:
24
+ raise ModuleNotFoundError(
25
+ "The cell doesn't contain any class that inherits from 'FlowSpec'"
26
+ )
27
+
28
+ lines = cell.splitlines()[: flowspec[0].end_lineno]
29
+ lines += ["if __name__ == '__main__':", f" {flowspec[0].name}()"]
30
+ return "\n".join(lines)
31
+
32
+
33
+ def clear_and_set_os_environ(env: Dict):
34
+ os.environ.clear()
35
+ os.environ.update(env)
36
+
37
+
38
+ def read_from_file_when_ready(file_path: str, timeout: float = 5):
39
+ start_time = time.time()
40
+ with open(file_path, "r", encoding="utf-8") as file_pointer:
41
+ content = file_pointer.read()
42
+ while not content:
43
+ if time.time() - start_time > timeout:
44
+ raise TimeoutError(
45
+ "Timeout while waiting for file content from '%s'" % file_path
46
+ )
47
+ time.sleep(0.1)
48
+ content = file_pointer.read()
49
+ return content