modal 1.1.5.dev0__py3-none-any.whl → 1.1.5.dev2__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.
- modal/client.pyi +2 -2
- modal/container_process.py +2 -0
- modal/experimental/flash.py +29 -12
- modal/functions.pyi +6 -6
- modal/io_streams.py +4 -0
- modal/sandbox.py +4 -1
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/METADATA +1 -1
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/RECORD +13 -13
- modal_version/__init__.py +1 -1
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/WHEEL +0 -0
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/entry_points.txt +0 -0
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/licenses/LICENSE +0 -0
- {modal-1.1.5.dev0.dist-info → modal-1.1.5.dev2.dist-info}/top_level.txt +0 -0
modal/client.pyi
CHANGED
@@ -33,7 +33,7 @@ class _Client:
|
|
33
33
|
server_url: str,
|
34
34
|
client_type: int,
|
35
35
|
credentials: typing.Optional[tuple[str, str]],
|
36
|
-
version: str = "1.1.5.
|
36
|
+
version: str = "1.1.5.dev2",
|
37
37
|
):
|
38
38
|
"""mdmd:hidden
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -164,7 +164,7 @@ class Client:
|
|
164
164
|
server_url: str,
|
165
165
|
client_type: int,
|
166
166
|
credentials: typing.Optional[tuple[str, str]],
|
167
|
-
version: str = "1.1.5.
|
167
|
+
version: str = "1.1.5.dev2",
|
168
168
|
):
|
169
169
|
"""mdmd:hidden
|
170
170
|
The Modal client object is not intended to be instantiated directly by users.
|
modal/container_process.py
CHANGED
@@ -10,6 +10,7 @@ from ._utils.async_utils import TaskContext, synchronize_api
|
|
10
10
|
from ._utils.grpc_utils import retry_transient_errors
|
11
11
|
from ._utils.shell_utils import stream_from_stdin, write_to_fd
|
12
12
|
from .client import _Client
|
13
|
+
from .config import logger
|
13
14
|
from .exception import InteractiveTimeoutError, InvalidError
|
14
15
|
from .io_streams import _StreamReader, _StreamWriter
|
15
16
|
from .stream_type import StreamType
|
@@ -136,6 +137,7 @@ class _ContainerProcess(Generic[T]):
|
|
136
137
|
self._returncode = await asyncio.wait_for(self._wait_for_completion(), timeout=timeout)
|
137
138
|
except (asyncio.TimeoutError, TimeoutError):
|
138
139
|
self._returncode = -1
|
140
|
+
logger.debug(f"ContainerProcess {self._process_id} wait completed with returncode {self._returncode}")
|
139
141
|
return self._returncode
|
140
142
|
|
141
143
|
async def attach(self):
|
modal/experimental/flash.py
CHANGED
@@ -337,25 +337,42 @@ class _FlashPrometheusAutoscaler:
|
|
337
337
|
if not internal_metrics_list:
|
338
338
|
return current_replicas
|
339
339
|
|
340
|
-
|
340
|
+
sum_metric = sum(internal_metrics_list)
|
341
|
+
containers_with_metrics = len(internal_metrics_list)
|
342
|
+
# n_containers_missing_metric is the number of unhealthy containers + number of cold starting containers
|
343
|
+
n_containers_missing_metric = current_replicas - containers_with_metrics
|
344
|
+
# n_containers_unhealthy is the number of live containers that are not emitting metrics i.e. unhealthy
|
345
|
+
n_containers_unhealthy = len(containers) - containers_with_metrics
|
346
|
+
|
347
|
+
# Scale up assuming that every unhealthy container is at 2x the target metric value.
|
348
|
+
scale_up_target_metric_value = (sum_metric + n_containers_unhealthy * self.target_metric_value) / (
|
349
|
+
(containers_with_metrics + n_containers_unhealthy) or 1
|
350
|
+
)
|
351
|
+
|
352
|
+
# Scale down assuming that every container (including cold starting containers) are at the target metric value.
|
353
|
+
scale_down_target_metric_value = (sum_metric + n_containers_missing_metric * self.target_metric_value) / (
|
354
|
+
current_replicas or 1
|
355
|
+
)
|
341
356
|
|
342
|
-
|
357
|
+
scale_up_ratio = scale_up_target_metric_value / self.target_metric_value
|
358
|
+
scale_down_ratio = scale_down_target_metric_value / self.target_metric_value
|
343
359
|
|
344
360
|
desired_replicas = current_replicas
|
345
|
-
if
|
346
|
-
desired_replicas = math.ceil(current_replicas *
|
347
|
-
elif
|
348
|
-
desired_replicas = math.ceil(current_replicas *
|
361
|
+
if scale_up_ratio > 1 + self.scale_up_tolerance:
|
362
|
+
desired_replicas = math.ceil(current_replicas * scale_up_ratio)
|
363
|
+
elif scale_down_ratio < 1 - self.scale_down_tolerance:
|
364
|
+
desired_replicas = math.ceil(current_replicas * scale_down_ratio)
|
349
365
|
|
350
366
|
logger.warning(
|
351
367
|
f"[Modal Flash] Current replicas: {current_replicas}, "
|
352
|
-
f"
|
368
|
+
f"sum internal metric `{self.target_metric}`: {sum_metric}, "
|
353
369
|
f"target internal metric value: {self.target_metric_value}, "
|
354
|
-
f"scale
|
370
|
+
f"scale up ratio: {scale_up_ratio}, "
|
371
|
+
f"scale down ratio: {scale_down_ratio}, "
|
355
372
|
f"desired replicas: {desired_replicas}"
|
356
373
|
)
|
357
374
|
|
358
|
-
desired_replicas = max(1, min(desired_replicas, self.max_containers or
|
375
|
+
desired_replicas = max(1, min(desired_replicas, self.max_containers or 5000))
|
359
376
|
return desired_replicas
|
360
377
|
|
361
378
|
async def _compute_target_containers_prometheus(self, current_replicas: int) -> int:
|
@@ -405,9 +422,9 @@ class _FlashPrometheusAutoscaler:
|
|
405
422
|
)
|
406
423
|
|
407
424
|
# Scale down assuming that every container (including cold starting containers) are at the target metric value.
|
408
|
-
scale_down_target_metric_value = (
|
409
|
-
|
410
|
-
)
|
425
|
+
scale_down_target_metric_value = (sum_metric + n_containers_missing_metric * target_metric_value) / (
|
426
|
+
current_replicas or 1
|
427
|
+
)
|
411
428
|
|
412
429
|
scale_up_ratio = scale_up_target_metric_value / target_metric_value
|
413
430
|
scale_down_ratio = scale_down_target_metric_value / target_metric_value
|
modal/functions.pyi
CHANGED
@@ -445,7 +445,7 @@ class Function(
|
|
445
445
|
|
446
446
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
447
447
|
|
448
|
-
class __remote_spec(typing_extensions.Protocol[
|
448
|
+
class __remote_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
449
449
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
450
450
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
451
451
|
...
|
@@ -454,7 +454,7 @@ class Function(
|
|
454
454
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
455
455
|
...
|
456
456
|
|
457
|
-
remote: __remote_spec[modal._functions.
|
457
|
+
remote: __remote_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
458
458
|
|
459
459
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
460
460
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
@@ -481,7 +481,7 @@ class Function(
|
|
481
481
|
"""
|
482
482
|
...
|
483
483
|
|
484
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
484
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
485
485
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
486
486
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
487
487
|
|
@@ -505,7 +505,7 @@ class Function(
|
|
505
505
|
...
|
506
506
|
|
507
507
|
_experimental_spawn: ___experimental_spawn_spec[
|
508
|
-
modal._functions.
|
508
|
+
modal._functions.ReturnType, modal._functions.P, typing_extensions.Self
|
509
509
|
]
|
510
510
|
|
511
511
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
@@ -514,7 +514,7 @@ class Function(
|
|
514
514
|
|
515
515
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
516
516
|
|
517
|
-
class __spawn_spec(typing_extensions.Protocol[
|
517
|
+
class __spawn_spec(typing_extensions.Protocol[ReturnType_INNER, P_INNER, SUPERSELF]):
|
518
518
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
519
519
|
"""Calls the function with the given arguments, without waiting for the results.
|
520
520
|
|
@@ -535,7 +535,7 @@ class Function(
|
|
535
535
|
"""
|
536
536
|
...
|
537
537
|
|
538
|
-
spawn: __spawn_spec[modal._functions.
|
538
|
+
spawn: __spawn_spec[modal._functions.ReturnType, modal._functions.P, typing_extensions.Self]
|
539
539
|
|
540
540
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
541
541
|
"""Return the inner Python object wrapped by this Modal Function."""
|
modal/io_streams.py
CHANGED
@@ -21,6 +21,7 @@ from modal_proto import api_pb2
|
|
21
21
|
from ._utils.async_utils import synchronize_api
|
22
22
|
from ._utils.grpc_utils import RETRYABLE_GRPC_STATUS_CODES, retry_transient_errors
|
23
23
|
from .client import _Client
|
24
|
+
from .config import logger
|
24
25
|
from .stream_type import StreamType
|
25
26
|
|
26
27
|
if TYPE_CHECKING:
|
@@ -180,6 +181,7 @@ class _StreamReader(Generic[T]):
|
|
180
181
|
"""
|
181
182
|
data_str = ""
|
182
183
|
data_bytes = b""
|
184
|
+
logger.debug(f"{self._object_id} StreamReader fd={self._file_descriptor} read starting")
|
183
185
|
async for message in self._get_logs():
|
184
186
|
if message is None:
|
185
187
|
break
|
@@ -188,6 +190,7 @@ class _StreamReader(Generic[T]):
|
|
188
190
|
else:
|
189
191
|
data_bytes += message
|
190
192
|
|
193
|
+
logger.debug(f"{self._object_id} StreamReader fd={self._file_descriptor} read completed after EOF")
|
191
194
|
if self._text:
|
192
195
|
return cast(T, data_str)
|
193
196
|
else:
|
@@ -232,6 +235,7 @@ class _StreamReader(Generic[T]):
|
|
232
235
|
elif isinstance(exc, ClientClosed):
|
233
236
|
# If the client was closed, the user has triggered a cleanup.
|
234
237
|
break
|
238
|
+
logger.error(f"{self._object_id} stream read failure while consuming process output: {exc}")
|
235
239
|
raise exc
|
236
240
|
|
237
241
|
async def _stream_container_process(self) -> AsyncGenerator[tuple[Optional[bytes], str], None]:
|
modal/sandbox.py
CHANGED
@@ -5,6 +5,8 @@ import time
|
|
5
5
|
from collections.abc import AsyncGenerator, Sequence
|
6
6
|
from typing import TYPE_CHECKING, AsyncIterator, Literal, Optional, Union, overload
|
7
7
|
|
8
|
+
from .config import config, logger
|
9
|
+
|
8
10
|
if TYPE_CHECKING:
|
9
11
|
import _typeshed
|
10
12
|
|
@@ -26,7 +28,6 @@ from ._utils.grpc_utils import retry_transient_errors
|
|
26
28
|
from ._utils.mount_utils import validate_network_file_systems, validate_volumes
|
27
29
|
from ._utils.name_utils import is_valid_object_name
|
28
30
|
from .client import _Client
|
29
|
-
from .config import config
|
30
31
|
from .container_process import _ContainerProcess
|
31
32
|
from .exception import AlreadyExistsError, ExecutionError, InvalidError, SandboxTerminatedError, SandboxTimeoutError
|
32
33
|
from .file_io import FileWatchEvent, FileWatchEventType, _FileIO
|
@@ -588,6 +589,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
588
589
|
req = api_pb2.SandboxWaitRequest(sandbox_id=self.object_id, timeout=10)
|
589
590
|
resp = await retry_transient_errors(self._client.stub.SandboxWait, req)
|
590
591
|
if resp.result.status:
|
592
|
+
logger.debug(f"Sandbox {self.object_id} wait completed with status {resp.result.status}")
|
591
593
|
self._result = resp.result
|
592
594
|
|
593
595
|
if resp.result.status == api_pb2.GenericResult.GENERIC_STATUS_TIMEOUT:
|
@@ -757,6 +759,7 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
757
759
|
resp = await retry_transient_errors(self._client.stub.ContainerExec, req)
|
758
760
|
by_line = bufsize == 1
|
759
761
|
exec_deadline = time.monotonic() + int(timeout) + CONTAINER_EXEC_TIMEOUT_BUFFER if timeout else None
|
762
|
+
logger.debug(f"Created ContainerProcess for exec_id {resp.exec_id} on Sandbox {self.object_id}")
|
760
763
|
return _ContainerProcess(
|
761
764
|
resp.exec_id,
|
762
765
|
self._client,
|
@@ -22,13 +22,13 @@ modal/app.py,sha256=F4baVULljFq0CwC_7U-EKNRNx7CYeWBKudjjYUuWc4U,48416
|
|
22
22
|
modal/app.pyi,sha256=AbXJCBkyt2rI_-M3VbTBYb32at0P6iRZuoC87xY_JrQ,43591
|
23
23
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
24
24
|
modal/client.py,sha256=kyAIVB3Ay-XKJizQ_1ufUFB__EagV0MLmHJpyYyJ7J0,18636
|
25
|
-
modal/client.pyi,sha256=
|
25
|
+
modal/client.pyi,sha256=hJfIJH60sX3D2zzwpVGIdUjFeh0YYNyJZCIagvmVLc8,15829
|
26
26
|
modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
|
27
27
|
modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
|
28
28
|
modal/cls.py,sha256=pTEO7pHjlO7taMbIqs4oI9ZZgKDJpVKyGkO5ZT0w6tQ,40934
|
29
29
|
modal/cls.pyi,sha256=C1eK-AkN-QaeXu0qmMZVgJmkb1tYAFS43iEG37takDs,28959
|
30
30
|
modal/config.py,sha256=tW-SEGjVvAt3D_MNi3LhxXnFKIA9fjLd3UIgbW8uSJE,12121
|
31
|
-
modal/container_process.py,sha256=
|
31
|
+
modal/container_process.py,sha256=Mutkl7sg_WR5zP4oJiWSC-3UdYRqp0zdKi1shZbi-bk,6996
|
32
32
|
modal/container_process.pyi,sha256=9m-st3hCUlNN1GOTctfPPvIvoLtEl7FbuGWwif5-7YU,6037
|
33
33
|
modal/dict.py,sha256=azL6WHOAR49OsqB33Rqyd1j9ljbbW7blHZDuRV8xPrA,22676
|
34
34
|
modal/dict.pyi,sha256=x0PxEqfC8wNGe5u4Y1GI5W1J0H51e3ZG9kHdYFRVLvQ,33575
|
@@ -39,11 +39,11 @@ modal/file_io.py,sha256=OSKr77TujcXGJW1iikzYiHckLSmv07QBgBHcxxYEkoI,21456
|
|
39
39
|
modal/file_io.pyi,sha256=xtO6Glf_BFwDE7QiQQo24QqcMf_Vv-iz7WojcGVlLBU,15932
|
40
40
|
modal/file_pattern_matcher.py,sha256=A_Kdkej6q7YQyhM_2-BvpFmPqJ0oHb54B6yf9VqvPVE,8116
|
41
41
|
modal/functions.py,sha256=kcNHvqeGBxPI7Cgd57NIBBghkfbeFJzXO44WW0jSmao,325
|
42
|
-
modal/functions.pyi,sha256=
|
42
|
+
modal/functions.pyi,sha256=cDqhpIM5caoCR18_8krpAmPOd4QvEbm1ypYUZ6Ze9Wo,39404
|
43
43
|
modal/gpu.py,sha256=Fe5ORvVPDIstSq1xjmM6OoNgLYFWvogP9r5BgmD3hYg,6769
|
44
44
|
modal/image.py,sha256=nXN9k_6gApHFy8-Bk_XT2Zu3jsDsGVrC3QcuiDC4yRY,103543
|
45
45
|
modal/image.pyi,sha256=vKdb5PpYM8wcpq9PQegeVMjrPLzAipuV4q994NZiL84,69325
|
46
|
-
modal/io_streams.py,sha256=
|
46
|
+
modal/io_streams.py,sha256=hZOVc5beOAm8S_VQQmmKUbk_BJ9OltN83RY0yMPqUDo,16545
|
47
47
|
modal/io_streams.pyi,sha256=aOun_jUFKHSJyUY6-7gKvNoxzcULsa8_hxdtEO7v-gk,13980
|
48
48
|
modal/mount.py,sha256=3WpYaaCBGLyawW2uhQzB4jXRBQEsuuRMxnCFsXSa9_k,37470
|
49
49
|
modal/mount.pyi,sha256=y4jbfYwvD4NsLIxP8i0sua_98kNRPk1w1YlRiHqgrdo,20580
|
@@ -65,7 +65,7 @@ modal/retries.py,sha256=IvNLDM0f_GLUDD5VgEDoN09C88yoxSrCquinAuxT1Sc,5205
|
|
65
65
|
modal/runner.py,sha256=ostdzYpQb-20tlD6dIq7bpWTkZkOhjJBNuMNektqnJA,24068
|
66
66
|
modal/runner.pyi,sha256=lbwLljm1cC8d6PcNvmYQhkE8501V9fg0bYqqKX6G4r4,8489
|
67
67
|
modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
|
68
|
-
modal/sandbox.py,sha256=
|
68
|
+
modal/sandbox.py,sha256=BDjFvr_rp67W5WGoGvV47uBPVsmp3yceoCqqHAGLFwg,42384
|
69
69
|
modal/sandbox.pyi,sha256=mOyungHDDmUrg7jLmJpWuoUEbA4z6TUaVx291hndPmI,42049
|
70
70
|
modal/schedule.py,sha256=ng0g0AqNY5GQI9KhkXZQ5Wam5G42glbkqVQsNpBtbDE,3078
|
71
71
|
modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
|
@@ -150,10 +150,10 @@ modal/cli/programs/run_jupyter.py,sha256=44Lpvqk2l3hH-uOkmAOzw60NEsfB5uaRDWDKVsh
|
|
150
150
|
modal/cli/programs/run_marimo.py,sha256=HyZ2za0NYqg31-mGxFQxUIAJ3Q-jRaMocEwWwI5-cdw,2887
|
151
151
|
modal/cli/programs/vscode.py,sha256=KbTAaIXyQBVCDXxXjmBHmKpgXkUw0q4R4KkJvUjCYgk,3380
|
152
152
|
modal/experimental/__init__.py,sha256=fCqzo_f3vcY750vHtd7CtLs5dvdM_C0ZLLGb3zXuK9w,14913
|
153
|
-
modal/experimental/flash.py,sha256=
|
153
|
+
modal/experimental/flash.py,sha256=dPTB1k2H72dsq3TuEFs2WAxrU8y5n-SoJzZ4AXVMdZs,28287
|
154
154
|
modal/experimental/flash.pyi,sha256=32bvUlolZHthplDJNXokmbjwb0RSOuXGCBpU6qfFPOk,13732
|
155
155
|
modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
|
156
|
-
modal-1.1.5.
|
156
|
+
modal-1.1.5.dev2.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
157
157
|
modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
|
158
158
|
modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
|
159
159
|
modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
|
@@ -176,10 +176,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
|
|
176
176
|
modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
|
177
177
|
modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
|
178
178
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
179
|
-
modal_version/__init__.py,sha256=
|
179
|
+
modal_version/__init__.py,sha256=7xr5x1fR3u8HehALlYaPVtqFIs1N4jX9fmYOu7qKObo,120
|
180
180
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
181
|
-
modal-1.1.5.
|
182
|
-
modal-1.1.5.
|
183
|
-
modal-1.1.5.
|
184
|
-
modal-1.1.5.
|
185
|
-
modal-1.1.5.
|
181
|
+
modal-1.1.5.dev2.dist-info/METADATA,sha256=w5lDiGuDQkQMzeJaXCB77cmJTdB5sznIbfgyqDSJG_0,2459
|
182
|
+
modal-1.1.5.dev2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
183
|
+
modal-1.1.5.dev2.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
184
|
+
modal-1.1.5.dev2.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
|
185
|
+
modal-1.1.5.dev2.dist-info/RECORD,,
|
modal_version/__init__.py
CHANGED
File without changes
|
File without changes
|
File without changes
|
File without changes
|