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,416 +0,0 @@
1
- import importlib
2
- import json
3
- import os
4
- import sys
5
- from hashlib import sha1
6
- from multiprocessing.dummy import Pool
7
- import platform
8
- import requests
9
- import shutil
10
- import tempfile
11
-
12
- from typing import Dict
13
-
14
- try:
15
- from urlparse import urlparse
16
- except:
17
- from urllib.parse import urlparse
18
-
19
- from metaflow.decorators import StepDecorator
20
- from metaflow.extension_support import EXT_PKG
21
- from metaflow.metaflow_environment import InvalidEnvironmentException
22
- from metaflow.metadata import MetaDatum
23
- from metaflow.metaflow_config import (
24
- get_pinned_conda_libs,
25
- )
26
- from metaflow.util import get_metaflow_root
27
-
28
- from ... import INFO_FILE
29
- from ..env_escape import generate_trampolines
30
- from . import read_conda_manifest, write_to_conda_manifest, get_conda_package_root
31
- from .conda import Conda
32
-
33
- try:
34
- unicode
35
- except NameError:
36
- unicode = str
37
- basestring = str
38
-
39
-
40
- class CondaStepDecorator(StepDecorator):
41
- """
42
- Specifies the Conda environment for the step.
43
-
44
- Information in this decorator will augment any
45
- attributes set in the `@conda_base` flow-level decorator. Hence,
46
- you can use `@conda_base` to set common libraries required by all
47
- steps and use `@conda` to specify step-specific additions.
48
-
49
- Parameters
50
- ----------
51
- libraries : Dict[str, str], default: {}
52
- Libraries to use for this step. The key is the name of the package
53
- and the value is the version to use.
54
- python : str, optional
55
- Version of Python to use, e.g. '3.7.4'. A default value of None means to
56
- use the current Python version.
57
- disabled : bool, default: False
58
- If set to True, disables Conda.
59
- """
60
-
61
- name = "conda"
62
- defaults = {"libraries": {}, "python": None, "disabled": None}
63
-
64
- conda = None
65
- environments = None
66
-
67
- def _get_base_attributes(self):
68
- if "conda_base" in self.flow._flow_decorators:
69
- return self.flow._flow_decorators["conda_base"][0].attributes
70
- return self.defaults
71
-
72
- def _python_version(self):
73
- return next(
74
- x
75
- for x in [
76
- self.attributes["python"],
77
- self.base_attributes["python"],
78
- platform.python_version(),
79
- ]
80
- if x is not None
81
- )
82
-
83
- def is_enabled(self, ubf_context=None):
84
- return not next(
85
- x
86
- for x in [
87
- self.attributes["disabled"],
88
- self.base_attributes["disabled"],
89
- False,
90
- ]
91
- if x is not None
92
- )
93
-
94
- def _lib_deps(self):
95
- deps = get_pinned_conda_libs(self._python_version(), self.flow_datastore.TYPE)
96
-
97
- base_deps = self.base_attributes["libraries"]
98
- deps.update(base_deps)
99
- step_deps = self.attributes["libraries"]
100
-
101
- deps.update(step_deps)
102
- return deps
103
-
104
- def _step_deps(self):
105
- deps = [b"python==%s" % self._python_version().encode()]
106
- deps.extend(
107
- b"%s==%s" % (name.encode("ascii"), ver.encode("ascii"))
108
- for name, ver in self._lib_deps().items()
109
- )
110
- return deps
111
-
112
- def _env_id(self):
113
- deps = self._step_deps()
114
- return "metaflow_%s_%s_%s" % (
115
- self.flow.name,
116
- self.architecture,
117
- sha1(b" ".join(sorted(deps))).hexdigest(),
118
- )
119
-
120
- def _resolve_step_environment(self, ds_root, force=False):
121
- env_id = self._env_id()
122
- cached_deps = read_conda_manifest(ds_root, self.flow.name)
123
- if CondaStepDecorator.conda is None:
124
- CondaStepDecorator.conda = Conda()
125
- CondaStepDecorator.environments = CondaStepDecorator.conda.environments(
126
- self.flow.name
127
- )
128
- if (
129
- force
130
- or env_id not in cached_deps
131
- or "cache_urls" not in cached_deps[env_id]
132
- ):
133
- if force or env_id not in cached_deps:
134
- deps = self._step_deps()
135
- (exact_deps, urls, order) = self.conda.create(
136
- self.step,
137
- env_id,
138
- deps,
139
- architecture=self.architecture,
140
- disable_safety_checks=self.disable_safety_checks,
141
- )
142
- payload = {
143
- "explicit": exact_deps,
144
- "deps": [d.decode("ascii") for d in deps],
145
- "urls": urls,
146
- "order": order,
147
- }
148
- else:
149
- payload = cached_deps[env_id]
150
-
151
- if (
152
- self.flow_datastore.TYPE in ("s3", "azure", "gs")
153
- and "cache_urls" not in payload
154
- ):
155
- payload["cache_urls"] = self._cache_env()
156
- write_to_conda_manifest(ds_root, self.flow.name, env_id, payload)
157
- CondaStepDecorator.environments = CondaStepDecorator.conda.environments(
158
- self.flow.name
159
- )
160
- return env_id
161
-
162
- def _cache_env(self):
163
- # Move here to avoid circular imports
164
- from metaflow.plugins import DATASTORES
165
-
166
- def _download(entry):
167
- url, local_path = entry
168
- with requests.get(url, stream=True) as r:
169
- with open(local_path, "wb") as f:
170
- shutil.copyfileobj(r.raw, f)
171
-
172
- env_id = self._env_id()
173
- files = []
174
- to_download = []
175
- for package_info in self.conda.package_info(env_id):
176
- url = urlparse(package_info["url"])
177
- path = os.path.join(
178
- url.netloc,
179
- url.path.lstrip("/"),
180
- package_info["md5"],
181
- package_info["fn"],
182
- )
183
- tarball_path = package_info["package_tarball_full_path"]
184
- # we were originally restricted to just .tar.bz2 packages
185
- # due to https://github.com/conda/conda/issues/9674
186
- # which doesn't seem to be the case anymore
187
- if not tarball_path.endswith(".conda") and not tarball_path.endswith(
188
- ".tar.bz2"
189
- ):
190
- tarball_path_suffix = ".tar.bz2"
191
- if package_info["url"].endswith(".conda"):
192
- tarball_path_suffix = ".conda"
193
- tarball_path = "%s%s" % (tarball_path, tarball_path_suffix)
194
- if not os.path.isfile(tarball_path):
195
- # The tarball maybe missing when user invokes `conda clean`!
196
- to_download.append((package_info["url"], tarball_path))
197
- files.append((path, tarball_path))
198
- if to_download:
199
- Pool(8).map(_download, to_download)
200
-
201
- list_of_path_and_filehandle = [
202
- (path, open(tarball_path, "rb")) for path, tarball_path in files
203
- ]
204
-
205
- # We need our own storage backend so that we can customize datastore_root on it
206
- # in a clearly safe way, without the existing backend owned by FlowDatastore
207
- storage_impl = [d for d in DATASTORES if d.TYPE == self.flow_datastore.TYPE][0]
208
- storage = storage_impl(get_conda_package_root(self.flow_datastore.TYPE))
209
- storage.save_bytes(
210
- list_of_path_and_filehandle, len_hint=len(list_of_path_and_filehandle)
211
- )
212
-
213
- return [files[0] for files in files]
214
-
215
- def _prepare_step_environment(self, step_name, ds_root):
216
- env_id = self._resolve_step_environment(ds_root)
217
- if env_id not in CondaStepDecorator.environments:
218
- cached_deps = read_conda_manifest(ds_root, self.flow.name)
219
- self.conda.create(
220
- self.step,
221
- env_id,
222
- cached_deps[env_id]["urls"],
223
- architecture=self.architecture,
224
- explicit=True,
225
- disable_safety_checks=self.disable_safety_checks,
226
- )
227
- CondaStepDecorator.environments = CondaStepDecorator.conda.environments(
228
- self.flow.name
229
- )
230
- return env_id
231
-
232
- def _disable_safety_checks(self, decos):
233
- # Disable conda safety checks when creating linux-64 environments on
234
- # a macOS. This is needed because of gotchas around inconsistently
235
- # case-(in)sensitive filesystems for macOS and linux.
236
- for deco in decos:
237
- if deco.name in ("batch", "kubernetes") and platform.system() == "Darwin":
238
- return True
239
- return False
240
-
241
- def _architecture(self, decos):
242
- for deco in decos:
243
- if deco.name in ("batch", "kubernetes"):
244
- # force conda resolution for linux-64 architectures
245
- return "linux-64"
246
- bit = "32"
247
- if platform.machine().endswith("64"):
248
- bit = "64"
249
- if platform.system() == "Linux":
250
- return "linux-%s" % bit
251
- elif platform.system() == "Darwin":
252
- # Support M1 Mac
253
- if platform.machine() == "arm64":
254
- return "osx-arm64"
255
- else:
256
- return "osx-%s" % bit
257
- else:
258
- raise InvalidEnvironmentException(
259
- "The *@conda* decorator is not supported "
260
- "outside of Linux and Darwin platforms"
261
- )
262
-
263
- def runtime_init(self, flow, graph, package, run_id):
264
- info_file_name = os.path.basename(INFO_FILE)
265
- # Create a symlink to installed version of metaflow to execute user code against
266
- path_to_metaflow = os.path.join(get_metaflow_root(), "metaflow")
267
- path_to_info = os.path.join(get_metaflow_root(), info_file_name)
268
- self.metaflow_home = tempfile.mkdtemp(dir="/tmp")
269
- self.addl_paths = None
270
- os.symlink(path_to_metaflow, os.path.join(self.metaflow_home, "metaflow"))
271
-
272
- # Symlink the INFO file as well to properly propagate down the Metaflow version
273
- # if launching on AWS Batch for example
274
- if os.path.isfile(path_to_info):
275
- os.symlink(path_to_info, os.path.join(self.metaflow_home, info_file_name))
276
- else:
277
- # If there is no info_file_name file, we will actually create one in this new
278
- # place because we won't be able to properly resolve the EXT_PKG extensions
279
- # the same way as outside conda (looking at distributions, etc.). In a
280
- # Conda environment, as shown below (where we set self.addl_paths), all
281
- # EXT_PKG extensions are PYTHONPATH extensions. Instead of re-resolving,
282
- # we use the resolved information that is written out to the INFO file.
283
- with open(
284
- os.path.join(self.metaflow_home, info_file_name),
285
- mode="wt",
286
- encoding="utf-8",
287
- ) as f:
288
- f.write(
289
- json.dumps(
290
- self._cur_environment.get_environment_info(
291
- include_ext_info=True
292
- )
293
- )
294
- )
295
-
296
- # Do the same for EXT_PKG
297
- try:
298
- m = importlib.import_module(EXT_PKG)
299
- except ImportError:
300
- # No additional check needed because if we are here, we already checked
301
- # for other issues when loading at the toplevel
302
- pass
303
- else:
304
- custom_paths = list(set(m.__path__)) # For some reason, at times, unique
305
- # paths appear multiple times. We simplify
306
- # to avoid un-necessary links
307
-
308
- if len(custom_paths) == 1:
309
- # Regular package; we take a quick shortcut here
310
- os.symlink(
311
- custom_paths[0],
312
- os.path.join(self.metaflow_home, EXT_PKG),
313
- )
314
- else:
315
- # This is a namespace package, we therefore create a bunch of directories
316
- # so that we can symlink in those separately, and we will add those paths
317
- # to the PYTHONPATH for the interpreter. Note that we don't symlink
318
- # to the parent of the package because that could end up including
319
- # more stuff we don't want
320
- self.addl_paths = []
321
- for p in custom_paths:
322
- temp_dir = tempfile.mkdtemp(dir=self.metaflow_home)
323
- os.symlink(p, os.path.join(temp_dir, EXT_PKG))
324
- self.addl_paths.append(temp_dir)
325
-
326
- # Also install any environment escape overrides directly here to enable
327
- # the escape to work even in non metaflow-created subprocesses
328
- generate_trampolines(self.metaflow_home)
329
-
330
- def step_init(self, flow, graph, step, decos, environment, flow_datastore, logger):
331
- # Move here to avoid circular import
332
- from metaflow.plugins.datastores.local_storage import LocalStorage
333
-
334
- if environment.TYPE != "conda":
335
- raise InvalidEnvironmentException(
336
- "The *@conda* decorator requires " "--environment=conda"
337
- )
338
-
339
- def _logger(line, **kwargs):
340
- logger(line)
341
-
342
- self.local_root = LocalStorage.get_datastore_root_from_config(_logger)
343
- environment.set_local_root(self.local_root)
344
- self.architecture = self._architecture(decos)
345
- self.disable_safety_checks = self._disable_safety_checks(decos)
346
- self.step = step
347
- self.flow = flow
348
- self.flow_datastore = flow_datastore
349
- self.base_attributes = self._get_base_attributes()
350
- os.environ["PYTHONNOUSERSITE"] = "1"
351
-
352
- def package_init(self, flow, step, environment):
353
- self._cur_environment = environment
354
- if self.is_enabled():
355
- self._prepare_step_environment(step, self.local_root)
356
-
357
- def runtime_task_created(
358
- self, task_datastore, task_id, split_index, input_paths, is_cloned, ubf_context
359
- ):
360
- if self.is_enabled(ubf_context):
361
- self.env_id = self._prepare_step_environment(self.step, self.local_root)
362
-
363
- def task_pre_step(
364
- self,
365
- step_name,
366
- task_datastore,
367
- meta,
368
- run_id,
369
- task_id,
370
- flow,
371
- graph,
372
- retry_count,
373
- max_retries,
374
- ubf_context,
375
- inputs,
376
- ):
377
- if self.is_enabled(ubf_context):
378
- # Add the Python interpreter's parent to the path. This is to
379
- # ensure that any non-pythonic dependencies introduced by the conda
380
- # environment are visible to the user code.
381
- env_path = os.path.dirname(sys.executable)
382
- if os.environ.get("PATH") is not None:
383
- env_path = os.pathsep.join([env_path, os.environ["PATH"]])
384
- os.environ["PATH"] = env_path
385
-
386
- meta.register_metadata(
387
- run_id,
388
- step_name,
389
- task_id,
390
- [
391
- MetaDatum(
392
- field="conda_env_id",
393
- value=self._env_id(),
394
- type="conda_env_id",
395
- tags=["attempt_id:{0}".format(retry_count)],
396
- )
397
- ],
398
- )
399
-
400
- def runtime_step_cli(
401
- self, cli_args, retry_count, max_user_code_retries, ubf_context
402
- ):
403
- no_batch = "batch" not in cli_args.commands
404
- no_kubernetes = "kubernetes" not in cli_args.commands
405
- if self.is_enabled(ubf_context) and no_batch and no_kubernetes:
406
- python_path = self.metaflow_home
407
- if self.addl_paths is not None:
408
- addl_paths = os.pathsep.join(self.addl_paths)
409
- python_path = os.pathsep.join([addl_paths, python_path])
410
-
411
- cli_args.env["PYTHONPATH"] = python_path
412
- cli_args.env["_METAFLOW_CONDA_ENV"] = self.env_id
413
- cli_args.entrypoint[0] = self.conda.python(self.env_id)
414
-
415
- def runtime_finished(self, exception):
416
- shutil.rmtree(self.metaflow_home)