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

@@ -116,40 +116,39 @@ def get_boto3_session(role_arn=None, session_vars=None):
116
116
  if token_info.get("region"):
117
117
  os.environ["AWS_DEFAULT_REGION"] = token_info["region"]
118
118
 
119
- with hide_access_keys():
120
- if cspr_role:
121
- # The generated AWS config will be used here since we set the
122
- # AWS_CONFIG_FILE environment variable above.
123
- if role_arn == USE_CSPR_ROLE_ARN_IF_SET:
124
- # Otherwise start from the default profile, assuming CSPR role
125
- session = boto3.session.Session(profile_name="cspr")
126
- else:
127
- session = boto3.session.Session(profile_name="task")
128
- else:
129
- # Not using AWS config, just AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN
130
- session = boto3.session.Session()
131
-
132
- if role_arn and role_arn != USE_CSPR_ROLE_ARN_IF_SET:
133
- # If the user provided a role_arn, we assume that role
134
- # using the task role credentials. CSPR role is not used.
135
- fetcher = botocore.credentials.AssumeRoleCredentialFetcher(
136
- client_creator=session._session.create_client,
137
- source_credentials=session._session.get_credentials(),
138
- role_arn=role_arn,
139
- extra_args={},
140
- )
141
- creds = botocore.credentials.DeferredRefreshableCredentials(
142
- method="assume-role", refresh_using=fetcher.fetch_credentials
143
- )
144
- botocore_session = botocore.session.Session(session_vars=session_vars)
145
- botocore_session._credentials = creds
146
- return boto3.session.Session(botocore_session=botocore_session)
119
+ if cspr_role:
120
+ # The generated AWS config will be used here since we set the
121
+ # AWS_CONFIG_FILE environment variable above.
122
+ if role_arn == USE_CSPR_ROLE_ARN_IF_SET:
123
+ # Otherwise start from the default profile, assuming CSPR role
124
+ session = boto3.session.Session(profile_name="cspr")
147
125
  else:
148
- # If the user didn't provide a role_arn, or if the role_arn
149
- # is set to USE_CSPR_ROLE_ARN_IF_SET, we return the default
150
- # session which would use the CSPR role if it is set on the
151
- # server, and the task role otherwise.
152
- return session
126
+ session = boto3.session.Session(profile_name="task")
127
+ else:
128
+ # Not using AWS config, just AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN
129
+ session = boto3.session.Session()
130
+
131
+ if role_arn and role_arn != USE_CSPR_ROLE_ARN_IF_SET:
132
+ # If the user provided a role_arn, we assume that role
133
+ # using the task role credentials. CSPR role is not used.
134
+ fetcher = botocore.credentials.AssumeRoleCredentialFetcher(
135
+ client_creator=session._session.create_client,
136
+ source_credentials=session._session.get_credentials(),
137
+ role_arn=role_arn,
138
+ extra_args={},
139
+ )
140
+ creds = botocore.credentials.DeferredRefreshableCredentials(
141
+ method="assume-role", refresh_using=fetcher.fetch_credentials
142
+ )
143
+ botocore_session = botocore.session.Session(session_vars=session_vars)
144
+ botocore_session._credentials = creds
145
+ return boto3.session.Session(botocore_session=botocore_session)
146
+ else:
147
+ # If the user didn't provide a role_arn, or if the role_arn
148
+ # is set to USE_CSPR_ROLE_ARN_IF_SET, we return the default
149
+ # session which would use the CSPR role if it is set on the
150
+ # server, and the task role otherwise.
151
+ return session
153
152
 
154
153
 
155
154
  class ObpAuthProvider(object):
@@ -164,11 +163,12 @@ class ObpAuthProvider(object):
164
163
 
165
164
  from botocore.exceptions import ClientError
166
165
 
167
- session = get_boto3_session(role_arn, session_vars)
168
- if with_error:
169
- return session.client(module, **client_params), ClientError
170
- else:
171
- return session.client(module, **client_params)
166
+ with hide_access_keys():
167
+ session = get_boto3_session(role_arn, session_vars)
168
+ if with_error:
169
+ return session.client(module, **client_params), ClientError
170
+ else:
171
+ return session.client(module, **client_params)
172
172
 
173
173
 
174
174
  AWS_CLIENT_PROVIDERS_DESC = [("obp", ".ObpAuthProvider")]
@@ -306,7 +306,7 @@ class ObpGcpAuthProvider(object):
306
306
 
