modal 0.70.2__py3-none-any.whl → 0.70.3__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 +15 -15
- modal/client.pyi +2 -2
- modal/runner.py +26 -30
- modal/runner.pyi +6 -3
- modal/running_app.py +4 -3
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/METADATA +1 -1
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/RECORD +12 -12
- modal_version/_version_generated.py +1 -1
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/LICENSE +0 -0
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/WHEEL +0 -0
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/entry_points.txt +0 -0
- {modal-0.70.2.dist-info → modal-0.70.3.dist-info}/top_level.txt +0 -0
modal/app.py
CHANGED
@@ -463,8 +463,8 @@ class _App:
|
|
463
463
|
if self._running_app:
|
464
464
|
# If this is inside a container, then objects can be defined after app initialization.
|
465
465
|
# So we may have to initialize objects once they get bound to the app.
|
466
|
-
if function.tag in self._running_app.
|
467
|
-
object_id: str = self._running_app.
|
466
|
+
if function.tag in self._running_app.function_ids:
|
467
|
+
object_id: str = self._running_app.function_ids[function.tag]
|
468
468
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
469
469
|
function._hydrate(object_id, self._client, metadata)
|
470
470
|
|
@@ -476,8 +476,8 @@ class _App:
|
|
476
476
|
if self._running_app:
|
477
477
|
# If this is inside a container, then objects can be defined after app initialization.
|
478
478
|
# So we may have to initialize objects once they get bound to the app.
|
479
|
-
if tag in self._running_app.
|
480
|
-
object_id: str = self._running_app.
|
479
|
+
if tag in self._running_app.class_ids:
|
480
|
+
object_id: str = self._running_app.class_ids[tag]
|
481
481
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
482
482
|
cls._hydrate(object_id, self._client, metadata)
|
483
483
|
|
@@ -490,19 +490,19 @@ class _App:
|
|
490
490
|
|
491
491
|
_App._container_app = running_app
|
492
492
|
|
493
|
-
# Hydrate objects on app -- hydrating functions first so that when a class is being hydrated its
|
494
|
-
# corresponding class service function is already hydrated.
|
495
|
-
def hydrate_objects(objects_dict):
|
496
|
-
for tag, object_id in running_app.tag_to_object_id.items():
|
497
|
-
if tag in objects_dict:
|
498
|
-
obj = objects_dict[tag]
|
499
|
-
handle_metadata = running_app.object_handle_metadata[object_id]
|
500
|
-
obj._hydrate(object_id, client, handle_metadata)
|
501
|
-
|
502
493
|
# Hydrate function objects
|
503
|
-
|
494
|
+
for tag, object_id in running_app.function_ids.items():
|
495
|
+
if tag in self._functions:
|
496
|
+
obj = self._functions[tag]
|
497
|
+
handle_metadata = running_app.object_handle_metadata[object_id]
|
498
|
+
obj._hydrate(object_id, client, handle_metadata)
|
499
|
+
|
504
500
|
# Hydrate class objects
|
505
|
-
|
501
|
+
for tag, object_id in running_app.class_ids.items():
|
502
|
+
if tag in self._classes:
|
503
|
+
obj = self._classes[tag]
|
504
|
+
handle_metadata = running_app.object_handle_metadata[object_id]
|
505
|
+
obj._hydrate(object_id, client, handle_metadata)
|
506
506
|
|
507
507
|
@property
|
508
508
|
def registered_functions(self) -> dict[str, _Function]:
|
modal/client.pyi
CHANGED
@@ -26,7 +26,7 @@ class _Client:
|
|
26
26
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
27
27
|
|
28
28
|
def __init__(
|
29
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.70.
|
29
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.70.3"
|
30
30
|
): ...
|
31
31
|
def is_closed(self) -> bool: ...
|
32
32
|
@property
|
@@ -81,7 +81,7 @@ class Client:
|
|
81
81
|
_stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
|
82
82
|
|
83
83
|
def __init__(
|
84
|
-
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.70.
|
84
|
+
self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.70.3"
|
85
85
|
): ...
|
86
86
|
def is_closed(self) -> bool: ...
|
87
87
|
@property
|
modal/runner.py
CHANGED
@@ -6,7 +6,7 @@ import time
|
|
6
6
|
import typing
|
7
7
|
from collections.abc import AsyncGenerator
|
8
8
|
from multiprocessing.synchronize import Event
|
9
|
-
from typing import TYPE_CHECKING, Any,
|
9
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar
|
10
10
|
|
11
11
|
from grpclib import GRPCError, Status
|
12
12
|
from synchronicity.async_wrap import asynccontextmanager
|
@@ -124,10 +124,12 @@ async def _init_local_app_from_name(
|
|
124
124
|
async def _create_all_objects(
|
125
125
|
client: _Client,
|
126
126
|
running_app: RunningApp,
|
127
|
-
|
127
|
+
functions: dict[str, _Function],
|
128
|
+
classes: dict[str, _Cls],
|
128
129
|
environment_name: str,
|
129
130
|
) -> None:
|
130
131
|
"""Create objects that have been defined but not created on the server."""
|
132
|
+
indexed_objects: dict[str, _Object] = {**functions, **classes}
|
131
133
|
resolver = Resolver(
|
132
134
|
client,
|
133
135
|
environment_name=environment_name,
|
@@ -135,8 +137,9 @@ async def _create_all_objects(
|
|
135
137
|
)
|
136
138
|
with resolver.display():
|
137
139
|
# Get current objects, and reset all objects
|
138
|
-
tag_to_object_id = running_app.
|
139
|
-
running_app.
|
140
|
+
tag_to_object_id = {**running_app.function_ids, **running_app.class_ids}
|
141
|
+
running_app.function_ids = {}
|
142
|
+
running_app.class_ids = {}
|
140
143
|
|
141
144
|
# Assign all objects
|
142
145
|
for tag, obj in indexed_objects.items():
|
@@ -163,7 +166,12 @@ async def _create_all_objects(
|
|
163
166
|
async def _load(tag, obj):
|
164
167
|
existing_object_id = tag_to_object_id.get(tag)
|
165
168
|
await resolver.load(obj, existing_object_id)
|
166
|
-
|
169
|
+
if _Function._is_id_type(obj.object_id):
|
170
|
+
running_app.function_ids[tag] = obj.object_id
|
171
|
+
elif _Cls._is_id_type(obj.object_id):
|
172
|
+
running_app.class_ids[tag] = obj.object_id
|
173
|
+
else:
|
174
|
+
raise RuntimeError(f"Unexpected object {obj.object_id}")
|
167
175
|
|
168
176
|
await TaskContext.gather(*(_load(tag, obj) for tag, obj in indexed_objects.items()))
|
169
177
|
|
@@ -172,30 +180,22 @@ async def _publish_app(
|
|
172
180
|
client: _Client,
|
173
181
|
running_app: RunningApp,
|
174
182
|
app_state: int, # api_pb2.AppState.value
|
175
|
-
|
183
|
+
functions: dict[str, _Function],
|
184
|
+
classes: dict[str, _Cls],
|
176
185
|
name: str = "", # Only relevant for deployments
|
177
186
|
tag: str = "", # Only relevant for deployments
|
178
187
|
) -> tuple[str, list[api_pb2.Warning]]:
|
179
188
|
"""Wrapper for AppPublish RPC."""
|
180
189
|
|
181
|
-
|
182
|
-
# function_ids / class_ids rather than the current tag_to_object_id (i.e. "indexed_objects")
|
183
|
-
def filter_values(full_dict: dict[str, V], condition: Callable[[V], bool]) -> dict[str, V]:
|
184
|
-
return {k: v for k, v in full_dict.items() if condition(v)}
|
185
|
-
|
186
|
-
function_ids = filter_values(running_app.tag_to_object_id, _Function._is_id_type)
|
187
|
-
class_ids = filter_values(running_app.tag_to_object_id, _Cls._is_id_type)
|
188
|
-
|
189
|
-
function_objs = filter_values(indexed_objects, lambda v: v.object_id in function_ids.values())
|
190
|
-
definition_ids = {obj.object_id: obj._get_metadata().definition_id for obj in function_objs.values()} # type: ignore
|
190
|
+
definition_ids = {obj.object_id: obj._get_metadata().definition_id for obj in functions.values()} # type: ignore
|
191
191
|
|
192
192
|
request = api_pb2.AppPublishRequest(
|
193
193
|
app_id=running_app.app_id,
|
194
194
|
name=name,
|
195
195
|
deployment_tag=tag,
|
196
196
|
app_state=app_state, # type: ignore : should be a api_pb2.AppState.value
|
197
|
-
function_ids=function_ids,
|
198
|
-
class_ids=class_ids,
|
197
|
+
function_ids=running_app.function_ids,
|
198
|
+
class_ids=running_app.class_ids,
|
199
199
|
definition_ids=definition_ids,
|
200
200
|
)
|
201
201
|
try:
|
@@ -329,13 +329,11 @@ async def _run_app(
|
|
329
329
|
)
|
330
330
|
|
331
331
|
try:
|
332
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
333
|
-
|
334
332
|
# Create all members
|
335
|
-
await _create_all_objects(client, running_app,
|
333
|
+
await _create_all_objects(client, running_app, app._functions, app._classes, environment_name)
|
336
334
|
|
337
335
|
# Publish the app
|
338
|
-
await _publish_app(client, running_app, app_state,
|
336
|
+
await _publish_app(client, running_app, app_state, app._functions, app._classes)
|
339
337
|
except asyncio.CancelledError as e:
|
340
338
|
# this typically happens on sigint/ctrl-C during setup (the KeyboardInterrupt happens in the main thread)
|
341
339
|
if output_mgr := _get_output_manager():
|
@@ -428,18 +426,17 @@ async def _serve_update(
|
|
428
426
|
try:
|
429
427
|
running_app: RunningApp = await _init_local_app_existing(client, existing_app_id, environment_name)
|
430
428
|
|
431
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
432
|
-
|
433
429
|
# Create objects
|
434
430
|
await _create_all_objects(
|
435
431
|
client,
|
436
432
|
running_app,
|
437
|
-
|
433
|
+
app._functions,
|
434
|
+
app._classes,
|
438
435
|
environment_name,
|
439
436
|
)
|
440
437
|
|
441
438
|
# Publish the updated app
|
442
|
-
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED,
|
439
|
+
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED, app._functions, app._classes)
|
443
440
|
|
444
441
|
# Communicate to the parent process
|
445
442
|
is_ready.set()
|
@@ -527,19 +524,18 @@ async def _deploy_app(
|
|
527
524
|
|
528
525
|
tc.infinite_loop(heartbeat, sleep=HEARTBEAT_INTERVAL)
|
529
526
|
|
530
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
531
|
-
|
532
527
|
try:
|
533
528
|
# Create all members
|
534
529
|
await _create_all_objects(
|
535
530
|
client,
|
536
531
|
running_app,
|
537
|
-
|
532
|
+
app._functions,
|
533
|
+
app._classes,
|
538
534
|
environment_name=environment_name,
|
539
535
|
)
|
540
536
|
|
541
537
|
app_url, warnings = await _publish_app(
|
542
|
-
client, running_app, api_pb2.APP_STATE_DEPLOYED,
|
538
|
+
client, running_app, api_pb2.APP_STATE_DEPLOYED, app._functions, app._classes, name, tag
|
543
539
|
)
|
544
540
|
except Exception as e:
|
545
541
|
# Note that AppClientDisconnect only stops the app if it's still initializing, and is a no-op otherwise.
|
modal/runner.pyi
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import modal.client
|
2
|
-
import modal.
|
2
|
+
import modal.cls
|
3
|
+
import modal.functions
|
3
4
|
import modal.running_app
|
4
5
|
import modal_proto.api_pb2
|
5
6
|
import multiprocessing.synchronize
|
@@ -28,14 +29,16 @@ async def _init_local_app_from_name(
|
|
28
29
|
async def _create_all_objects(
|
29
30
|
client: modal.client._Client,
|
30
31
|
running_app: modal.running_app.RunningApp,
|
31
|
-
|
32
|
+
functions: dict[str, modal.functions._Function],
|
33
|
+
classes: dict[str, modal.cls._Cls],
|
32
34
|
environment_name: str,
|
33
35
|
) -> None: ...
|
34
36
|
async def _publish_app(
|
35
37
|
client: modal.client._Client,
|
36
38
|
running_app: modal.running_app.RunningApp,
|
37
39
|
app_state: int,
|
38
|
-
|
40
|
+
functions: dict[str, modal.functions._Function],
|
41
|
+
classes: dict[str, modal.cls._Cls],
|
39
42
|
name: str = "",
|
40
43
|
tag: str = "",
|
41
44
|
) -> tuple[str, list[modal_proto.api_pb2.Warning]]: ...
|
modal/running_app.py
CHANGED
@@ -17,7 +17,8 @@ class RunningApp:
|
|
17
17
|
environment_name: Optional[str] = None
|
18
18
|
app_page_url: Optional[str] = None
|
19
19
|
app_logs_url: Optional[str] = None
|
20
|
-
|
20
|
+
function_ids: dict[str, str] = field(default_factory=dict)
|
21
|
+
class_ids: dict[str, str] = field(default_factory=dict)
|
21
22
|
object_handle_metadata: dict[str, Optional[Message]] = field(default_factory=dict)
|
22
23
|
interactive: bool = False
|
23
24
|
|
@@ -29,7 +30,6 @@ def running_app_from_layout(
|
|
29
30
|
environment_name: Optional[str] = None,
|
30
31
|
app_page_url: Optional[str] = None,
|
31
32
|
) -> RunningApp:
|
32
|
-
tag_to_object_id = dict(**app_layout.function_ids, **app_layout.class_ids)
|
33
33
|
object_handle_metadata = {}
|
34
34
|
for obj in app_layout.objects:
|
35
35
|
handle_metadata: Optional[Message] = get_proto_oneof(obj, "handle_metadata_oneof")
|
@@ -39,7 +39,8 @@ def running_app_from_layout(
|
|
39
39
|
app_id,
|
40
40
|
client,
|
41
41
|
environment_name=environment_name,
|
42
|
-
|
42
|
+
function_ids=dict(app_layout.function_ids),
|
43
|
+
class_ids=dict(app_layout.class_ids),
|
43
44
|
object_handle_metadata=object_handle_metadata,
|
44
45
|
app_page_url=app_page_url,
|
45
46
|
)
|
@@ -15,11 +15,11 @@ modal/_traceback.py,sha256=IZQzB3fVlUfMHOSyKUgw0H6qv4yHnpyq-XVCNZKfUdA,5023
|
|
15
15
|
modal/_tunnel.py,sha256=o-jJhS4vQ6-XswDhHcJWGMZZmD03SC0e9i8fEu1JTjo,6310
|
16
16
|
modal/_tunnel.pyi,sha256=JmmDYAy9F1FpgJ_hWx0xkom2nTOFQjn4mTPYlU3PFo4,1245
|
17
17
|
modal/_watcher.py,sha256=K6LYnlmSGQB4tWWI9JADv-tvSvQ1j522FwT71B51CX8,3584
|
18
|
-
modal/app.py,sha256=
|
18
|
+
modal/app.py,sha256=jzqFUHK-tNJ2Ah4zv4eLfZimHwLC2M3J2c3RbveMBAw,45474
|
19
19
|
modal/app.pyi,sha256=FYPCEJNhof4YF6HIuNP_2yG6s2PgZnKW9tO1hFE6sfA,25194
|
20
20
|
modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
|
21
21
|
modal/client.py,sha256=JAnd4-GCN093BwkvOFAK5a6iy5ycxofjpUncMxlrIMw,15253
|
22
|
-
modal/client.pyi,sha256=
|
22
|
+
modal/client.pyi,sha256=gYox-KDSDT-Sk7i-alSUPPAYGqQ-X3C755COzC8SnTo,7278
|
23
23
|
modal/cloud_bucket_mount.py,sha256=G7T7jWLD0QkmrfKR75mSTwdUZ2xNfj7pkVqb4ipmxmI,5735
|
24
24
|
modal/cloud_bucket_mount.pyi,sha256=CEi7vrH3kDUF4LAy4qP6tfImy2UJuFRcRbsgRNM1wo8,1403
|
25
25
|
modal/cls.py,sha256=3hjb0JcoPjxKZNeK22f5rR43bZRBjoRI7_EMZXY7YrE,31172
|
@@ -60,9 +60,9 @@ modal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
60
60
|
modal/queue.py,sha256=zMUQtdAyqZzBg-2iAo3c3G54HLP7TEWfVhiQXLjewb4,18556
|
61
61
|
modal/queue.pyi,sha256=gGV97pWelSSYqMV9Bl4ys3mSP7q82fS71oqSWeAwyDE,9818
|
62
62
|
modal/retries.py,sha256=HKR2Q9aNPWkMjQ5nwobqYTuZaSuw0a8lI2zrtY5IW98,5230
|
63
|
-
modal/runner.py,sha256=
|
64
|
-
modal/runner.pyi,sha256=
|
65
|
-
modal/running_app.py,sha256=
|
63
|
+
modal/runner.py,sha256=miYYjZcXU8q4zG20kPoPgtSmcGxpi07FCdboaVhyWVs,24196
|
64
|
+
modal/runner.pyi,sha256=YmP4EOCNjjkwSIPi2Gl6hF_ji_ytkxz9dw3iB9KXaOI,5275
|
65
|
+
modal/running_app.py,sha256=_fUf-qJXdtXgblETH7JpgvOtcnzrtnGcMKc2v3pBqJg,1404
|
66
66
|
modal/sandbox.py,sha256=c-Qli3QJPN7bBQzsTk4iS51zurNlq--InZ2eRR-B6No,28106
|
67
67
|
modal/sandbox.pyi,sha256=k8_vHjN3oigxSCF13Cm2HfcSHuliGuSb8ryd3CGqwoA,19815
|
68
68
|
modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
|
@@ -165,10 +165,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
|
|
165
165
|
modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
166
166
|
modal_version/__init__.py,sha256=N9Kh4DrM2649_INTJG4Lp3NKdux7cxGuiDtXpq_hkFY,470
|
167
167
|
modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
|
168
|
-
modal_version/_version_generated.py,sha256
|
169
|
-
modal-0.70.
|
170
|
-
modal-0.70.
|
171
|
-
modal-0.70.
|
172
|
-
modal-0.70.
|
173
|
-
modal-0.70.
|
174
|
-
modal-0.70.
|
168
|
+
modal_version/_version_generated.py,sha256=C3_yPhD3BROKMT-d8--G4NKBC4UkPBzHESdS0qSFJB4,148
|
169
|
+
modal-0.70.3.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
170
|
+
modal-0.70.3.dist-info/METADATA,sha256=Y65xpw-VrQOe_s50VTrCEIkl6FQKMSN18NSOmMBhZl0,2328
|
171
|
+
modal-0.70.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
172
|
+
modal-0.70.3.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
173
|
+
modal-0.70.3.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
|
174
|
+
modal-0.70.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|