modal 0.70.2__py3-none-any.whl → 0.70.4__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/_container_entrypoint.py +14 -13
- modal/_runtime/container_io_manager.py +1 -6
- modal/app.py +25 -23
- modal/app.pyi +6 -2
- modal/client.pyi +2 -2
- modal/runner.py +26 -33
- modal/runner.pyi +6 -3
- modal/running_app.py +4 -11
- modal/sandbox.py +3 -3
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/METADATA +1 -1
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/RECORD +16 -16
- modal_version/_version_generated.py +2 -2
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/LICENSE +0 -0
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/WHEEL +0 -0
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/entry_points.txt +0 -0
- {modal-0.70.2.dist-info → modal-0.70.4.dist-info}/top_level.txt +0 -0
modal/_container_entrypoint.py
CHANGED
@@ -337,14 +337,17 @@ def call_function(
|
|
337
337
|
signal.signal(signal.SIGUSR1, usr1_handler) # reset signal handler
|
338
338
|
|
339
339
|
|
340
|
-
def get_active_app_fallback(function_def: api_pb2.Function) ->
|
340
|
+
def get_active_app_fallback(function_def: api_pb2.Function) -> _App:
|
341
341
|
# This branch is reached in the special case that the imported function/class is:
|
342
342
|
# 1) not serialized, and
|
343
343
|
# 2) isn't a FunctionHandle - i.e, not decorated at definition time
|
344
344
|
# Look at all instantiated apps - if there is only one with the indicated name, use that one
|
345
345
|
app_name: Optional[str] = function_def.app_name or None # coalesce protobuf field to None
|
346
346
|
matching_apps = _App._all_apps.get(app_name, [])
|
347
|
-
|
347
|
+
if len(matching_apps) == 1:
|
348
|
+
active_app: _App = matching_apps[0]
|
349
|
+
return active_app
|
350
|
+
|
348
351
|
if len(matching_apps) > 1:
|
349
352
|
if app_name is not None:
|
350
353
|
warning_sub_message = f"app with the same name ('{app_name}')"
|
@@ -354,12 +357,10 @@ def get_active_app_fallback(function_def: api_pb2.Function) -> Optional[_App]:
|
|
354
357
|
f"You have more than one {warning_sub_message}. "
|
355
358
|
"It's recommended to name all your Apps uniquely when using multiple apps"
|
356
359
|
)
|
357
|
-
elif len(matching_apps) == 1:
|
358
|
-
(active_app,) = matching_apps
|
359
|
-
# there could also technically be zero found apps, but that should probably never be an
|
360
|
-
# issue since that would mean user won't use is_inside or other function handles anyway
|
361
360
|
|
362
|
-
|
361
|
+
# If we don't have an active app, create one on the fly
|
362
|
+
# The app object is used to carry the app layout etc
|
363
|
+
return _App()
|
363
364
|
|
364
365
|
|
365
366
|
def call_lifecycle_functions(
|
@@ -403,7 +404,7 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
|
|
403
404
|
# This is a bit weird but we need both the blocking and async versions of ContainerIOManager.
|
404
405
|
# At some point, we should fix that by having built-in support for running "user code"
|
405
406
|
container_io_manager = ContainerIOManager(container_args, client)
|
406
|
-
active_app:
|
407
|
+
active_app: _App
|
407
408
|
service: Service
|
408
409
|
function_def = container_args.function_def
|
409
410
|
is_auto_snapshot: bool = function_def.is_auto_snapshot
|
@@ -450,8 +451,9 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
|
|
450
451
|
)
|
451
452
|
|
452
453
|
# If the cls/function decorator was applied in local scope, but the app is global, we can look it up
|
453
|
-
|
454
|
-
|
454
|
+
if service.app is not None:
|
455
|
+
active_app = service.app
|
456
|
+
else:
|
455
457
|
# if the app can't be inferred by the imported function, use name-based fallback
|
456
458
|
active_app = get_active_app_fallback(function_def)
|
457
459
|
|
@@ -468,9 +470,8 @@ def main(container_args: api_pb2.ContainerArguments, client: Client):
|
|
468
470
|
|
469
471
|
# Initialize objects on the app.
|
470
472
|
# This is basically only functions and classes - anything else is deprecated and will be unsupported soon
|
471
|
-
|
472
|
-
|
473
|
-
app._init_container(client, container_app)
|
473
|
+
app: App = synchronizer._translate_out(active_app)
|
474
|
+
app._init_container(client, container_app)
|
474
475
|
|
475
476
|
# Hydrate all function dependencies.
|
476
477
|
# TODO(erikbern): we an remove this once we
|
@@ -457,12 +457,7 @@ class _ContainerIOManager:
|
|
457
457
|
resp = await retry_transient_errors(self._client.stub.AppGetLayout, req)
|
458
458
|
app_layout = resp.app_layout
|
459
459
|
|
460
|
-
return running_app_from_layout(
|
461
|
-
self.app_id,
|
462
|
-
app_layout,
|
463
|
-
self._client,
|
464
|
-
environment_name=self._environment_name,
|
465
|
-
)
|
460
|
+
return running_app_from_layout(self.app_id, app_layout)
|
466
461
|
|
467
462
|
async def get_serialized_function(self) -> tuple[Optional[Any], Optional[Callable[..., Any]]]:
|
468
463
|
# Fetch the serialized function definition
|
modal/app.py
CHANGED
@@ -168,7 +168,7 @@ class _App:
|
|
168
168
|
"""
|
169
169
|
|
170
170
|
_all_apps: ClassVar[dict[Optional[str], list["_App"]]] = {}
|
171
|
-
_container_app: ClassVar[Optional[
|
171
|
+
_container_app: ClassVar[Optional["_App"]] = None
|
172
172
|
|
173
173
|
_name: Optional[str]
|
174
174
|
_description: Optional[str]
|
@@ -294,12 +294,7 @@ class _App:
|
|
294
294
|
app = _App(name)
|
295
295
|
app._app_id = response.app_id
|
296
296
|
app._client = client
|
297
|
-
app._running_app = RunningApp(
|
298
|
-
response.app_id,
|
299
|
-
client=client,
|
300
|
-
environment_name=environment_name,
|
301
|
-
interactive=False,
|
302
|
-
)
|
297
|
+
app._running_app = RunningApp(response.app_id, interactive=False)
|
303
298
|
return app
|
304
299
|
|
305
300
|
def set_description(self, description: str):
|
@@ -463,8 +458,8 @@ class _App:
|
|
463
458
|
if self._running_app:
|
464
459
|
# If this is inside a container, then objects can be defined after app initialization.
|
465
460
|
# 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.
|
461
|
+
if function.tag in self._running_app.function_ids:
|
462
|
+
object_id: str = self._running_app.function_ids[function.tag]
|
468
463
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
469
464
|
function._hydrate(object_id, self._client, metadata)
|
470
465
|
|
@@ -476,8 +471,8 @@ class _App:
|
|
476
471
|
if self._running_app:
|
477
472
|
# If this is inside a container, then objects can be defined after app initialization.
|
478
473
|
# 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.
|
474
|
+
if tag in self._running_app.class_ids:
|
475
|
+
object_id: str = self._running_app.class_ids[tag]
|
481
476
|
metadata: Message = self._running_app.object_handle_metadata[object_id]
|
482
477
|
cls._hydrate(object_id, self._client, metadata)
|
483
478
|
|
@@ -488,21 +483,21 @@ class _App:
|
|
488
483
|
self._running_app = running_app
|
489
484
|
self._client = client
|
490
485
|
|
491
|
-
_App._container_app =
|
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)
|
486
|
+
_App._container_app = self
|
501
487
|
|
502
488
|
# Hydrate function objects
|
503
|
-
|
489
|
+
for tag, object_id in running_app.function_ids.items():
|
490
|
+
if tag in self._functions:
|
491
|
+
obj = self._functions[tag]
|
492
|
+
handle_metadata = running_app.object_handle_metadata[object_id]
|
493
|
+
obj._hydrate(object_id, client, handle_metadata)
|
494
|
+
|
504
495
|
# Hydrate class objects
|
505
|
-
|
496
|
+
for tag, object_id in running_app.class_ids.items():
|
497
|
+
if tag in self._classes:
|
498
|
+
obj = self._classes[tag]
|
499
|
+
handle_metadata = running_app.object_handle_metadata[object_id]
|
500
|
+
obj._hydrate(object_id, client, handle_metadata)
|
506
501
|
|
507
502
|
@property
|
508
503
|
def registered_functions(self) -> dict[str, _Function]:
|
@@ -1047,6 +1042,13 @@ class _App:
|
|
1047
1042
|
if log.data:
|
1048
1043
|
yield log.data
|
1049
1044
|
|
1045
|
+
@classmethod
|
1046
|
+
def container_app(cls) -> Optional["_App"]:
|
1047
|
+
"""Returns the `App` running inside a container.
|
1048
|
+
|
1049
|
+
This will return `None` outside of a Modal container."""
|
1050
|
+
return cls._container_app
|
1051
|
+
|
1050
1052
|
@classmethod
|
1051
1053
|
def _reset_container_app(cls):
|
1052
1054
|
"""Only used for tests."""
|
modal/app.pyi
CHANGED
@@ -73,7 +73,7 @@ class _FunctionDecoratorType:
|
|
73
73
|
|
74
74
|
class _App:
|
75
75
|
_all_apps: typing.ClassVar[dict[typing.Optional[str], list[_App]]]
|
76
|
-
_container_app: typing.ClassVar[typing.Optional[
|
76
|
+
_container_app: typing.ClassVar[typing.Optional[_App]]
|
77
77
|
_name: typing.Optional[str]
|
78
78
|
_description: typing.Optional[str]
|
79
79
|
_functions: dict[str, modal.functions._Function]
|
@@ -266,11 +266,13 @@ class _App:
|
|
266
266
|
self, client: typing.Optional[modal.client._Client] = None
|
267
267
|
) -> collections.abc.AsyncGenerator[str, None]: ...
|
268
268
|
@classmethod
|
269
|
+
def container_app(cls) -> typing.Optional[_App]: ...
|
270
|
+
@classmethod
|
269
271
|
def _reset_container_app(cls): ...
|
270
272
|
|
271
273
|
class App:
|
272
274
|
_all_apps: typing.ClassVar[dict[typing.Optional[str], list[App]]]
|
273
|
-
_container_app: typing.ClassVar[typing.Optional[
|
275
|
+
_container_app: typing.ClassVar[typing.Optional[App]]
|
274
276
|
_name: typing.Optional[str]
|
275
277
|
_description: typing.Optional[str]
|
276
278
|
_functions: dict[str, modal.functions.Function]
|
@@ -530,6 +532,8 @@ class App:
|
|
530
532
|
|
531
533
|
_logs: ___logs_spec
|
532
534
|
|
535
|
+
@classmethod
|
536
|
+
def container_app(cls) -> typing.Optional[App]: ...
|
533
537
|
@classmethod
|
534
538
|
def _reset_container_app(cls): ...
|
535
539
|
|
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.4"
|
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.4"
|
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
|
@@ -64,7 +64,6 @@ async def _init_local_app_existing(client: _Client, existing_app_id: str, enviro
|
|
64
64
|
return running_app_from_layout(
|
65
65
|
existing_app_id,
|
66
66
|
obj_resp.app_layout,
|
67
|
-
client,
|
68
67
|
app_page_url=app_page_url,
|
69
68
|
)
|
70
69
|
|
@@ -89,10 +88,8 @@ async def _init_local_app_new(
|
|
89
88
|
logger.debug(f"Created new app with id {app_resp.app_id}")
|
90
89
|
return RunningApp(
|
91
90
|
app_resp.app_id,
|
92
|
-
client=client,
|
93
91
|
app_page_url=app_resp.app_page_url,
|
94
92
|
app_logs_url=app_resp.app_logs_url,
|
95
|
-
environment_name=environment_name,
|
96
93
|
interactive=interactive,
|
97
94
|
)
|
98
95
|
|
@@ -124,10 +121,12 @@ async def _init_local_app_from_name(
|
|
124
121
|
async def _create_all_objects(
|
125
122
|
client: _Client,
|
126
123
|
running_app: RunningApp,
|
127
|
-
|
124
|
+
functions: dict[str, _Function],
|
125
|
+
classes: dict[str, _Cls],
|
128
126
|
environment_name: str,
|
129
127
|
) -> None:
|
130
128
|
"""Create objects that have been defined but not created on the server."""
|
129
|
+
indexed_objects: dict[str, _Object] = {**functions, **classes}
|
131
130
|
resolver = Resolver(
|
132
131
|
client,
|
133
132
|
environment_name=environment_name,
|
@@ -135,8 +134,9 @@ async def _create_all_objects(
|
|
135
134
|
)
|
136
135
|
with resolver.display():
|
137
136
|
# Get current objects, and reset all objects
|
138
|
-
tag_to_object_id = running_app.
|
139
|
-
running_app.
|
137
|
+
tag_to_object_id = {**running_app.function_ids, **running_app.class_ids}
|
138
|
+
running_app.function_ids = {}
|
139
|
+
running_app.class_ids = {}
|
140
140
|
|
141
141
|
# Assign all objects
|
142
142
|
for tag, obj in indexed_objects.items():
|
@@ -163,7 +163,12 @@ async def _create_all_objects(
|
|
163
163
|
async def _load(tag, obj):
|
164
164
|
existing_object_id = tag_to_object_id.get(tag)
|
165
165
|
await resolver.load(obj, existing_object_id)
|
166
|
-
|
166
|
+
if _Function._is_id_type(obj.object_id):
|
167
|
+
running_app.function_ids[tag] = obj.object_id
|
168
|
+
elif _Cls._is_id_type(obj.object_id):
|
169
|
+
running_app.class_ids[tag] = obj.object_id
|
170
|
+
else:
|
171
|
+
raise RuntimeError(f"Unexpected object {obj.object_id}")
|
167
172
|
|
168
173
|
await TaskContext.gather(*(_load(tag, obj) for tag, obj in indexed_objects.items()))
|
169
174
|
|
@@ -172,30 +177,22 @@ async def _publish_app(
|
|
172
177
|
client: _Client,
|
173
178
|
running_app: RunningApp,
|
174
179
|
app_state: int, # api_pb2.AppState.value
|
175
|
-
|
180
|
+
functions: dict[str, _Function],
|
181
|
+
classes: dict[str, _Cls],
|
176
182
|
name: str = "", # Only relevant for deployments
|
177
183
|
tag: str = "", # Only relevant for deployments
|
178
184
|
) -> tuple[str, list[api_pb2.Warning]]:
|
179
185
|
"""Wrapper for AppPublish RPC."""
|
180
186
|
|
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
|
187
|
+
definition_ids = {obj.object_id: obj._get_metadata().definition_id for obj in functions.values()} # type: ignore
|
191
188
|
|
192
189
|
request = api_pb2.AppPublishRequest(
|
193
190
|
app_id=running_app.app_id,
|
194
191
|
name=name,
|
195
192
|
deployment_tag=tag,
|
196
193
|
app_state=app_state, # type: ignore : should be a api_pb2.AppState.value
|
197
|
-
function_ids=function_ids,
|
198
|
-
class_ids=class_ids,
|
194
|
+
function_ids=running_app.function_ids,
|
195
|
+
class_ids=running_app.class_ids,
|
199
196
|
definition_ids=definition_ids,
|
200
197
|
)
|
201
198
|
try:
|
@@ -329,13 +326,11 @@ async def _run_app(
|
|
329
326
|
)
|
330
327
|
|
331
328
|
try:
|
332
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
333
|
-
|
334
329
|
# Create all members
|
335
|
-
await _create_all_objects(client, running_app,
|
330
|
+
await _create_all_objects(client, running_app, app._functions, app._classes, environment_name)
|
336
331
|
|
337
332
|
# Publish the app
|
338
|
-
await _publish_app(client, running_app, app_state,
|
333
|
+
await _publish_app(client, running_app, app_state, app._functions, app._classes)
|
339
334
|
except asyncio.CancelledError as e:
|
340
335
|
# this typically happens on sigint/ctrl-C during setup (the KeyboardInterrupt happens in the main thread)
|
341
336
|
if output_mgr := _get_output_manager():
|
@@ -428,18 +423,17 @@ async def _serve_update(
|
|
428
423
|
try:
|
429
424
|
running_app: RunningApp = await _init_local_app_existing(client, existing_app_id, environment_name)
|
430
425
|
|
431
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
432
|
-
|
433
426
|
# Create objects
|
434
427
|
await _create_all_objects(
|
435
428
|
client,
|
436
429
|
running_app,
|
437
|
-
|
430
|
+
app._functions,
|
431
|
+
app._classes,
|
438
432
|
environment_name,
|
439
433
|
)
|
440
434
|
|
441
435
|
# Publish the updated app
|
442
|
-
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED,
|
436
|
+
await _publish_app(client, running_app, api_pb2.APP_STATE_UNSPECIFIED, app._functions, app._classes)
|
443
437
|
|
444
438
|
# Communicate to the parent process
|
445
439
|
is_ready.set()
|
@@ -527,19 +521,18 @@ async def _deploy_app(
|
|
527
521
|
|
528
522
|
tc.infinite_loop(heartbeat, sleep=HEARTBEAT_INTERVAL)
|
529
523
|
|
530
|
-
indexed_objects = dict(**app._functions, **app._classes) # TODO(erikbern): remove
|
531
|
-
|
532
524
|
try:
|
533
525
|
# Create all members
|
534
526
|
await _create_all_objects(
|
535
527
|
client,
|
536
528
|
running_app,
|
537
|
-
|
529
|
+
app._functions,
|
530
|
+
app._classes,
|
538
531
|
environment_name=environment_name,
|
539
532
|
)
|
540
533
|
|
541
534
|
app_url, warnings = await _publish_app(
|
542
|
-
client, running_app, api_pb2.APP_STATE_DEPLOYED,
|
535
|
+
client, running_app, api_pb2.APP_STATE_DEPLOYED, app._functions, app._classes, name, tag
|
543
536
|
)
|
544
537
|
except Exception as e:
|
545
538
|
# 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
@@ -7,17 +7,14 @@ from google.protobuf.message import Message
|
|
7
7
|
from modal._utils.grpc_utils import get_proto_oneof
|
8
8
|
from modal_proto import api_pb2
|
9
9
|
|
10
|
-
from .client import _Client
|
11
|
-
|
12
10
|
|
13
11
|
@dataclass
|
14
12
|
class RunningApp:
|
15
13
|
app_id: str
|
16
|
-
client: _Client
|
17
|
-
environment_name: Optional[str] = None
|
18
14
|
app_page_url: Optional[str] = None
|
19
15
|
app_logs_url: Optional[str] = None
|
20
|
-
|
16
|
+
function_ids: dict[str, str] = field(default_factory=dict)
|
17
|
+
class_ids: dict[str, str] = field(default_factory=dict)
|
21
18
|
object_handle_metadata: dict[str, Optional[Message]] = field(default_factory=dict)
|
22
19
|
interactive: bool = False
|
23
20
|
|
@@ -25,11 +22,8 @@ class RunningApp:
|
|
25
22
|
def running_app_from_layout(
|
26
23
|
app_id: str,
|
27
24
|
app_layout: api_pb2.AppLayout,
|
28
|
-
client: _Client,
|
29
|
-
environment_name: Optional[str] = None,
|
30
25
|
app_page_url: Optional[str] = None,
|
31
26
|
) -> RunningApp:
|
32
|
-
tag_to_object_id = dict(**app_layout.function_ids, **app_layout.class_ids)
|
33
27
|
object_handle_metadata = {}
|
34
28
|
for obj in app_layout.objects:
|
35
29
|
handle_metadata: Optional[Message] = get_proto_oneof(obj, "handle_metadata_oneof")
|
@@ -37,9 +31,8 @@ def running_app_from_layout(
|
|
37
31
|
|
38
32
|
return RunningApp(
|
39
33
|
app_id,
|
40
|
-
|
41
|
-
|
42
|
-
tag_to_object_id=tag_to_object_id,
|
34
|
+
function_ids=dict(app_layout.function_ids),
|
35
|
+
class_ids=dict(app_layout.class_ids),
|
43
36
|
object_handle_metadata=object_handle_metadata,
|
44
37
|
app_page_url=app_page_url,
|
45
38
|
)
|
modal/sandbox.py
CHANGED
@@ -276,9 +276,9 @@ class _Sandbox(_Object, type_prefix="sb"):
|
|
276
276
|
|
277
277
|
app_id = app.app_id
|
278
278
|
app_client = app._client
|
279
|
-
elif _App.
|
280
|
-
app_id =
|
281
|
-
app_client =
|
279
|
+
elif (container_app := _App.container_app()) is not None:
|
280
|
+
app_id = container_app.app_id
|
281
|
+
app_client = container_app._client
|
282
282
|
else:
|
283
283
|
arglist = ", ".join(repr(s) for s in entrypoint_args)
|
284
284
|
deprecation_error(
|
@@ -2,7 +2,7 @@ modal/__init__.py,sha256=3NJLLHb0TRc2tc68kf8NHzORx38GbtbZvPEWDWrQ6N4,2234
|
|
2
2
|
modal/__main__.py,sha256=scYhGFqh8OJcVDo-VOxIT6CCwxOgzgflYWMnIZiMRqE,2871
|
3
3
|
modal/_clustered_functions.py,sha256=kTf-9YBXY88NutC1akI-gCbvf01RhMPCw-zoOI_YIUE,2700
|
4
4
|
modal/_clustered_functions.pyi,sha256=vllkegc99A0jrUOWa8mdlSbdp6uz36TsHhGxysAOpaQ,771
|
5
|
-
modal/_container_entrypoint.py,sha256=
|
5
|
+
modal/_container_entrypoint.py,sha256=d4Mgwkv93Kvt92msYSNGyhH4QXhrt08wosz4WfDp0Aw,28830
|
6
6
|
modal/_ipython.py,sha256=TW1fkVOmZL3YYqdS2YlM1hqpf654Yf8ZyybHdBnlhSw,301
|
7
7
|
modal/_location.py,sha256=S3lSxIU3h9HkWpkJ3Pwo0pqjIOSB1fjeSgUsY3x7eec,1202
|
8
8
|
modal/_output.py,sha256=0fWX_KQwhER--U81ys16CL-pA5A-LN20C0EZjElKGJQ,25410
|
@@ -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=
|
19
|
-
modal/app.pyi,sha256=
|
18
|
+
modal/app.py,sha256=LhAdfXUfqcVvmqTC8HM-LxMlGWCW2U8Xuhb6URyj9RI,45577
|
19
|
+
modal/app.pyi,sha256=ojqaDubpV6wdhqewMe2T_AKt2RPXSG4nySZu8_lHpvc,25292
|
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=tK1--wDx9xNyIcEiYHIHtti3ZVkYOuTVjeZXSRT1-HY,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,10 +60,10 @@ 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=
|
66
|
-
modal/sandbox.py,sha256=
|
63
|
+
modal/runner.py,sha256=mhqgRdjD5cUDpBQIokiX7OCfVblpGV6aWmZ-WvWJgGg,24114
|
64
|
+
modal/runner.pyi,sha256=YmP4EOCNjjkwSIPi2Gl6hF_ji_ytkxz9dw3iB9KXaOI,5275
|
65
|
+
modal/running_app.py,sha256=v61mapYNV1-O-Uaho5EfJlryMLvIT9We0amUOSvSGx8,1188
|
66
|
+
modal/sandbox.py,sha256=_r-Cj5L6BE5tOzwIUxGP99BH9EsCTupQSV3jcP61aZM,28115
|
67
67
|
modal/sandbox.pyi,sha256=k8_vHjN3oigxSCF13Cm2HfcSHuliGuSb8ryd3CGqwoA,19815
|
68
68
|
modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
|
69
69
|
modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
|
@@ -78,7 +78,7 @@ modal/volume.py,sha256=T-pLxCYqmqRO6OolpAXlPxomMu0RWjti2e4kUpaj2cQ,29229
|
|
78
78
|
modal/volume.pyi,sha256=eekb2dnAAwFK_NO9ciAOOTthl8NP1iAmMFrCGgjDA2k,11100
|
79
79
|
modal/_runtime/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
|
80
80
|
modal/_runtime/asgi.py,sha256=Mjs859pSgOmtZL-YmEsSKN557v1A2Ax_5-ERgPfj55E,21920
|
81
|
-
modal/_runtime/container_io_manager.py,sha256=
|
81
|
+
modal/_runtime/container_io_manager.py,sha256=HgDLjE78yy1P7WZTmsEVDf89YnFFWG63Ddes8uYLVDY,43764
|
82
82
|
modal/_runtime/execution_context.py,sha256=E6ofm6j1POXGPxS841X3V7JU6NheVb8OkQc7JpLq4Kg,2712
|
83
83
|
modal/_runtime/telemetry.py,sha256=T1RoAGyjBDr1swiM6pPsGRSITm7LI5FDK18oNXxY08U,5163
|
84
84
|
modal/_runtime/user_code_imports.py,sha256=n4CQOojzSdf0jwSKSy6MEnVX3IWl3t3Dq54-x9VS2Ds,14663
|
@@ -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=ZMPi8R_MjME99Sf5PLcfgOuAzbE-RYxPuF4CSKV1_vg,148
|
169
|
+
modal-0.70.4.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
|
170
|
+
modal-0.70.4.dist-info/METADATA,sha256=cQc9rstYeBi9SeZxjUL12d2OZjHF2UAua4d8C4acz3Y,2328
|
171
|
+
modal-0.70.4.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
172
|
+
modal-0.70.4.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
|
173
|
+
modal-0.70.4.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
|
174
|
+
modal-0.70.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|