307
307
  GCP_CLIENT_PROVIDERS_DESC = [("obp", ".ObpGcpAuthProvider")]
308
308
  CLIS_DESC = [
309
- ("nvcf", ".nvcf.nvcf_cli.cli"),
309
+ ("nvidia", ".nvcf.nvcf_cli.cli"),
310
310
  ("fast-bakery", ".fast_bakery.fast_bakery_cli.cli"),
311
311
  ("snowpark", ".snowpark.snowpark_cli.cli"),
312
312
  ]
@@ -15,6 +15,7 @@ from metaflow.plugins.kubernetes.kubernetes_decorator import KubernetesDecorator
15
15
  from metaflow.plugins.pypi.conda_decorator import CondaStepDecorator
16
16
  from metaflow.plugins.pypi.conda_environment import CondaEnvironment
17
17
  from metaflow.plugins.pypi.pypi_decorator import PyPIStepDecorator
18
+ from metaflow import decorators
18
19
 
19
20
  from .fast_bakery import FastBakery, FastBakeryApiResponse, FastBakeryException
20
21
 
@@ -26,8 +27,6 @@ import os
26
27
  from concurrent.futures import ThreadPoolExecutor
27
28
  from functools import wraps
28
29
 
29
- # TODO - ensure that both @conda/@pypi are not assigned to the same step
30
-
31
30
 
32
31
  def cache_request(cache_file):
33
32
  def decorator(func):
@@ -103,7 +102,10 @@ class DockerEnvironment(MetaflowEnvironment):
103
102
  self.local_root = local_root
104
103
 
105
104
  def decospecs(self):
106
- return ("conda", "fast_bakery_internal") + super().decospecs()
105
+ # Due to conflicts with the CondaEnvironment fallback and bakery,
106
+ # we can not simply attach 'conda' or 'pypi' to all steps here.
107
+ # Instead we do this on a per-step basis in init_environment
108
+ return ("fast_bakery_internal",) + super().decospecs()
107
109
 
108
110
  def validate_environment(self, logger, datastore_type):
109
111
  self.datastore_type = datastore_type
@@ -116,14 +118,7 @@ class DockerEnvironment(MetaflowEnvironment):
116
118
 
117
119
  # Mixing @pypi/@conda in a single step is not supported yet
118
120
  for step in self.flow:
