ob-metaflow 2.9.10.1__py2.py3-none-any.whl → 2.10.2.6__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 might be problematic. Click here for more details.

Files changed (57) hide show
  1. metaflow/_vendor/packaging/__init__.py +15 -0
  2. metaflow/_vendor/packaging/_elffile.py +108 -0
  3. metaflow/_vendor/packaging/_manylinux.py +238 -0
  4. metaflow/_vendor/packaging/_musllinux.py +80 -0
  5. metaflow/_vendor/packaging/_parser.py +328 -0
  6. metaflow/_vendor/packaging/_structures.py +61 -0
  7. metaflow/_vendor/packaging/_tokenizer.py +188 -0
  8. metaflow/_vendor/packaging/markers.py +245 -0
  9. metaflow/_vendor/packaging/requirements.py +95 -0
  10. metaflow/_vendor/packaging/specifiers.py +1005 -0
  11. metaflow/_vendor/packaging/tags.py +546 -0
  12. metaflow/_vendor/packaging/utils.py +141 -0
  13. metaflow/_vendor/packaging/version.py +563 -0
  14. metaflow/_vendor/v3_7/__init__.py +1 -0
  15. metaflow/_vendor/v3_7/zipp.py +329 -0
  16. metaflow/metaflow_config.py +2 -1
  17. metaflow/metaflow_environment.py +3 -1
  18. metaflow/mflog/mflog.py +7 -1
  19. metaflow/multicore_utils.py +12 -2
  20. metaflow/plugins/__init__.py +8 -3
  21. metaflow/plugins/airflow/airflow.py +13 -0
  22. metaflow/plugins/argo/argo_client.py +16 -0
  23. metaflow/plugins/argo/argo_events.py +7 -1
  24. metaflow/plugins/argo/argo_workflows.py +62 -0
  25. metaflow/plugins/argo/argo_workflows_cli.py +15 -0
  26. metaflow/plugins/aws/batch/batch.py +10 -0
  27. metaflow/plugins/aws/batch/batch_cli.py +1 -2
  28. metaflow/plugins/aws/batch/batch_decorator.py +2 -9
  29. metaflow/plugins/datatools/s3/s3.py +4 -0
  30. metaflow/plugins/env_escape/client.py +24 -3
  31. metaflow/plugins/env_escape/stub.py +2 -8
  32. metaflow/plugins/kubernetes/kubernetes.py +13 -0
  33. metaflow/plugins/kubernetes/kubernetes_cli.py +1 -2
  34. metaflow/plugins/kubernetes/kubernetes_decorator.py +9 -2
  35. metaflow/plugins/pypi/__init__.py +29 -0
  36. metaflow/plugins/pypi/bootstrap.py +131 -0
  37. metaflow/plugins/pypi/conda_decorator.py +335 -0
  38. metaflow/plugins/pypi/conda_environment.py +414 -0
  39. metaflow/plugins/pypi/micromamba.py +294 -0
  40. metaflow/plugins/pypi/pip.py +205 -0
  41. metaflow/plugins/pypi/pypi_decorator.py +130 -0
  42. metaflow/plugins/pypi/pypi_environment.py +7 -0
  43. metaflow/plugins/pypi/utils.py +75 -0
  44. metaflow/task.py +0 -3
  45. metaflow/vendor.py +1 -0
  46. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/METADATA +1 -1
  47. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/RECORD +51 -33
  48. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/WHEEL +1 -1
  49. metaflow/plugins/conda/__init__.py +0 -90
  50. metaflow/plugins/conda/batch_bootstrap.py +0 -104
  51. metaflow/plugins/conda/conda.py +0 -247
  52. metaflow/plugins/conda/conda_environment.py +0 -136
  53. metaflow/plugins/conda/conda_flow_decorator.py +0 -35
  54. metaflow/plugins/conda/conda_step_decorator.py +0 -416
  55. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/LICENSE +0 -0
  56. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/entry_points.txt +0 -0
  57. {ob_metaflow-2.9.10.1.dist-info → ob_metaflow-2.10.2.6.dist-info}/top_level.txt +0 -0
