modal 0.66.44__py3-none-any.whl → 0.66.48__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/app.py +39 -24
- modal/app.pyi +4 -2
- modal/cli/import_refs.py +1 -1
- modal/cli/launch.py +6 -4
- modal/cli/run.py +2 -2
- modal/client.pyi +2 -2
- modal/runner.py +12 -6
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/METADATA +1 -1
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/RECORD +14 -14
- modal_version/_version_generated.py +1 -1
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/LICENSE +0 -0
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/WHEEL +0 -0
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/entry_points.txt +0 -0
- {modal-0.66.44.dist-info → modal-0.66.48.dist-info}/top_level.txt +0 -0
modal/app.py
CHANGED
@@ -177,7 +177,8 @@ class _App:
|
|
177
177
|
|
178
178
|
_name: Optional[str]
|
179
179
|
_description: Optional[str]
|
180
|
-
|
180
|
+
_functions: Dict[str, _Function]
|
181
|
+
_classes: Dict[str, _Cls]
|
181
182
|
|
182
183
|
_image: Optional[_Image]
|
183
184
|
_mounts: Sequence[_Mount]
|
@@ -223,7 +224,8 @@ class _App:
|
|
223
224
|
if image is not None and not isinstance(image, _Image):
|
224
225
|
raise InvalidError("image has to be a modal Image or AioImage object")
|
225
226
|
|
226
|
-
self.
|
227
|
+
self._functions = {}
|
228
|
+
self._classes = {}
|
227
229
|
self._image = image
|
228
230
|
self._mounts = mounts
|
229
231
|
self._secrets = secrets
|
@@ -312,6 +314,7 @@ class _App:
|
|
312
314
|
raise InvalidError(f"App attribute `{key}` with value {value!r} is not a valid Modal object")
|
313
315
|
|
314
316
|
def _add_object(self, tag, obj):
|
317
|
+
# TODO(erikbern): replace this with _add_function and _add_class
|
315
318
|
if self._running_app:
|
316
319
|
# If this is inside a container, then objects can be defined after app initialization.
|
317
320
|
# So we may have to initialize objects once they get bound to the app.
|
@@ -320,7 +323,12 @@ class _App:
|
|
320
323
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
321
324
|
obj._hydrate(object_id, self._client, metadata)
|
322
325
|
|
323
|
-
|
326
|
+
if isinstance(obj, _Function):
|
327
|
+
self._functions[tag] = obj
|
328
|
+
elif isinstance(obj, _Cls):
|
329
|
+
self._classes[tag] = obj
|
330
|
+
else:
|
331
|
+
raise RuntimeError(f"Expected `obj` to be a _Function or _Cls (got {type(obj)}")
|
324
332
|
|
325
333
|
def __getitem__(self, tag: str):
|
326
334
|
deprecation_error((2024, 3, 25), _app_attr_error)
|
@@ -334,7 +342,7 @@ class _App:
|
|
334
342
|
if tag.startswith("__"):
|
335
343
|
# Hacky way to avoid certain issues, e.g. pickle will try to look this up
|
336
344
|
raise AttributeError(f"App has no member {tag}")
|
337
|
-
if tag not in self.
|
345
|
+
if tag not in self._functions or tag not in self._classes:
|
338
346
|
# Primarily to make hasattr work
|
339
347
|
raise AttributeError(f"App has no member {tag}")
|
340
348
|
deprecation_error((2024, 3, 25), _app_attr_error)
|
@@ -360,7 +368,9 @@ class _App:
|
|
360
368
|
|
361
369
|
def _uncreate_all_objects(self):
|
362
370
|
# TODO(erikbern): this doesn't unhydrate objects that aren't tagged
|
363
|
-
for obj in self.
|
371
|
+
for obj in self._functions.values():
|
372
|
+
obj._unhydrate()
|
373
|
+
for obj in self._classes.values():
|
364
374
|
obj._unhydrate()
|
365
375
|
|
366
376
|
@asynccontextmanager
|
@@ -459,18 +469,17 @@ class _App:
|
|
459
469
|
return [m for m in all_mounts if m.is_local()]
|
460
470
|
|
461
471
|
def _add_function(self, function: _Function, is_web_endpoint: bool):
|
462
|
-
if function.tag in self.
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
logger.warning(f"Warning: tag {function.tag} exists but is overridden by function")
|
472
|
+
if function.tag in self._functions:
|
473
|
+
if not is_notebook():
|
474
|
+
old_function: _Function = self._functions[function.tag]
|
475
|
+
logger.warning(
|
476
|
+
f"Warning: Tag '{function.tag}' collision!"
|
477
|
+
" Overriding existing function "
|
478
|
+
f"[{old_function._info.module_name}].{old_function._info.function_name}"
|
479
|
+
f" with new function [{function._info.module_name}].{function._info.function_name}"
|
480
|
+
)
|
481
|
+
if function.tag in self._classes:
|
482
|
+
logger.warning(f"Warning: tag {function.tag} exists but is overridden by function")
|
474
483
|
|
475
484
|
self._add_object(function.tag, function)
|
476
485
|
if is_web_endpoint:
|
@@ -484,21 +493,22 @@ class _App:
|
|
484
493
|
_App._container_app = running_app
|
485
494
|
|
486
495
|
# Hydrate objects on app
|
496
|
+
indexed_objects = dict(**self._functions, **self._classes)
|
487
497
|
for tag, object_id in running_app.tag_to_object_id.items():
|
488
|
-
if tag in
|
489
|
-
obj =
|
498
|
+
if tag in indexed_objects:
|
499
|
+
obj = indexed_objects[tag]
|
490
500
|
handle_metadata = running_app.object_handle_metadata[object_id]
|
491
501
|
obj._hydrate(object_id, client, handle_metadata)
|
492
502
|
|
493
503
|
@property
|
494
504
|
def registered_functions(self) -> Dict[str, _Function]:
|
495
505
|
"""All modal.Function objects registered on the app."""
|
496
|
-
return
|
506
|
+
return self._functions
|
497
507
|
|
498
508
|
@property
|
499
509
|
def registered_classes(self) -> Dict[str, _Function]:
|
500
510
|
"""All modal.Cls objects registered on the app."""
|
501
|
-
return
|
511
|
+
return self._classes
|
502
512
|
|
503
513
|
@property
|
504
514
|
def registered_entrypoints(self) -> Dict[str, _LocalEntrypoint]:
|
@@ -507,7 +517,11 @@ class _App:
|
|
507
517
|
|
508
518
|
@property
|
509
519
|
def indexed_objects(self) -> Dict[str, _Object]:
|
510
|
-
|
520
|
+
deprecation_warning(
|
521
|
+
(2024, 11, 25),
|
522
|
+
"`app.indexed_objects` is deprecated! Use `app.registered_functions` or `app.registered_classes` instead.",
|
523
|
+
)
|
524
|
+
return dict(**self._functions, **self._classes)
|
511
525
|
|
512
526
|
@property
|
513
527
|
def registered_web_endpoints(self) -> List[str]:
|
@@ -1002,8 +1016,9 @@ class _App:
|
|
1002
1016
|
bar.remote()
|
1003
1017
|
```
|
1004
1018
|
"""
|
1005
|
-
|
1006
|
-
|
1019
|
+
indexed_objects = dict(**other_app._functions, **other_app._classes)
|
1020
|
+
for tag, object in indexed_objects.items():
|
1021
|
+
existing_object = indexed_objects.get(tag)
|
1007
1022
|
if existing_object and existing_object != object:
|
1008
1023
|
logger.warning(
|
1009
1024
|
f"Named app object {tag} with existing value {existing_object} is being "
|
modal/app.pyi
CHANGED
@@ -76,7 +76,8 @@ class _App:
|
|
76
76
|
_container_app: typing.ClassVar[typing.Optional[modal.running_app.RunningApp]]
|
77
77
|
_name: typing.Optional[str]
|
78
78
|
_description: typing.Optional[str]
|
79
|
-
|
79
|
+
_functions: typing.Dict[str, modal.functions._Function]
|
80
|
+
_classes: typing.Dict[str, modal.cls._Cls]
|
80
81
|
_image: typing.Optional[modal.image._Image]
|
81
82
|
_mounts: typing.Sequence[modal.mount._Mount]
|
82
83
|
_secrets: typing.Sequence[modal.secret._Secret]
|
@@ -270,7 +271,8 @@ class App:
|
|
270
271
|
_container_app: typing.ClassVar[typing.Optional[modal.running_app.RunningApp]]
|
271
272
|
_name: typing.Optional[str]
|
272
273
|
_description: typing.Optional[str]
|
273
|
-
|
274
|
+
_functions: typing.Dict[str, modal.functions.Function]
|
275
|
+
_classes: typing.Dict[str, modal.cls.Cls]
|
274
276
|
_image: typing.Optional[modal.image.Image]
|
275
277
|
_mounts: typing.Sequence[modal.mount.Mount]
|
276
278
|
_secrets: typing.Sequence[modal.secret.Secret]
|
modal/cli/import_refs.py
CHANGED
@@ -154,7 +154,7 @@ Registered functions and local entrypoints on the selected app are:
|
|
154
154
|
# entrypoint is in entrypoint registry, for now
|
155
155
|
return app.registered_entrypoints[function_name]
|
156
156
|
|
157
|
-
function = app.
|
157
|
+
function = app.registered_functions[function_name]
|
158
158
|
assert isinstance(function, Function)
|
159
159
|
return function
|
160
160
|
|
modal/cli/launch.py
CHANGED
@@ -25,7 +25,7 @@ launch_cli = Typer(
|
|
25
25
|
)
|
26
26
|
|
27
27
|
|
28
|
-
def _launch_program(name: str, filename: str, args: Dict[str, Any]) -> None:
|
28
|
+
def _launch_program(name: str, filename: str, detach: bool, args: Dict[str, Any]) -> None:
|
29
29
|
os.environ["MODAL_LAUNCH_ARGS"] = json.dumps(args)
|
30
30
|
|
31
31
|
program_path = str(Path(__file__).parent / "programs" / filename)
|
@@ -37,7 +37,7 @@ def _launch_program(name: str, filename: str, args: Dict[str, Any]) -> None:
|
|
37
37
|
func = entrypoint.info.raw_f
|
38
38
|
isasync = inspect.iscoroutinefunction(func)
|
39
39
|
with enable_output():
|
40
|
-
with run_app(app):
|
40
|
+
with run_app(app, detach=detach):
|
41
41
|
try:
|
42
42
|
if isasync:
|
43
43
|
asyncio.run(func())
|
@@ -57,6 +57,7 @@ def jupyter(
|
|
57
57
|
add_python: Optional[str] = "3.11",
|
58
58
|
mount: Optional[str] = None, # Create a `modal.Mount` from a local directory.
|
59
59
|
volume: Optional[str] = None, # Attach a persisted `modal.Volume` by name (creating if missing).
|
60
|
+
detach: bool = False, # Run the app in "detached" mode to persist after local client disconnects
|
60
61
|
):
|
61
62
|
args = {
|
62
63
|
"cpu": cpu,
|
@@ -68,7 +69,7 @@ def jupyter(
|
|
68
69
|
"mount": mount,
|
69
70
|
"volume": volume,
|
70
71
|
}
|
71
|
-
_launch_program("jupyter", "run_jupyter.py", args)
|
72
|
+
_launch_program("jupyter", "run_jupyter.py", detach, args)
|
72
73
|
|
73
74
|
|
74
75
|
@launch_cli.command(name="vscode", help="Start Visual Studio Code on Modal.")
|
@@ -79,6 +80,7 @@ def vscode(
|
|
79
80
|
timeout: int = 3600,
|
80
81
|
mount: Optional[str] = None, # Create a `modal.Mount` from a local directory.
|
81
82
|
volume: Optional[str] = None, # Attach a persisted `modal.Volume` by name (creating if missing).
|
83
|
+
detach: bool = False, # Run the app in "detached" mode to persist after local client disconnects
|
82
84
|
):
|
83
85
|
args = {
|
84
86
|
"cpu": cpu,
|
@@ -88,4 +90,4 @@ def vscode(
|
|
88
90
|
"mount": mount,
|
89
91
|
"volume": volume,
|
90
92
|
}
|
91
|
-
_launch_program("vscode", "vscode.py", args)
|
93
|
+
_launch_program("vscode", "vscode.py", detach, args)
|
modal/cli/run.py
CHANGED
@@ -136,7 +136,7 @@ def _get_clean_app_description(func_ref: str) -> str:
|
|
136
136
|
|
137
137
|
|
138
138
|
def _get_click_command_for_function(app: App, function_tag):
|
139
|
-
function = app.
|
139
|
+
function = app.registered_functions[function_tag]
|
140
140
|
assert isinstance(function, Function)
|
141
141
|
function = typing.cast(Function, function)
|
142
142
|
if function.is_generator:
|
@@ -147,7 +147,7 @@ def _get_click_command_for_function(app: App, function_tag):
|
|
147
147
|
method_name: Optional[str] = None
|
148
148
|
if function.info.user_cls is not None:
|
149
149
|
class_name, method_name = function_tag.rsplit(".", 1)
|
150
|
-
cls = typing.cast(Cls, app.
|
150
|
+
cls = typing.cast(Cls, app.registered_classes[class_name])
|
151
151
|
cls_signature = _get_signature(function.info.user_cls)
|
152
152
|
fun_signature = _get_signature(function.info.raw_f, is_method=True)
|
153
153
|
signature = dict(**cls_signature, **fun_signature) # Pool all arguments
|
modal/client.pyi
CHANGED
@@ -31,7 +31,7 @@ class _Client:
|
|
31
31
|
server_url: str,
|
32
32
|
client_type: int,
|
33
33
|
credentials: typing.Optional[typing.Tuple[str, str]],
|
34
|
-
version: str = "0.66.
|
34
|
+
version: str = "0.66.48",
|
35
35
|
): ...
|
36
36
|
def is_closed(self) -> bool: ...
|
37
37
|
@property
|
@@ -90,7 +90,7 @@ class Client:
|
|
90
90
|
server_url: str,
|
91
91
|
client_type: int,
|
92
92
|
credentials: typing.Optional[typing.Tuple[str, str]],
|
93
|
-
version: str = "0.66.
|
93
|
+
version: str = "0.66.48",
|
94
94
|
): ...
|
95
95
|
def is_closed(self) -> bool: ...
|
96
96
|
@property
|
modal/runner.py
CHANGED
@@ -327,11 +327,13 @@ async def _run_app(
|
|
327
327
|
)
|
328
328
|
|
329
329
|
try:
|
330
|
+
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
331
|
+
|
330
332
|
# Create all members
|
331
|
-
await _create_all_objects(client, running_app,
|
333
|
+
await _create_all_objects(client, running_app, indexed_objects, environment_name)
|
332
334
|
|
333
335
|
# Publish the app
|
334
|
-
await _publish_app(client, running_app, app_state,
|
336
|
+
await _publish_app(client, running_app, app_state, indexed_objects)
|
335
337
|
except asyncio.CancelledError as e:
|
336
338
|
# this typically happens on sigint/ctrl-C during setup (the KeyboardInterrupt happens in the main thread)
|
337
339
|
if output_mgr := _get_output_manager():
|
@@ -424,16 +426,18 @@ async def _serve_update(
|
|
424
426
|
try:
|
425
427
|
running_app: RunningApp = await _init_local_app_existing(client, existing_app_id, environment_name)
|
426
428
|
|
429
|
+
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
430
|
+
|
427
431
|
# Create objects
|
428
432
|
await _create_all_objects(
|
429
433
|
client,
|
430
434
|
running_app,
|
431
|
-
|
435
|
+
indexed_objects,
|
432
436
|
environment_name,
|
433
437
|
)
|
434
438
|
|
435
439
|
# Publish the updated app
|
436
|
-
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED,
|
440
|
+
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED, indexed_objects)
|
437
441
|
|
438
442
|
# Communicate to the parent process
|
439
443
|
is_ready.set()
|
@@ -521,17 +525,19 @@ async def _deploy_app(
|
|
521
525
|
|
522
526
|
tc.infinite_loop(heartbeat, sleep=HEARTBEAT_INTERVAL)
|
523
527
|
|
528
|
+
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
529
|
+
|
524
530
|
try:
|
525
531
|
# Create all members
|
526
532
|
await _create_all_objects(
|
527
533
|
client,
|
528
534
|
running_app,
|
529
|
-
|
535
|
+
indexed_objects,
|
530
536
|
environment_name=environment_name,
|
531
537
|
)
|
532
538
|
|
533
539
|
app_url, warnings = await _publish_app(
|
534
|
-
client, running_app, api_pb2.APP_STATE_DEPLOYED,
|
540
|
+
client, running_app, api_pb2.APP_STATE_DEPLOYED, indexed_objects, name, tag
|
535
541
|
)
|
536
542
|
except Exception as e:
|
537
543
|
# Note that AppClientDisconnect only stops the app if it's still initializing, and is a no-op otherwise.
|
@@ -15,11 +15,11 @@ modal/_traceback.py,sha256=1yNp1Dqq4qRIQp8idDp5PEqjwH4eA8MNI0FhFkCOFgo,4408
|
|
15
15
|
modal/_tunnel.py,sha256=SVmQxGbV7dcLwyY9eB2PIWmXw8QQmcKg2ppTcRQgZrU,6283
|
16
16
|
modal/_tunnel.pyi,sha256=SA_Q0UGB-D9skFjv6CqlTnCEWU67a2xJxfwVdXtar3Y,1259
|
17
17
|
modal/_watcher.py,sha256=STlDe73R7IS33a_GMW2HnDc3hCDKLdsBfMxRpVh-flA,3581
|
18
|
-
modal/app.py,sha256=
|
19
|
-
modal/app.pyi,sha256=
|
18
|
+
modal/app.py,sha256=ZQux8ZGLblIWbKHn7s15mucx97EwbjJso9WKRTYYOf0,45208
|
19
|
+
modal/app.pyi,sha256=sX2BXX_178lp8O_GvwZqsxDdxQi1j3DjNfthMvlMlJU,25273
|
20
20
|
modal/call_graph.py,sha256=l-Wi6vM8aosCdHTWegcCyGeVJGFdZ_fzlCmbRVPBXFI,2593
|
21
21
|
modal/client.py,sha256=4SpWb4n0nolITR36kADZl1tYLOg6avukmzZU56UQjCo,16385
|
22
|
-
modal/client.pyi,sha256=
|
22
|
+
modal/client.pyi,sha256=OwqZyJGr-WduAK8NsbCxSz_xwD-Cl157xm6h4LFumWc,7372
|
23
23
|
modal/cloud_bucket_mount.py,sha256=eWQhCtMIczpokjfTZEgNBCGO_s5ft46PqTSLfKBykq4,5748
|
24
24
|
modal/cloud_bucket_mount.pyi,sha256=tTF7M4FR9bTA30cFkz8qq3ZTlFL19NHU_36e_5GgAGA,1424
|
25
25
|
modal/cls.py,sha256=apKnBOHKYEpBiMC8mRvHtCDJl1g0vP0tG1r8mUZ1yH0,24684
|
@@ -57,7 +57,7 @@ modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
57
|
modal/queue.py,sha256=qCBE-V2QRl_taSDUR5bDJL91J0A8xwbTxfEU3taA4Es,18338
|
58
58
|
modal/queue.pyi,sha256=t5yhDqXRtexy7AVraCexPyT6Xo3QA_H5OxVe_JLzTps,9999
|
59
59
|
modal/retries.py,sha256=z4dYXdksUcjkefM3vGLkhCQ_m_TUPLJgC4uSYDzWSOU,3750
|
60
|
-
modal/runner.py,sha256=
|
60
|
+
modal/runner.py,sha256=oCyAB0cPqHi9fzkbmnccwhCpUYFXMiy0_zjomMnCzDI,24055
|
61
61
|
modal/runner.pyi,sha256=b2qoID4HO-ww6Q0jdboR9iCTxVWTzGiC2taIx7kA-U0,5135
|
62
62
|
modal/running_app.py,sha256=AhWWCB16_k5R80oQxEVSNrmRq3fVInUCxtXKrAvcEPQ,566
|
63
63
|
modal/sandbox.py,sha256=_7_sqTrEiC2zFo1XN7UCHA1L9NFXj6Kb6xu6Ecfancg,24878
|
@@ -108,12 +108,12 @@ modal/cli/container.py,sha256=LGrF9iz8D3PGst6IUl0VB1Y1LJ0BWLrNRNFxWa4z-tg,3199
|
|
108
108
|
modal/cli/dict.py,sha256=lIEl6uxygFt3omC-oF6tHUxnFjVhy4d0InC_kZrlkvM,4454
|
109
109
|
modal/cli/entry_point.py,sha256=aaNxFAqZcmtSjwzkYIA_Ba9CkL4cL4_i2gy5VjoXxkM,4228
|
110
110
|
modal/cli/environment.py,sha256=eq8Rixbo8u-nJPvtGwW4-I1lXZPnevsFEv65WlSxFXY,4362
|
111
|
-
modal/cli/import_refs.py,sha256=
|
112
|
-
modal/cli/launch.py,sha256=
|
111
|
+
modal/cli/import_refs.py,sha256=wVJFeKeQinNk7NAm3ixVEal-7x2Nf-Ryv8IO6kpjaZ8,9242
|
112
|
+
modal/cli/launch.py,sha256=FgZ0L-e3dLl9vRJ_IVHfSRUzCbmdyS8-u_abC42tTDo,2941
|
113
113
|
modal/cli/network_file_system.py,sha256=p_o3wu8rh2tjHXJYrjaad__pD8hv93ypeDtfSY2fSEU,7527
|
114
114
|
modal/cli/profile.py,sha256=s4jCYHwriOorEFCKxeGZoSWX8rXTR_hDTNFZhOA565s,3109
|
115
115
|
modal/cli/queues.py,sha256=mJ44A319sPIrysH3A0HCIz4Or0jFey6miiuQKZoEQxo,4493
|
116
|
-
modal/cli/run.py,sha256=
|
116
|
+
modal/cli/run.py,sha256=cQKxmvwh6gcp53-BA7LtD8TDKb7gSducN73K0IDS4ok,16296
|
117
117
|
modal/cli/secret.py,sha256=GWz425Fhdftb2hDljQzO2NS1NY5ogg298Uu-e0JAQWs,4211
|
118
118
|
modal/cli/token.py,sha256=mxSgOWakXG6N71hQb1ko61XAR9ZGkTMZD-Txn7gmTac,1924
|
119
119
|
modal/cli/utils.py,sha256=59-cqBHSg00oFMRHtRbFZZnoIJfW6w9Gfno63XfNpt4,3633
|
@@ -159,10 +159,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
|
|
159
159
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
160
160
|
modal_version/__init__.py,sha256=UnAuHBPuPSstqgdCOx0SBVdfhpeJnMlY_oxEbu44Izg,470
|
161
161
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
162
|
-
modal_version/_version_generated.py,sha256=
|
163
|
-
modal-0.66.
|
164
|
-
modal-0.66.
|
165
|
-
modal-0.66.
|
166
|
-
modal-0.66.
|
167
|
-
modal-0.66.
|
168
|
-
modal-0.66.
|
162
|
+
modal_version/_version_generated.py,sha256=s6ccZZ3yL2JQUo8MQ7AFG_3X3ISxs4x-0mV2G2TxRoI,149
|
163
|
+
modal-0.66.48.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
164
|
+
modal-0.66.48.dist-info/METADATA,sha256=Atopb7dtPHi9exqYvy9KBIVNFr02eYy-7RqJ6yc2_L0,2329
|
165
|
+
modal-0.66.48.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
166
|
+
modal-0.66.48.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
167
|
+
modal-0.66.48.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
|
168
|
+
modal-0.66.48.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|