119
- if (
120
- sum(
121
- 1
122
- for deco in step.decorators
123
- if isinstance(deco, (PyPIStepDecorator, CondaStepDecorator))
124
- )
125
- > 1
126
- ):
121
+ if sum(1 for deco in step.decorators if _is_env_deco(deco)) > 1:
127
122
  raise MetaflowException(
128
123
  "Mixing and matching PyPI packages and Conda packages within a\n"
129
124
  "step is not yet supported. Use one of @pypi or @conda only for the *%s* step."
@@ -132,13 +127,31 @@ class DockerEnvironment(MetaflowEnvironment):
132
127
 
133
128
  def init_environment(self, echo):
134
129
  self.skipped_steps = {
135
- step.name
136
- for step in self.flow
137
- if not any(
138
- isinstance(deco, (BatchDecorator, KubernetesDecorator))
139
- for deco in step.decorators
140
- )
130
+ step.name for step in self.flow if not _step_executes_remotely(step)
141
131
  }
132
+ # Attach environment decorator as needed. This is done on a step-by-step basis
133
+ # as we require a conda decorator for fallback steps, but prefer pypi for the baked ones.
134
+ for step in self.flow:
135
+ if not _step_has_environment_deco(step):
136
+ if step.name in self.skipped_steps:
137
+ # Conda fallback requires a conda decorator as the default for a step
138
+ decorators._attach_decorators_to_step(step, ["conda"])
139
+ else:
140
+ # We default to PyPI for steps that are going to be baked.
141
+ decorators._attach_decorators_to_step(step, ["pypi"])
142
+ # Initialize the decorator we attached.
143
+ # This is crucial for the conda decorator to work properly in the fallback environment
144
+ for deco in step.decorators:
145
+ if _is_env_deco(deco):
146
+ deco.step_init(
147
+ self.flow,
148
+ None, # not passing graph as it is not available, and not required by conda/pypi decorators
149
+ step.name,
150
+ step.decorators,
151
+ self,
152
+ self.datastore,
153
+ echo,
154
+ )
142
155
 
143
156
  steps_to_bake = [
144
157
  step for step in self.flow if step.name not in self.skipped_steps
@@ -149,7 +162,7 @@ class DockerEnvironment(MetaflowEnvironment):
149
162
  self.results = self._bake(steps_to_bake)
150
163
  for step in self.flow:
151
164
  for d in step.decorators:
152
- if isinstance(d, (BatchDecorator, KubernetesDecorator)):
165
+ if _is_remote_deco(d):
153
166
  d.attributes["image"] = self.results[step.name].container_image
154
167
  d.attributes["executable"] = self.results[step.name].python_path
155
168
  if self.images_baked > 0:
@@ -178,32 +191,32 @@ class DockerEnvironment(MetaflowEnvironment):
178
191
  conda_packages=None,
179
192
  base_image=None,
180
193
  ):
181
- bakery = FastBakery(url=FAST_BAKERY_URL)
182
- bakery._reset_payload()
183
- bakery.python_version(python)
184
- bakery.pypi_packages(pypi_packages)
185
- bakery.conda_packages(conda_packages)
186
- bakery.base_image(base_image)
187
- # bakery.ignore_cache()
188
-
189
- with logger_lock:
190
- self.logger(f"🍳 Baking [{ref}] ...")
191
- self.logger(f" 🐍 Python: {python}")
192
-
193
- if pypi_packages:
194
- self.logger(f" 📦 PyPI packages:")
195
- for package, version in pypi_packages.items():
196
- self.logger(f" 🔧 {package}: {version}")
197
-
198
- if conda_packages:
199
- self.logger(f" 📦 Conda packages:")
200
- for package, version in conda_packages.items():
201
- self.logger(f" 🔧 {package}: {version}")
202
-
203
- self.logger(f" 🏗️ Base image: {base_image}")
204
-
205
- start_time = time.time()
206
194
  try:
195
+ bakery = FastBakery(url=FAST_BAKERY_URL)
196
+ bakery._reset_payload()
197
+ bakery.python_version(python)
198
+ bakery.pypi_packages(pypi_packages)
199
+ bakery.conda_packages(conda_packages)
200
+ bakery.base_image(base_image)
201
+ # bakery.ignore_cache()
202
+
203
+ with logger_lock:
204
+ self.logger(f"🍳 Baking [{ref}] ...")
205
+ self.logger(f" 🐍 Python: {python}")
206
+
207
+ if pypi_packages:
208
+ self.logger(f" 📦 PyPI packages:")
209
+ for package, version in pypi_packages.items():
210
+ self.logger(f" 🔧 {package}: {version}")
211
+
212
+ if conda_packages:
213
+ self.logger(f" 📦 Conda packages:")
214
+ for package, version in conda_packages.items():
215
+ self.logger(f" 🔧 {package}: {version}")
216
+
217
+ self.logger(f" 🏗️ Base image: {base_image}")
218
+
219
+ start_time = time.time()
207
220
  res = bakery.bake()
208
221
  # TODO: Get actual bake time from bakery
209
222
  bake_time = time.time() - start_time
@@ -225,11 +238,7 @@ class DockerEnvironment(MetaflowEnvironment):
225
238
  None,
226
239
  )
227
240
  dependencies = next(
228
- (
229
- d
230
- for d in step.decorators
231
- if isinstance(d, (CondaStepDecorator, PyPIStepDecorator))
232
- ),
241
+ (d for d in step.decorators if _is_env_deco(d)),
233
242
  None,
234
243
  )