@@ -1,247 +0,0 @@
1
- import errno
2
- import os
3
- import json
4
- import subprocess
5
- import time
6
- from distutils.version import LooseVersion
7
-
8
- from metaflow.exception import MetaflowException
9
- from metaflow.metaflow_config import CONDA_DEPENDENCY_RESOLVER
10
- from metaflow.metaflow_environment import InvalidEnvironmentException
11
- from metaflow.util import which
12
-
13
-
14
- class CondaException(MetaflowException):
15
- headline = "Conda ran into an error while setting up environment."
16
-
17
- def __init__(self, error):
18
- if isinstance(error, (list,)):
19
- error = "\n".join(error)
20
- msg = "{error}".format(error=error)
21
- super(CondaException, self).__init__(msg)
22
-
23
-
24
- class CondaStepException(CondaException):
25
- def __init__(self, exception, step):
26
- msg = "Step: {step}, Error: {error}".format(step=step, error=exception.message)
27
- super(CondaStepException, self).__init__(msg)
28
-
29
-
30
- class Conda(object):
31
- def __init__(self):
32
- dependency_solver = CONDA_DEPENDENCY_RESOLVER.lower()
33
- self._bin = which(dependency_solver)
34
- # Check if the dependency solver exists.
35
- if self._bin is None:
36
- raise InvalidEnvironmentException(
37
- "No %s installation found. Install %s first."
38
- % (dependency_solver, dependency_solver)
39
- )
40
- # Check for a minimum version for conda when conda or mamba is used
41
- # for dependency resolution.
42
- if dependency_solver == "conda" or dependency_solver == "mamba":
43
- if LooseVersion(self._info()["conda_version"]) < LooseVersion("4.6.0"):
44
- msg = "Conda version 4.6.0 or newer is required."
45
- if dependency_solver == "mamba":
46
- msg += " Visit https://mamba.readthedocs.io/en/latest/installation.html for installation instructions."
47
- else:
48
- msg += " Visit https://docs.conda.io/en/latest/miniconda.html for installation instructions."
49
- raise InvalidEnvironmentException(msg)
50
- # Check if conda-forge is available as a channel to pick up Metaflow's
51
- # dependencies. This check will go away once all of Metaflow's
52
- # dependencies are vendored in.
53
- if "conda-forge" not in "\t".join(self._info()["channels"]):
54
- raise InvalidEnvironmentException(
55
- "Conda channel 'conda-forge' is required. Specify it with CONDA_CHANNELS environment variable."
56
- )
57
-
58
- def create(
59
- self,
60
- step_name,
61
- env_id,
62
- deps,
63
- architecture=None,
64
- explicit=False,
65
- disable_safety_checks=False,
66
- ):
67
- # Create the conda environment
68
- try:
69
- with CondaLock(self._env_lock_file(env_id)):
70
- self._remove(env_id)
71
- self._create(
72
- env_id, deps, explicit, architecture, disable_safety_checks
73
- )
74
- return self._deps(env_id)
75
- except CondaException as e:
76
- raise CondaStepException(e, step_name)
77
-
78
- def remove(self, step_name, env_id):
79
- # Remove the conda environment
80
- try:
81
- with CondaLock(self._env_lock_file(env_id)):
82
- self._remove(env_id)
83
- except CondaException as e:
84
- raise CondaStepException(e, step_name)
85
-
86
- def python(self, env_id):
87
- # Get Python interpreter for the conda environment
88
- return os.path.join(self._env_path(env_id), "bin/python")
89
-
90
- def environments(self, flow):
91
- # List all conda environments associated with the flow
92
- envs = self._info()["envs"]
93
- ret = {}
94
- for env in envs:
95
- name = os.path.basename(env)
96
- if name.startswith("metaflow_%s" % flow):
97
- ret[name] = env
98
- return ret
99
-
100
- def package_info(self, env_id):
101
- # Show conda environment package configuration
102
- # Not every parameter is exposed via conda cli hence this ignominy
103
- metadata = os.path.join(self._env_path(env_id), "conda-meta")
104
- for path, dirs, files in os.walk(metadata):
105
- for file in files:
106
- if file.endswith(".json"):
107
- with open(os.path.join(path, file)) as f:
108
- yield json.loads(f.read())
109
-
110
- def _info(self):
111
- return json.loads(self._call_conda(["info"]))
112
-
113
- def _create(
114
- self,
115
- env_id,
116
- deps,
117
- explicit=False,
118
- architecture=None,
119
- disable_safety_checks=False,
120
- ):
121
- cmd = ["create", "--yes", "--no-default-packages", "--name", env_id, "--quiet"]
122
- if explicit:
123
- cmd.append("--no-deps")
124
- cmd.extend(deps)
125
- self._call_conda(
126
- cmd, architecture=architecture, disable_safety_checks=disable_safety_checks
127
- )
128
-
129
- def _remove(self, env_id):
130
- self._call_conda(["env", "remove", "--name", env_id, "--yes", "--quiet"])
131
-
132
- def _install(self, env_id, deps, explicit=False):
133
- cmd = ["install", "--yes", "--name", env_id, "--quiet"]
134
- if explicit:
135
- cmd.append("--no-deps")
136
- cmd.extend(deps)
137
- self._call_conda(cmd)
138
-
139
- def _install_order(self, env_id):
140
- cmd = ["list", "--name", env_id, "--explicit"]
141
- response = self._call_conda(cmd).decode("utf-8")
142
- emit = False
143
- result = []
144
- for line in response.splitlines():
145
- if emit:
146
- result.append(line.split("/")[-1])
147
- if not emit and line == "@EXPLICIT":
148
- emit = True
149
- return result
150
-
151
- def _deps(self, env_id):
152
- exact_deps = []
153
- urls = []
154
- for package in self.package_info(env_id):
155
- exact_deps.append(
156
- "%s=%s=%s" % (package["name"], package["version"], package["build"])
157
- )
158
- urls.append(package["url"])
159
- order = self._install_order(env_id)
160
- return (exact_deps, urls, order)
161
-
162
- def _env_path(self, env_id):
163
- envs = self._info()["envs"]
164
- for env in envs:
165
- name = os.path.basename(env)
166
- if name == env_id:
167
- return env
168
- return None
169
-
170
- def _env_lock_file(self, env_id):
171
- return os.path.join(self._info()["envs_dirs"][0], "mf_env-creation.lock")
172
-
173
- def _call_conda(self, args, architecture=None, disable_safety_checks=False):
174
- try:
175
- env = {
176
- "CONDA_JSON": "True",
177
- "CONDA_SUBDIR": (architecture if architecture else ""),
178
- "MAMBA_NO_BANNER": "1",
179
- "MAMBA_JSON": "True",
180
- }
181
- if disable_safety_checks:
182
- env["CONDA_SAFETY_CHECKS"] = "disabled"
183
- return subprocess.check_output(
184
- [self._bin] + args, stderr=subprocess.PIPE, env=dict(os.environ, **env)
185
- ).strip()
186
- except subprocess.CalledProcessError as e:
187
- try:
188
- output = json.loads(e.output)
189
- err = [output["error"]]
190
- for error in output.get("errors", []):
191
- err.append(error["error"])
192
- raise CondaException(err)
193
- except (TypeError, ValueError) as ve:
194
- pass
195
- raise CondaException(
196
- "command '{cmd}' returned error ({code}): {output}, stderr={stderr}".format(
197
- cmd=e.cmd, code=e.returncode, output=e.output, stderr=e.stderr
198
- )
199
- )
200
-
201
-
202
- class CondaLock(object):
203
- def __init__(self, lock, timeout=3600, delay=10):
204
- self.lock = lock
205
- self.locked = False
206
- self.timeout = timeout
207
- self.delay = delay
208
-
209
- def _acquire(self):
210
- start = time.time()
211
- try:
212
- os.makedirs(os.path.dirname(self.lock))
213
- except OSError as x:
214
- if x.errno != errno.EEXIST:
215
- raise
216
- while True:
217
- try:
218
- self.fd = os.open(self.lock, os.O_CREAT | os.O_EXCL | os.O_RDWR)
219
- self.locked = True
220
- break
221
- except OSError as e:
222
- if e.errno != errno.EEXIST:
223
- raise
224
- if self.timeout is None:
225
- raise CondaException("Could not acquire lock {}".format(self.lock))
226
- if (time.time() - start) >= self.timeout:
227
- raise CondaException(
228
- "Timeout occurred while acquiring lock {}".format(self.lock)
229
- )
230
- time.sleep(self.delay)
231
-
232
- def _release(self):
233
- if self.locked:
234
- os.close(self.fd)
235
- os.unlink(self.lock)
236
- self.locked = False
237
-
238
- def __enter__(self):
239
- if not self.locked:
240
- self._acquire()
241
- return self
242
-
243
- def __exit__(self, type, value, traceback):
244
- self.__del__()
245
-
246
- def __del__(self):
247
- self._release()
@@ -1,136 +0,0 @@
1
- import json
2
- import os
3
- import sys
4
- import tarfile
5
-
6
- from io import BytesIO
7
-
8
- from metaflow.metaflow_environment import MetaflowEnvironment
9
- from metaflow.exception import MetaflowException
10
- from metaflow.mflog import BASH_SAVE_LOGS
11
-
12
- from .conda import Conda
13
- from . import get_conda_manifest_path, CONDA_MAGIC_FILE
14
-
15
-
16
- class CondaEnvironment(MetaflowEnvironment):
17
- TYPE = "conda"
18
- _filecache = None
19
-
20
- def __init__(self, flow):
21
- self.flow = flow
22
- self.local_root = None
23
- # A conda environment sits on top of whatever default environment
24
- # the user has, so we get that environment to be able to forward
25
- # any calls we don't handle specifically to that one.
26
- from ...plugins import ENVIRONMENTS
27
- from metaflow.metaflow_config import DEFAULT_ENVIRONMENT
28
-
29
- if DEFAULT_ENVIRONMENT == self.TYPE:
30
- # If the default environment is Conda itself then fallback on
31
- # the default 'default environment'
32
- self.base_env = MetaflowEnvironment(self.flow)
33
- else:
34
- self.base_env = [
35
- e
36
- for e in ENVIRONMENTS + [MetaflowEnvironment]
37
- if e.TYPE == DEFAULT_ENVIRONMENT
38
- ][0](self.flow)
39
-
40
- def init_environment(self, echo):
41
- # Print a message for now
42
- echo("Bootstrapping conda environment..." + "(this could take a few minutes)")
43
- self.base_env.init_environment(echo)
44
-
45
- def validate_environment(self, echo, datastore_type):
46
- return self.base_env.validate_environment(echo, datastore_type)
47
-
48
- def decospecs(self):
49
- # Apply conda decorator and base environment's decorators to all steps
50
- return ("conda",) + self.base_env.decospecs()
51
-
52
- def _get_conda_decorator(self, step_name):
53
- step = next(step for step in self.flow if step.name == step_name)
54
- decorator = next(deco for deco in step.decorators if deco.name == "conda")
55
- # Guaranteed to have a conda decorator because of self.decospecs()
56
- return decorator
57
-
58
- def _get_env_id(self, step_name):
59
- conda_decorator = self._get_conda_decorator(step_name)
60
- if conda_decorator.is_enabled():
61
- return conda_decorator._env_id()
62
- return None
63
-
64
- def _get_executable(self, step_name):
65
- env_id = self._get_env_id(step_name)
66
- if env_id is not None:
67
- return os.path.join(env_id, "bin/python -s")
68
- return None
69
-
70
- def set_local_root(self, ds_root):
71
- self.local_root = ds_root
72
-
73
- def bootstrap_commands(self, step_name, datastore_type):
74
- # Bootstrap conda and execution environment for step
75
- env_id = self._get_env_id(step_name)
76
- if env_id is not None:
77
- return [
78
- "echo 'Bootstrapping environment...'",
79
- 'python -m metaflow.plugins.conda.batch_bootstrap "%s" %s "%s"'
80
- % (self.flow.name, env_id, datastore_type),
81
- "echo 'Environment bootstrapped.'",
82
- ]
83
- return []
84
-
85
- def add_to_package(self):
86
- files = self.base_env.add_to_package()
87
- # Add conda manifest file to job package at the top level.
88
- path = get_conda_manifest_path(self.local_root, self.flow.name)
89
- if os.path.exists(path):
90
- files.append((path, os.path.basename(path)))
91
- return files
92
-
93
- def pylint_config(self):
94
- config = self.base_env.pylint_config()
95
- # Disable (import-error) in pylint
96
- config.append("--disable=F0401")
97
- return config
98
-
99
- def executable(self, step_name):
100
- # Get relevant python interpreter for step
101
- executable = self._get_executable(step_name)
102
- if executable is not None:
103
- return executable
104
- return self.base_env.executable(step_name)
105
-
106
- @classmethod
107
- def get_client_info(cls, flow_name, metadata):
108
- if cls._filecache is None:
109
- from metaflow.client.filecache import FileCache
110
-
111
- cls._filecache = FileCache()
112
- info = metadata.get("code-package")
113
- env_id = metadata.get("conda_env_id")
114
- if info is None or env_id is None:
115
- return {"type": "conda"}
116
- info = json.loads(info)
117
- _, blobdata = cls._filecache.get_data(
118
- info["ds_type"], flow_name, info["location"], info["sha"]
119
- )
120
- with tarfile.open(fileobj=BytesIO(blobdata), mode="r:gz") as tar:
121
- conda_file = tar.extractfile(CONDA_MAGIC_FILE)
122
- if conda_file is None:
123
- return {"type": "conda"}
124
- info = json.loads(conda_file.read().decode("utf-8"))
125
- new_info = {
126
- "type": "conda",
127
- "explicit": info[env_id]["explicit"],
128
- "deps": info[env_id]["deps"],
129
- }
130
- return new_info
131
-
132
- def get_package_commands(self, code_package_url, datastore_type):
133
- return self.base_env.get_package_commands(code_package_url, datastore_type)
134
-
135
- def get_environment_info(self, include_ext_info=False):
136
- return self.base_env.get_environment_info(include_ext_info)
@@ -1,35 +0,0 @@
1
- from metaflow.decorators import FlowDecorator
2
- from metaflow.metaflow_environment import InvalidEnvironmentException
3
-
4
- from typing import Dict
5
-
6
-
7
- class CondaFlowDecorator(FlowDecorator):
8
- """
9
- Specifies the Conda environment for all steps of the flow.
10
-
11
- Use `@conda_base` to set common libraries required by all
12
- steps and use `@conda` to specify step-specific additions.
13
-
14
- Parameters
15
- ----------
16
- libraries : Dict[str, str], default: {}
17
- Libraries to use for this flow. The key is the name of the package
18
- and the value is the version to use.
19
- python : str, optional
20
- Version of Python to use, e.g. '3.7.4'. A default value of None means
21
- to use the current Python version.
22
- disabled : bool, default: False
23
- If set to True, disables Conda.
24
- """
25
-
26
- name = "conda_base"
27
- defaults = {"libraries": {}, "python": None, "disabled": None}
28
-
29
- def flow_init(
30
- self, flow, graph, environment, flow_datastore, metadata, logger, echo, options
31
- ):
32
- if environment.TYPE != "conda":
33
- raise InvalidEnvironmentException(
34
- "The *@conda* decorator requires " "--environment=conda"
35
- )