ob-metaflow 2.12.10.1__py2.py3-none-any.whl → 2.12.10.1rc2__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.

@@ -8,6 +8,7 @@ from tempfile import mkdtemp
8
8
 
9
9
  from metaflow.datastore.datastore_storage import DataStoreStorage, CloseAfterUse
10
10
  from metaflow.exception import MetaflowInternalError
11
+ from metaflow.tracing import traced, tracing
11
12
  from metaflow.metaflow_config import (
12
13
  DATASTORE_SYSROOT_GS,
13
14
  ARTIFACT_LOCALROOT,
@@ -70,12 +71,14 @@ class _GSRootClient(object):
70
71
  """Drives GSStorage.is_file()"""
71
72
  try:
72
73
  blob = self.get_blob_client(path)
73
- result = blob.exists()
74
+ with traced("exists", dict(path=path)):
75
+ result = blob.exists()
74
76
 
75
77
  return result
76
78
  except Exception as e:
77
79
  process_gs_exception(e)
78
80
 
81
+ @tracing
79
82
  def list_content_single(self, path):
80
83
  """Drives GSStorage.list_content()"""
81
84
 
@@ -104,6 +107,7 @@ class _GSRootClient(object):
104
107
  except Exception as e:
105
108
  process_gs_exception(e)
106
109
 
110
+ @tracing
107
111
  def save_bytes_single(
108
112
  self,
109
113
  path_tmpfile_metadata_triple,
@@ -119,10 +123,12 @@ class _GSRootClient(object):
119
123
  blob.metadata = {"metaflow-user-attributes": json.dumps(metadata)}
120
124
  from google.cloud.storage.retry import DEFAULT_RETRY
121
125
 
122
- blob.upload_from_filename(tmpfile, retry=DEFAULT_RETRY)
126
+ with traced("upload_blob", dict(path=path)):
127
+ blob.upload_from_filename(tmpfile, retry=DEFAULT_RETRY)
123
128
  except Exception as e:
124
129
  process_gs_exception(e)
125
130
 
131
+ @tracing
126
132
  def load_bytes_single(self, tmpdir, key):
127
133
  """Drives GSStorage.load_bytes()"""
128
134
  tmp_filename = os.path.join(tmpdir, str(uuid.uuid4()))
@@ -136,7 +142,8 @@ class _GSRootClient(object):
136
142
  metaflow_user_attributes = json.loads(
137
143
  blob.metadata["metaflow-user-attributes"]
138
144
  )
139
- blob.download_to_filename(tmp_filename)
145
+ with traced("download_blob", dict(path=key)):
146
+ blob.download_to_filename(tmp_filename)
140
147
  except google.api_core.exceptions.NotFound:
141
148
  tmp_filename = None
142
149
  return key, tmp_filename, metaflow_user_attributes
@@ -5,6 +5,7 @@ import random
5
5
  import sys
6
6
  import time
7
7
 
8
+ from metaflow.tracing import inject_tracing_vars, tracing, traced
8
9
  from metaflow.exception import MetaflowException
9
10
  from metaflow.metaflow_config import KUBERNETES_SECRETS
10
11
  from metaflow.tracing import inject_tracing_vars
@@ -299,13 +300,19 @@ class KubernetesJob(object):
299
300
  # achieve the guarantees that we are seeking.
300
301
  # https://github.com/kubernetes/enhancements/issues/1040
301
302
  # Hopefully, we will be able to get creative with kube-batch
302
- response = (
303
- client.BatchV1Api()
304
- .create_namespaced_job(
305
- body=self._job, namespace=self._kwargs["namespace"]
303
+
304
+ with traced(
305
+ "submit_kubernetes_job",
306
+ {"job": "%s/%s" % (self._job.metadata.name, self._kwargs["namespace"])},
307
+ ):
308
+
309
+ response = (
310
+ client.BatchV1Api()
311
+ .create_namespaced_job(
312
+ body=self._job, namespace=self._kwargs["namespace"]
313
+ )
314
+ .to_dict()
306
315
  )
307
- .to_dict()
308
- )
309
316
  return RunningJob(
310
317
  client=self._client,
311
318
  name=response["metadata"]["name"],
@@ -434,11 +441,14 @@ class RunningJob(object):
434
441
  def _fetch_job(self):
435
442
  client = self._client.get()
436
443
  try:
437
- return (
438
- client.BatchV1Api()
439
- .read_namespaced_job(name=self._name, namespace=self._namespace)
440
- .to_dict()
441
- )
444
+ with traced(
445
+ "fetch_kubernetes_job", {"job": "%s/%s" % (self._name, self._namespace)}
446
+ ):
447
+ return (
448
+ client.BatchV1Api()
449
+ .read_namespaced_job(name=self._name, namespace=self._namespace)
450
+ .to_dict()
451
+ )
442
452
  except client.rest.ApiException as e:
443
453
  if e.status == 404:
444
454
  raise KubernetesJobException(
@@ -450,17 +460,20 @@ class RunningJob(object):
450
460
  def _fetch_pod(self):
451
461
  # Fetch pod metadata.
452
462
  client = self._client.get()
453
- pods = (
454
- client.CoreV1Api()
455
- .list_namespaced_pod(
456
- namespace=self._namespace,
457
- label_selector="job-name={}".format(self._name),
463
+ with traced(
464
+ "fetch_kubernetes_pod", {"job": "%s/%s" % (self._name, self._namespace)}
465
+ ):
466
+ pods = (
467
+ client.CoreV1Api()
468
+ .list_namespaced_pod(
469
+ namespace=self._namespace,
470
+ label_selector="job-name={}".format(self._name),
471
+ )
472
+ .to_dict()["items"]
458
473
  )
459
- .to_dict()["items"]
460
- )
461
- if pods:
462
- return pods[0]
463
- return {}
474
+ if pods:
475
+ return pods[0]
476
+ return {}
464
477
 
465
478
  def kill(self):
466
479
  # Terminating a Kubernetes job is a bit tricky. Issuing a
@@ -6,6 +6,7 @@ import sys
6
6
  from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
7
7
 
8
8
  from metaflow.exception import MetaflowException
9
+ from metaflow.tracing import TracedThreadPoolExecutor
9
10
 
10
11
  if sys.version_info[:2] < (3, 7):
11
12
  # in 3.6, Only BrokenProcessPool exists (there is no BrokenThreadPool)
@@ -132,7 +133,10 @@ class StorageExecutor(object):
132
133
  msg="Cannot use ProcessPoolExecutor because Python version is older than 3.7 and multiprocess start method has been set to something other than 'spawn'"
133
134
  )
134
135
  else:
135
- self._executor = ThreadPoolExecutor(max_workers=threadpool_max_workers)
136
+ self._executor = TracedThreadPoolExecutor(
137
+ "StorageExecutor", max_workers=threadpool_max_workers
138
+ )
139
+ # self._executor = ThreadPoolExecutor(max_workers=threadpool_max_workers)
136
140
 
137
141
  def warm_up(self):
138
142
  # warm up at least one process or thread in the pool.
@@ -52,6 +52,10 @@ def tracing(func):
52
52
  return wrapper_func
53
53
 
54
54
 
55
+ from concurrent.futures import ThreadPoolExecutor
56
+ TracedThreadPoolExecutor = ThreadPoolExecutor
57
+
58
+
55
59
  if not DISABLE_TRACING and (CONSOLE_TRACE_ENABLED or OTEL_ENDPOINT or ZIPKIN_ENDPOINT):
56
60
  try:
57
61
  # Overrides No-Op implementations if a specific provider is configured.
@@ -63,6 +67,7 @@ if not DISABLE_TRACING and (CONSOLE_TRACE_ENABLED or OTEL_ENDPOINT or ZIPKIN_END
63
67
  get_trace_id,
64
68
  traced,
65
69
  tracing,
70
+ TracedThreadPoolExecutor,
66
71
  )
67
72
 
68
73
  except ImportError as e:
@@ -0,0 +1,30 @@
1
+ from concurrent.futures import ThreadPoolExecutor
2
+ from opentelemetry import context as otel_context
3
+ from opentelemetry.sdk.trace import Tracer
4
+ from opentelemetry import trace as trace_api
5
+ from typing import Callable
6
+
7
+
8
+ class TracedThreadPoolExecutor(ThreadPoolExecutor):
9
+ """Implementation of :class:`ThreadPoolExecutor` that will pass context into sub tasks."""
10
+
11
+ def __init__(self, name: str, *args, **kwargs):
12
+ tracer = trace_api.get_tracer(name)
13
+ self.tracer = tracer
14
+ super().__init__(*args, **kwargs)
15
+
16
+ def with_otel_context(self, context: otel_context.Context, fn: Callable):
17
+ otel_context.attach(context)
18
+ return fn()
19
+
20
+ def submit(self, fn, *args, **kwargs):
21
+ """Submit a new task to the thread pool."""
22
+
23
+ # get the current otel context
24
+ context = otel_context.get_current()
25
+ if context:
26
+ return super().submit(
27
+ lambda: self.with_otel_context(context, lambda: fn(*args, **kwargs)),
28
+ )
29
+ else:
30
+ return super().submit(lambda: fn(*args, **kwargs))
@@ -13,6 +13,8 @@ from typing import Dict, List, Optional
13
13
  from opentelemetry import trace as trace_api, context
14
14
  from .span_exporter import get_span_exporter
15
15
 
16
+ from .threadpool import TracedThreadPoolExecutor
17
+
16
18
  tracer_provider = None
17
19
 
18
20
 
@@ -21,6 +23,7 @@ def init_tracing():
21
23
  if tracer_provider is not None:
22
24
  print("Tracing already initialized", file=sys.stderr)
23
25
  return
26
+ import os
24
27
 
25
28
  from .propagator import EnvPropagator
26
29
 
@@ -142,7 +145,7 @@ def traced(name, attrs={}):
142
145
  def tracing(func):
143
146
  @wraps(func)
144
147
  def wrapper_func(*args, **kwargs):
145
- tracer = trace_api.get_tracer_provider().get_tracer(func.__module__.__name__)
148
+ tracer = trace_api.get_tracer_provider().get_tracer(func.__module__)
146
149
 
147
150
  with tracer.start_as_current_span(func.__name__):
148
151
  return func(*args, **kwargs)
metaflow/version.py CHANGED
@@ -1 +1 @@
1
- metaflow_version = "2.12.10.1"
1
+ metaflow_version = "2.12.10.1rc2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ob-metaflow
3
- Version: 2.12.10.1
3
+ Version: 2.12.10.1rc2
4
4
  Summary: Metaflow: More Data Science, Less Engineering
5
5
  Author: Netflix, Outerbounds & the Metaflow Community
6
6
  Author-email: help@outerbounds.co
@@ -12,7 +12,7 @@ Requires-Dist: boto3
12
12
  Requires-Dist: pylint
13
13
  Requires-Dist: kubernetes
14
14
  Provides-Extra: stubs
15
- Requires-Dist: metaflow-stubs ==2.12.10.1 ; extra == 'stubs'
15
+ Requires-Dist: metaflow-stubs ==2.12.10.1rc2 ; extra == 'stubs'
16
16
 
17
17
  ![Metaflow_Logo_Horizontal_FullColor_Ribbon_Dark_RGB](https://user-images.githubusercontent.com/763451/89453116-96a57e00-d713-11ea-9fa6-82b29d4d6eff.png)
18
18
 
@@ -35,7 +35,7 @@ metaflow/tuple_util.py,sha256=_G5YIEhuugwJ_f6rrZoelMFak3DqAR2tt_5CapS1XTY,830
35
35
  metaflow/unbounded_foreach.py,sha256=p184WMbrMJ3xKYHwewj27ZhRUsSj_kw1jlye5gA9xJk,387
36
36
  metaflow/util.py,sha256=m5womQ7y-jXehuMyHPfByDbZ4HwTJxzs869cPOlMR8s,13057
37
37
  metaflow/vendor.py,sha256=FchtA9tH22JM-eEtJ2c9FpUdMn8sSb1VHuQS56EcdZk,5139
38
- metaflow/version.py,sha256=3IvPc0z5CHdysfIGeD_OJlA1QS8xf5sReJcs7eZ-NRU,31
38
+ metaflow/version.py,sha256=kGj-PcLLHyv0B6fbtr3neBGsNkLetAXjMRmb2CychSs,34
39
39
  metaflow/_vendor/__init__.py,sha256=y_CiwUD3l4eAKvTVDZeqgVujMy31cAM1qjAB-HfI-9s,353
40
40
  metaflow/_vendor/typing_extensions.py,sha256=0nUs5p1A_UrZigrAVBoOEM6TxU37zzPDUtiij1ZwpNc,110417
41
41
  metaflow/_vendor/zipp.py,sha256=ajztOH-9I7KA_4wqDYygtHa6xUBVZgFpmZ8FE74HHHI,8425
@@ -154,7 +154,7 @@ metaflow/plugins/parallel_decorator.py,sha256=wXBmEnnOmWI46-Lcry_CArkujj6YOrfzAw
154
154
  metaflow/plugins/project_decorator.py,sha256=eJOe0Ea7CbUCReEhR_XQvRkhV6jyRqDxM72oZI7EMCk,5336
155
155
  metaflow/plugins/resources_decorator.py,sha256=3MMZ7uptDf99795_RcSOq4h0N3OFlKpd3ahIEsozBBs,1333
156
156
  metaflow/plugins/retry_decorator.py,sha256=tz_2Tq6GLg3vjDBZp0KKVTk3ADlCvqaWTSf7blmFdUw,1548
157
- metaflow/plugins/storage_executor.py,sha256=FqAgR0-L9MuqN8fRtTe4jjUfJL9lqt6fQkYaglAjRbk,6137
157
+ metaflow/plugins/storage_executor.py,sha256=BUzSyv0cU5I_FN8RfXpNy6mlTw_8UKa-xm_5AUJ8aGQ,6332
158
158
  metaflow/plugins/tag_cli.py,sha256=O_ZI4ILwGX3xKrLewUUF-zdJjCDi3JmsTb4ow87_RuY,17610
159
159
  metaflow/plugins/test_unbounded_foreach_decorator.py,sha256=-3o_VhmZW7R9i-0RgqEradmPqx9rS6jJxcIKV6-WQMg,5948
160
160
  metaflow/plugins/timeout_decorator.py,sha256=R-X8rKeMqd-xhfJFqskWb6ZpmZt2JB14U1BZJSRriwM,3648
@@ -237,7 +237,7 @@ metaflow/plugins/cards/card_modules/chevron/tokenizer.py,sha256=lQU9OELUE9a5Xu4s
237
237
  metaflow/plugins/cards/card_viewer/viewer.html,sha256=qZJGzhZhQ1gugsknRP7zkAPPfUAtvemK1UKqXoGff5M,11593
238
238
  metaflow/plugins/datastores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
239
  metaflow/plugins/datastores/azure_storage.py,sha256=QvIUQGOZF1oKeRJXbl3RsV1MnO3OMfLzheoo0UNWn7E,16670
240
- metaflow/plugins/datastores/gs_storage.py,sha256=ED1xfXNDiPkqma5PEui8HCv0b4ImHK_rlUMQJD9UNes,9622
240
+ metaflow/plugins/datastores/gs_storage.py,sha256=qKdYuMLw2_PQRRWWEWu57MymRAsgeTe6dY5Lmprh_lw,9885
241
241
  metaflow/plugins/datastores/local_storage.py,sha256=igrBDphhyu7EFIUj3BWcO7beiZbNnJLq--lF45UYSyI,4750
242
242
  metaflow/plugins/datastores/s3_storage.py,sha256=CZdNqaKtxDXQbEg2YHyphph3hWcLIE50puenm0WGVpk,5473
243
243
  metaflow/plugins/datatools/__init__.py,sha256=ge4L16OBQLy2J_MMvoHg3lMfdm-MluQgRWoyZ5GCRnk,1267
@@ -281,7 +281,7 @@ metaflow/plugins/kubernetes/kubernetes.py,sha256=0UjKZy5_5KOGYC-k0DZqpv-ca_tZBkw
281
281
  metaflow/plugins/kubernetes/kubernetes_cli.py,sha256=qBDdr1Lvtt-RO9pB-9_HTOPdzAmDvvJ0aiQ1OoCcrMU,10892
282
282
  metaflow/plugins/kubernetes/kubernetes_client.py,sha256=GKg-gT3qhXMRQV-sG1YyoOf3Z32NXr_wwEN2ytMVSEg,2471
283
283
  metaflow/plugins/kubernetes/kubernetes_decorator.py,sha256=Xu1PB9hrodnDcPIVHMC9HrTvOQzsEr4nR80zoIlXTME,25463
284
- metaflow/plugins/kubernetes/kubernetes_job.py,sha256=1uQmEHsLyJ5jewmIA5smrFtSO8MymOqPDb-YIS65u50,31614
284
+ metaflow/plugins/kubernetes/kubernetes_job.py,sha256=VcRhUrAlPQMwJ02xGHUh-E4dh1EWP-6RjwjgIiZHDf8,32190
285
285
  metaflow/plugins/kubernetes/kubernetes_jobsets.py,sha256=Cr5M7m0lKShv6o8xjRJap8hSRgf51fz4RR0THlCSM08,40780
286
286
  metaflow/plugins/metadata/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
287
287
  metaflow/plugins/metadata/local.py,sha256=YhLJC5zjVJrvQFIyQ92ZBByiUmhCC762RUX7ITX12O8,22428
@@ -315,10 +315,11 @@ metaflow/system/__init__.py,sha256=SB9Py7Acecqi76MY9MonSHXFuDD1yIJEGJtEQH8cNq4,1
315
315
  metaflow/system/system_logger.py,sha256=31noRo2qFdFyVtlyvIV2coUw4x6YdJGCdhctNBbBUso,3299
316
316
  metaflow/system/system_monitor.py,sha256=NracI4ITbUZWziGsAvE1910ODZhXGVYro7jD-rLWe48,3578
317
317
  metaflow/system/system_utils.py,sha256=E5C66_oeAxEE4-2okKlA-X6rgeYndPFP7KmWKHvvFZ8,657
318
- metaflow/tracing/__init__.py,sha256=xYTOT5BS5jbwhjk6hskxqNSU9st2LYtfeLN2Hknm3EI,1551
318
+ metaflow/tracing/__init__.py,sha256=aOoU4o0fIHARKY25QUeqrRpJMtXS9r2NcSvakPu047k,1687
319
319
  metaflow/tracing/propagator.py,sha256=AdPeAqoeRauH82pTw01hLFNPRAzm29nlwM7C2iqKFFk,2502
320
320
  metaflow/tracing/span_exporter.py,sha256=eFVW40Fakct26KWycA-HEyl9yDqZRSJoLr3BOx8qopM,1697
321
- metaflow/tracing/tracing_modules.py,sha256=_-3xwEq2-qRY2o2QMtZI6Xl8G5OHv_SAJUNaan0EYt8,4877
321
+ metaflow/tracing/threadpool.py,sha256=ldoSO9baoNPJpfr9msclNlQeeRfJIysGQ48YqLniM1k,1082
322
+ metaflow/tracing/tracing_modules.py,sha256=fhuflMFkMLCZnGw3uccn22DMp87EE5oblogjQnbeZyg,4932
322
323
  metaflow/tutorials/00-helloworld/README.md,sha256=ML9k-2mRZOAFV3RDzwAWSIjnWzG03-3n9ov59UAvN5k,386
323
324
  metaflow/tutorials/00-helloworld/helloworld.py,sha256=ji0v7TFjVVR0VTs-shQOswh1Zd0YP5rZxud_LEmsjHU,857
324
325
  metaflow/tutorials/01-playlist/README.md,sha256=b9jgxen-vaVNIyH2UZPys4vvbxBylSoqDzCQ-aL3ves,838
@@ -342,9 +343,9 @@ metaflow/tutorials/07-worldview/README.md,sha256=5vQTrFqulJ7rWN6r20dhot9lI2sVj9W
342
343
  metaflow/tutorials/07-worldview/worldview.ipynb,sha256=ztPZPI9BXxvW1QdS2Tfe7LBuVzvFvv0AToDnsDJhLdE,2237
343
344
  metaflow/tutorials/08-autopilot/README.md,sha256=GnePFp_q76jPs991lMUqfIIh5zSorIeWznyiUxzeUVE,1039
344
345
  metaflow/tutorials/08-autopilot/autopilot.ipynb,sha256=DQoJlILV7Mq9vfPBGW-QV_kNhWPjS5n6SJLqePjFYLY,3191
345
- ob_metaflow-2.12.10.1.dist-info/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
346
- ob_metaflow-2.12.10.1.dist-info/METADATA,sha256=RMXh3hmIQPNiE9VPNB4fcJfshMltyyQj8ECecFjkd9A,5145
347
- ob_metaflow-2.12.10.1.dist-info/WHEEL,sha256=XRxW4r1PNiVhMpP4bT9oWtu3HyndxpJ84SkubFgzp_Y,109
348
- ob_metaflow-2.12.10.1.dist-info/entry_points.txt,sha256=IKwTN1T3I5eJL3uo_vnkyxVffcgnRdFbKwlghZfn27k,57
349
- ob_metaflow-2.12.10.1.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
350
- ob_metaflow-2.12.10.1.dist-info/RECORD,,
346
+ ob_metaflow-2.12.10.1rc2.dist-info/LICENSE,sha256=nl_Lt5v9VvJ-5lWJDT4ddKAG-VZ-2IaLmbzpgYDz2hU,11343
347
+ ob_metaflow-2.12.10.1rc2.dist-info/METADATA,sha256=ZDGv_s5Zo4rCdA5Ds0EJjYYxOVYoCBhwEnPwh-YApJ4,5151
348
+ ob_metaflow-2.12.10.1rc2.dist-info/WHEEL,sha256=XRxW4r1PNiVhMpP4bT9oWtu3HyndxpJ84SkubFgzp_Y,109
349
+ ob_metaflow-2.12.10.1rc2.dist-info/entry_points.txt,sha256=IKwTN1T3I5eJL3uo_vnkyxVffcgnRdFbKwlghZfn27k,57
350
+ ob_metaflow-2.12.10.1rc2.dist-info/top_level.txt,sha256=v1pDHoWaSaKeuc5fKTRSfsXCKSdW1zvNVmvA-i0if3o,9
351
+ ob_metaflow-2.12.10.1rc2.dist-info/RECORD,,