235
244
  python = next(
@@ -322,3 +331,22 @@ class DockerEnvironment(MetaflowEnvironment):
322
331
 
323
332
  def get_fastbakery_metafile_path(local_root, flow_name):
324
333
  return os.path.join(local_root, flow_name, BAKERY_METAFILE)
334
+
335
+
336
+ def _is_remote_deco(deco):
337
+ return isinstance(deco, (BatchDecorator, KubernetesDecorator))
338
+
339
+
340
+ def _step_executes_remotely(step):
341
+ "Check if a step is going to execute remotely or locally"
342
+ return any(_is_remote_deco(deco) for deco in step.decorators)
343
+
344
+
345
+ def _is_env_deco(deco):
346
+ "Check if a decorator is a known environment decorator (conda/pypi)"
347
+ return isinstance(deco, (PyPIStepDecorator, CondaStepDecorator))
348
+
349
+
350
+ def _step_has_environment_deco(step):
351
+ "Check if a step has a virtual environment decorator"
352
+ return any(_is_env_deco(deco) for deco in step.decorators)
@@ -73,6 +73,8 @@ class FastBakeryApiResponse:
73
73
 
74
74
  class FastBakery:
75
75
  def __init__(self, url: str):
76
+ if not url:
77
+ raise FastBakeryException("Specifying a url is required.")
76
78
  self.url = url
77
79
  self.headers = {"Content-Type": "application/json", "Connection": "keep-alive"}
78
80
  self._reset_payload()
@@ -1,13 +1,29 @@
1
1
  import os
2
2
  import sys
3
3
  import time
4
- import signal
4
+ import subprocess
5
5
  from io import BytesIO
6
6
  from datetime import datetime, timezone
7
7
 
8
8
  from metaflow.exception import MetaflowException
9
9
 
10
10
 
11
+ def kill_process_and_descendants(pid, termination_timeout=5):
12
+ try:
13
+ subprocess.check_call(["pkill", "-TERM", "-P", str(pid)])
14
+ subprocess.check_call(["kill", "-TERM", str(pid)])
15
+ except subprocess.CalledProcessError:
16
+ pass
17
+
18
+ time.sleep(termination_timeout)
19
+
20
+ try:
21
+ subprocess.check_call(["pkill", "-KILL", "-P", str(pid)])
22
+ subprocess.check_call(["kill", "-KILL", str(pid)])
23
+ except subprocess.CalledProcessError:
24
+ pass
25
+
26
+
11
27
  class HeartbeatStore(object):
12
28
  def __init__(
13
29
  self,
@@ -67,7 +83,7 @@ class HeartbeatStore(object):
67
83
  contents = f.read()
68
84
  if "tombstone" in contents:
69
85
  print("[Outerbounds] Tombstone detected. Terminating the task..")
70
- os.kill(self.main_pid, signal.SIGTERM)
86
+ kill_process_and_descendants(self.main_pid)
71
87
  sys.exit(1)
72
88
 
73
89
  def __handle_heartbeat(self, path):
@@ -86,7 +102,7 @@ class HeartbeatStore(object):
86
102
  print(
87
103
  f"[Outerbounds] Missed {self.max_missed_heartbeats} consecutive heartbeats. Terminating the task.."
88
104
  )
89
- os.kill(self.main_pid, signal.SIGTERM)
105
+ kill_process_and_descendants(self.main_pid)
90
106
  sys.exit(1)
91
107
 
92
108
  def is_main_process_running(self):
@@ -39,13 +39,18 @@ def cli():
39
39
  pass
40
40
 
41
41
 
42
- @cli.group(help="Commands related to NVCF.")
43
- def nvcf():
42
+ @cli.group(help="Commands related to nvidia.")
43
+ def nvidia():
44
44
  pass
45
45
 
46
46
 
47
- @nvcf.command(help="List steps / tasks running as an NVCF job.")
48
- @click.argument("run-id")
47
+ @nvidia.command(help="List steps / tasks running as an nvidia job.")
48
+ @click.option(
49
+ "--run-id",
50
+ default=None,
51
+ required=True,
52
+ help="List unfinished tasks corresponding to the run id.",
53
+ )
49
54
  @click.pass_context
50
55
  def list(ctx, run_id):
51
56
  flow_name = ctx.obj.flow.name
@@ -65,13 +70,18 @@ def list(ctx, run_id):
65
70
 
66
71
  if running_invocations:
67
72
  for each_invocation in running_invocations:
68
- print(each_invocation)
73
+ ctx.obj.echo(each_invocation)
69
74
  else:
70
- print("No running NVCF invocations for Run ID: %s" % run_id)
75
+ ctx.obj.echo("No running @nvidia invocations for Run ID: %s" % run_id)
71
76
 
72
77
 
73
- @nvcf.command(help="Kill steps / tasks running as an NVCF job.")
74
- @click.argument("run-id")
78
+ @nvidia.command(help="Kill steps / tasks running as an nvidia job.")
79
+ @click.option(
80
+ "--run-id",
81
+ default=None,
82
+ required=True,
83
+ help="Terminate unfinished tasks corresponding to the run id.",
84
+ )
75
85
  @click.pass_context
76
86
  def kill(ctx, run_id):
77
87
  from metaflow_extensions.outerbounds.plugins.nvcf.heartbeat_store import (
@@ -100,12 +110,12 @@ def kill(ctx, run_id):
100
110
  )
101
111
  store.emit_tombstone(folder_name="nvcf_heartbeats")
102
112
  else:
103
- print("No running NVCF invocations for Run ID: %s" % run_id)
113
+ ctx.obj.echo("No running @nvidia invocations for Run ID: %s" % run_id)
104
114
 
105
115
 
106
- @nvcf.command(
107
- help="Execute a single task using NVCF. This command calls the "
108
- "top-level step command inside a NVCF job with the given options. "
116
+ @nvidia.command(
117
+ help="Execute a single task using @nvidia. This command calls the "
118
+ "top-level step command inside an nvidia job with the given options. "
109
119
  "Typically you do not call this command directly; it is used internally by "
110
120
  "Metaflow."
111
121
  )
@@ -72,7 +72,7 @@ class NvcfDecorator(StepDecorator):
72
72
  # after all attempts to run the user code have failed, we don't need
73
73
  # to execute on NVCF anymore. We can execute possible fallback
74
74
  # code locally.
75
- cli_args.commands = ["nvcf", "step"]
75
+ cli_args.commands = ["nvidia", "step"]
76
76
  cli_args.command_args.append(self.package_sha)
77
77
  cli_args.command_args.append(self.package_url)
78
78
  cli_args.command_options.update(self.attributes)
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ob-metaflow-extensions
3
- Version: 1.1.88
3
+ Version: 1.1.90
4
4
  Summary: Outerbounds Platform Extensions for Metaflow
5
5
  Author: Outerbounds, Inc.
6
6
  License: Commercial
7
7
  Description-Content-Type: text/markdown
8
8
  Requires-Dist: boto3
9
9
  Requires-Dist: kubernetes
10
- Requires-Dist: ob-metaflow (==2.12.18.2)
10
+ Requires-Dist: ob-metaflow (==2.12.19.1)
11
11
 
12
12
  # Outerbounds platform package
13
13
 
@@ -1,12 +1,12 @@
1
1
  metaflow_extensions/outerbounds/__init__.py,sha256=TRGvIUMjkfneWtYUFSWoubu_Kf2ekAL4WLbV3IxOj9k,499
2
2
  metaflow_extensions/outerbounds/remote_config.py,sha256=Zpfpjgz68_ZgxlXezjzlsDLo4840rkWuZgwDB_5H57U,4059
3
3
  metaflow_extensions/outerbounds/config/__init__.py,sha256=JsQGRuGFz28fQWjUvxUgR8EKBLGRdLUIk_buPLJplJY,1225
4
- metaflow_extensions/outerbounds/plugins/__init__.py,sha256=RNN9wxnIeNHO9S9lI-sgVINbAcO0C-29lYNd4BqNs-M,12508
4
+ metaflow_extensions/outerbounds/plugins/__init__.py,sha256=WwvFcN5kserbPwhrE4hXprnXzJxonEPT0Mlik2kmGMA,12406
5
5
  metaflow_extensions/outerbounds/plugins/auth_server.py,sha256=1v2GBqoMBxp5E7Lejz139w-jxJtPnLDvvHXP0HhEIHI,2361
6
6
  metaflow_extensions/outerbounds/plugins/perimeters.py,sha256=QXh3SFP7GQbS-RAIxUOPbhPzQ7KDFVxZkTdKqFKgXjI,2697
7
7
  metaflow_extensions/outerbounds/plugins/fast_bakery/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py,sha256=9iokzw--nCpk-omGXDSB-oct7-57rCJbq62HKvmt2NA,12126
9
- metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py,sha256=6OQdij49tjBwQuQ8Kdu16kfLBzKLGM4_f80KQm6WurQ,5069
8
+ metaflow_extensions/outerbounds/plugins/fast_bakery/docker_environment.py,sha256=gFeXt8nLv7SzZ2zEoAKMpdxAePN4jZclSsmQAm6hB4w,13846
9
+ metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery.py,sha256=MAPRQsfqeEkL1LXqgwPrUJOzZ3kY3C00QjdDgQ7wdIg,5160
10
10
  metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_cli.py,sha256=kqFyu2bJSnc9_9aYfBpz5xK6L6luWFZK_NMuh8f1eVk,1494
11
11
  metaflow_extensions/outerbounds/plugins/fast_bakery/fast_bakery_decorator.py,sha256=EZDbyrfZ7fgcU-P9dMS_hpCxsdDeUE0K5VU3uNM4aW4,1506
12
12
  metaflow_extensions/outerbounds/plugins/kubernetes/__init__.py,sha256=5zG8gShSj8m7rgF4xgWBZFuY3GDP5n1T0ktjRpGJLHA,69
@@ -14,10 +14,10 @@ metaflow_extensions/outerbounds/plugins/kubernetes/kubernetes_client.py,sha256=g
14
14
  metaflow_extensions/outerbounds/plugins/nim/__init__.py,sha256=GVnvSTjqYVj5oG2yh8KJFt7iZ33cEadDD5HbdmC9hJ0,1457
15
15
  metaflow_extensions/outerbounds/plugins/nim/nim_manager.py,sha256=SWieODDxtIaeZwdMYtObDi57Kjyfw2DUuE6pJtU750w,9206
16
16
  metaflow_extensions/outerbounds/plugins/nvcf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- metaflow_extensions/outerbounds/plugins/nvcf/heartbeat_store.py,sha256=wIlPBzsTszkHpftK1x7zBgaQ_7d3tNURqh4ez71Ra7A,5416
17
+ metaflow_extensions/outerbounds/plugins/nvcf/heartbeat_store.py,sha256=4aQZ0kpW2LlJbHx6AG4A9eaFLH9rWC_ENWnnfYNq1qk,5910
18
18
  metaflow_extensions/outerbounds/plugins/nvcf/nvcf.py,sha256=NIt1kJHuYpnCF7n73A90ZITWsk5QWtsbiHfzvdVjgqk,8997
19
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf_cli.py,sha256=AhlFa8UVzVKQRUilQwtwp7ZVWJ0WNitPU0vp29i7WuY,9545
20
- metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py,sha256=0xNA4aRTPJ4SKpRIFKZzlL9a7lf367KGTrVWVXd-uGE,6052
19
+ metaflow_extensions/outerbounds/plugins/nvcf/nvcf_cli.py,sha256=9nQBwm6AYtaKIAxdb937MOnsut3INEXN3v5eSnXy4cg,9811
20
+ metaflow_extensions/outerbounds/plugins/nvcf/nvcf_decorator.py,sha256=E7h94ni8yW9BQkKSBUptPdGAaVmXpR9FlXkPWpLyPd0,6054
21
21
  metaflow_extensions/outerbounds/plugins/snowpark/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  metaflow_extensions/outerbounds/plugins/snowpark/snowpark.py,sha256=vzgpVLCKvHjzHNfJvmH0jcxefYNsVggw_vof_y_U_a8,10643
23
23
  metaflow_extensions/outerbounds/plugins/snowpark/snowpark_cli.py,sha256=ErsVoCQLa33byiykOQzDEeEkRKk0mgffZme43f3jxn4,8747
@@ -33,7 +33,7 @@ metaflow_extensions/outerbounds/toplevel/global_aliases_for_metaflow_package.py,
33
33
  metaflow_extensions/outerbounds/toplevel/plugins/azure/__init__.py,sha256=WUuhz2YQfI4fz7nIcipwwWq781eaoHEk7n4GAn1npDg,63
34
34
  metaflow_extensions/outerbounds/toplevel/plugins/gcp/__init__.py,sha256=BbZiaH3uILlEZ6ntBLKeNyqn3If8nIXZFq_Apd7Dhco,70
35
35
  metaflow_extensions/outerbounds/toplevel/plugins/kubernetes/__init__.py,sha256=5zG8gShSj8m7rgF4xgWBZFuY3GDP5n1T0ktjRpGJLHA,69
36
- ob_metaflow_extensions-1.1.88.dist-info/METADATA,sha256=zgizoMrEL9ZXm9vj3WTY0K6y0DbQuoBkBuxiZGeXkCc,520
37
- ob_metaflow_extensions-1.1.88.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
38
- ob_metaflow_extensions-1.1.88.dist-info/top_level.txt,sha256=NwG0ukwjygtanDETyp_BUdtYtqIA_lOjzFFh1TsnxvI,20
39
- ob_metaflow_extensions-1.1.88.dist-info/RECORD,,
36
+ ob_metaflow_extensions-1.1.90.dist-info/METADATA,sha256=qJ6rqajag4RMd1NlmV8dAPQMjzK2AOchlP_vG_QbDik,520
37
+ ob_metaflow_extensions-1.1.90.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
38
+ ob_metaflow_extensions-1.1.90.dist-info/top_level.txt,sha256=NwG0ukwjygtanDETyp_BUdtYtqIA_lOjzFFh1TsnxvI,20
39
+ ob_metaflow_extensions-1.1.90.dist-info/RECORD,,