modal 0.67.6__py3-none-any.whl → 0.67.11__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/_clustered_functions.py +2 -2
- modal/_clustered_functions.pyi +2 -2
- modal/_container_entrypoint.py +5 -4
- modal/_output.py +29 -28
- modal/_pty.py +2 -2
- modal/_resolver.py +6 -5
- modal/_resources.py +3 -3
- modal/_runtime/asgi.py +7 -6
- modal/_runtime/container_io_manager.py +22 -26
- modal/_runtime/execution_context.py +2 -2
- modal/_runtime/telemetry.py +1 -2
- modal/_runtime/user_code_imports.py +12 -14
- modal/_serialization.py +3 -7
- modal/_traceback.py +5 -5
- modal/_tunnel.py +4 -3
- modal/_tunnel.pyi +2 -2
- modal/_utils/async_utils.py +8 -15
- modal/_utils/blob_utils.py +4 -3
- modal/_utils/function_utils.py +14 -10
- modal/_utils/grpc_testing.py +7 -6
- modal/_utils/grpc_utils.py +2 -3
- modal/_utils/hash_utils.py +2 -2
- modal/_utils/mount_utils.py +5 -4
- modal/_utils/package_utils.py +2 -3
- modal/_utils/pattern_matcher.py +6 -6
- modal/_utils/rand_pb_testing.py +3 -3
- modal/_utils/shell_utils.py +2 -1
- modal/_vendor/a2wsgi_wsgi.py +62 -72
- modal/_vendor/cloudpickle.py +1 -1
- modal/_watcher.py +8 -7
- modal/app.py +29 -34
- modal/app.pyi +102 -97
- modal/call_graph.py +6 -6
- modal/cli/_download.py +3 -2
- modal/cli/_traceback.py +4 -4
- modal/cli/app.py +4 -4
- modal/cli/container.py +4 -4
- modal/cli/dict.py +1 -1
- modal/cli/environment.py +2 -3
- modal/cli/launch.py +2 -2
- modal/cli/network_file_system.py +1 -1
- modal/cli/profile.py +1 -1
- modal/cli/programs/run_jupyter.py +2 -2
- modal/cli/programs/vscode.py +3 -3
- modal/cli/queues.py +1 -1
- modal/cli/run.py +6 -6
- modal/cli/secret.py +3 -3
- modal/cli/utils.py +2 -1
- modal/cli/volume.py +3 -3
- modal/client.py +6 -11
- modal/client.pyi +18 -27
- modal/cloud_bucket_mount.py +3 -3
- modal/cloud_bucket_mount.pyi +2 -2
- modal/cls.py +30 -30
- modal/cls.pyi +35 -34
- modal/config.py +3 -2
- modal/dict.py +4 -3
- modal/dict.pyi +10 -9
- modal/environments.py +3 -3
- modal/environments.pyi +3 -3
- modal/exception.py +2 -3
- modal/functions.py +105 -35
- modal/functions.pyi +71 -48
- modal/image.py +45 -48
- modal/image.pyi +102 -101
- modal/io_streams.py +4 -7
- modal/io_streams.pyi +14 -13
- modal/mount.py +23 -22
- modal/mount.pyi +28 -29
- modal/network_file_system.py +7 -6
- modal/network_file_system.pyi +12 -11
- modal/object.py +9 -8
- modal/object.pyi +47 -34
- modal/output.py +2 -1
- modal/parallel_map.py +4 -4
- modal/partial_function.py +9 -13
- modal/partial_function.pyi +17 -18
- modal/queue.py +9 -8
- modal/queue.pyi +23 -22
- modal/retries.py +38 -0
- modal/runner.py +8 -7
- modal/runner.pyi +8 -14
- modal/running_app.py +3 -3
- modal/sandbox.py +14 -13
- modal/sandbox.pyi +67 -72
- modal/scheduler_placement.py +2 -1
- modal/secret.py +7 -7
- modal/secret.pyi +12 -12
- modal/serving.py +4 -3
- modal/serving.pyi +5 -4
- modal/token_flow.py +3 -2
- modal/token_flow.pyi +3 -3
- modal/volume.py +7 -12
- modal/volume.pyi +17 -16
- {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/METADATA +1 -1
- modal-0.67.11.dist-info/RECORD +168 -0
- modal_docs/mdmd/signatures.py +1 -2
- modal_version/_version_generated.py +1 -1
- modal-0.67.6.dist-info/RECORD +0 -168
- {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/LICENSE +0 -0
- {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/WHEEL +0 -0
- {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/entry_points.txt +0 -0
- {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/top_level.txt +0 -0
modal/_vendor/a2wsgi_wsgi.py
CHANGED
@@ -35,10 +35,8 @@ from concurrent.futures import ThreadPoolExecutor
|
|
35
35
|
from types import TracebackType
|
36
36
|
from typing import (
|
37
37
|
Any,
|
38
|
-
Awaitable,
|
39
38
|
Callable,
|
40
39
|
Dict,
|
41
|
-
Iterable,
|
42
40
|
List,
|
43
41
|
Literal,
|
44
42
|
Optional,
|
@@ -48,6 +46,7 @@ from typing import (
|
|
48
46
|
TypedDict,
|
49
47
|
Union,
|
50
48
|
)
|
49
|
+
from collections.abc import Awaitable, Iterable
|
51
50
|
|
52
51
|
|
53
52
|
## BEGIN a2wsgi/asgi_typing.py
|
@@ -73,11 +72,11 @@ class HTTPScope(TypedDict):
|
|
73
72
|
raw_path: NotRequired[bytes]
|
74
73
|
query_string: bytes
|
75
74
|
root_path: str
|
76
|
-
headers: Iterable[
|
77
|
-
client: NotRequired[
|
78
|
-
server: NotRequired[
|
79
|
-
state: NotRequired[
|
80
|
-
extensions: NotRequired[
|
75
|
+
headers: Iterable[tuple[bytes, bytes]]
|
76
|
+
client: NotRequired[tuple[str, int]]
|
77
|
+
server: NotRequired[tuple[str, Optional[int]]]
|
78
|
+
state: NotRequired[dict[str, Any]]
|
79
|
+
extensions: NotRequired[dict[str, dict[object, object]]]
|
81
80
|
|
82
81
|
|
83
82
|
class WebSocketScope(TypedDict):
|
@@ -89,18 +88,18 @@ class WebSocketScope(TypedDict):
|
|
89
88
|
raw_path: bytes
|
90
89
|
query_string: bytes
|
91
90
|
root_path: str
|
92
|
-
headers: Iterable[
|
93
|
-
client: NotRequired[
|
94
|
-
server: NotRequired[
|
91
|
+
headers: Iterable[tuple[bytes, bytes]]
|
92
|
+
client: NotRequired[tuple[str, int]]
|
93
|
+
server: NotRequired[tuple[str, Optional[int]]]
|
95
94
|
subprotocols: Iterable[str]
|
96
|
-
state: NotRequired[
|
97
|
-
extensions: NotRequired[
|
95
|
+
state: NotRequired[dict[str, Any]]
|
96
|
+
extensions: NotRequired[dict[str, dict[object, object]]]
|
98
97
|
|
99
98
|
|
100
99
|
class LifespanScope(TypedDict):
|
101
100
|
type: Literal["lifespan"]
|
102
101
|
asgi: ASGIVersions
|
103
|
-
state: NotRequired[
|
102
|
+
state: NotRequired[dict[str, Any]]
|
104
103
|
|
105
104
|
|
106
105
|
WWWScope = Union[HTTPScope, WebSocketScope]
|
@@ -116,7 +115,7 @@ class HTTPRequestEvent(TypedDict):
|
|
116
115
|
class HTTPResponseStartEvent(TypedDict):
|
117
116
|
type: Literal["http.response.start"]
|
118
117
|
status: int
|
119
|
-
headers: NotRequired[Iterable[
|
118
|
+
headers: NotRequired[Iterable[tuple[bytes, bytes]]]
|
120
119
|
trailers: NotRequired[bool]
|
121
120
|
|
122
121
|
|
@@ -137,7 +136,7 @@ class WebSocketConnectEvent(TypedDict):
|
|
137
136
|
class WebSocketAcceptEvent(TypedDict):
|
138
137
|
type: Literal["websocket.accept"]
|
139
138
|
subprotocol: NotRequired[str]
|
140
|
-
headers: NotRequired[Iterable[
|
139
|
+
headers: NotRequired[Iterable[tuple[bytes, bytes]]]
|
141
140
|
|
142
141
|
|
143
142
|
class WebSocketReceiveEvent(TypedDict):
|
@@ -223,56 +222,47 @@ ASGIApp = Callable[[Scope, Receive, Send], Awaitable[None]]
|
|
223
222
|
|
224
223
|
## BEGIN a2wsgi/wsgi_typing.py
|
225
224
|
|
226
|
-
CGIRequiredDefined
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
# The contents of any Content-Type fields in the HTTP request. May be empty
|
268
|
-
# or absent.
|
269
|
-
"CONTENT_TYPE": str,
|
270
|
-
# The contents of any Content-Length fields in the HTTP request. May be empty
|
271
|
-
# or absent.
|
272
|
-
"CONTENT_LENGTH": str,
|
273
|
-
},
|
274
|
-
total=False,
|
275
|
-
)
|
225
|
+
class CGIRequiredDefined(TypedDict):
|
226
|
+
# The HTTP request method, such as GET or POST. This cannot ever be an
|
227
|
+
# empty string, and so is always required.
|
228
|
+
REQUEST_METHOD: str
|
229
|
+
# When HTTP_HOST is not set, these variables can be combined to determine
|
230
|
+
# a default.
|
231
|
+
# SERVER_NAME and SERVER_PORT are required strings and must never be empty.
|
232
|
+
SERVER_NAME: str
|
233
|
+
SERVER_PORT: str
|
234
|
+
# The version of the protocol the client used to send the request.
|
235
|
+
# Typically this will be something like "HTTP/1.0" or "HTTP/1.1" and
|
236
|
+
# may be used by the application to determine how to treat any HTTP
|
237
|
+
# request headers. (This variable should probably be called REQUEST_PROTOCOL,
|
238
|
+
# since it denotes the protocol used in the request, and is not necessarily
|
239
|
+
# the protocol that will be used in the server's response. However, for
|
240
|
+
# compatibility with CGI we have to keep the existing name.)
|
241
|
+
SERVER_PROTOCOL: str
|
242
|
+
|
243
|
+
class CGIOptionalDefined(TypedDict, total=False):
|
244
|
+
REQUEST_URI: str
|
245
|
+
REMOTE_ADDR: str
|
246
|
+
REMOTE_PORT: str
|
247
|
+
# The initial portion of the request URL’s “path” that corresponds to the
|
248
|
+
# application object, so that the application knows its virtual “location”.
|
249
|
+
# This may be an empty string, if the application corresponds to the “root”
|
250
|
+
# of the server.
|
251
|
+
SCRIPT_NAME: str
|
252
|
+
# The remainder of the request URL’s “path”, designating the virtual
|
253
|
+
# “location” of the request’s target within the application. This may be an
|
254
|
+
# empty string, if the request URL targets the application root and does
|
255
|
+
# not have a trailing slash.
|
256
|
+
PATH_INFO: str
|
257
|
+
# The portion of the request URL that follows the “?”, if any. May be empty
|
258
|
+
# or absent.
|
259
|
+
QUERY_STRING: str
|
260
|
+
# The contents of any Content-Type fields in the HTTP request. May be empty
|
261
|
+
# or absent.
|
262
|
+
CONTENT_TYPE: str
|
263
|
+
# The contents of any Content-Length fields in the HTTP request. May be empty
|
264
|
+
# or absent.
|
265
|
+
CONTENT_LENGTH: str
|
276
266
|
|
277
267
|
|
278
268
|
class InputStream(Protocol):
|
@@ -308,7 +298,7 @@ class InputStream(Protocol):
|
|
308
298
|
"""
|
309
299
|
raise NotImplementedError
|
310
300
|
|
311
|
-
def readlines(self, hint: int = -1, /) ->
|
301
|
+
def readlines(self, hint: int = -1, /) -> list[bytes]:
|
312
302
|
"""
|
313
303
|
Note that the hint argument to readlines() is optional for both caller and
|
314
304
|
implementer. The application is free not to supply it, and the server or gateway
|
@@ -349,14 +339,14 @@ class ErrorStream(Protocol):
|
|
349
339
|
def write(self, s: str, /) -> Any:
|
350
340
|
raise NotImplementedError
|
351
341
|
|
352
|
-
def writelines(self, seq:
|
342
|
+
def writelines(self, seq: list[str], /) -> Any:
|
353
343
|
raise NotImplementedError
|
354
344
|
|
355
345
|
|
356
346
|
WSGIDefined = TypedDict(
|
357
347
|
"WSGIDefined",
|
358
348
|
{
|
359
|
-
"wsgi.version":
|
349
|
+
"wsgi.version": tuple[int, int], # e.g. (1, 0)
|
360
350
|
"wsgi.url_scheme": str, # e.g. "http" or "https"
|
361
351
|
"wsgi.input": InputStream,
|
362
352
|
"wsgi.errors": ErrorStream,
|
@@ -381,7 +371,7 @@ class Environ(CGIRequiredDefined, CGIOptionalDefined, WSGIDefined):
|
|
381
371
|
"""
|
382
372
|
|
383
373
|
|
384
|
-
ExceptionInfo =
|
374
|
+
ExceptionInfo = tuple[type[BaseException], BaseException, Optional[TracebackType]]
|
385
375
|
|
386
376
|
# https://peps.python.org/pep-3333/#the-write-callable
|
387
377
|
WriteCallable = Callable[[bytes], None]
|
@@ -391,7 +381,7 @@ class StartResponse(Protocol):
|
|
391
381
|
def __call__(
|
392
382
|
self,
|
393
383
|
status: str,
|
394
|
-
response_headers:
|
384
|
+
response_headers: list[tuple[str, str]],
|
395
385
|
exc_info: Optional[ExceptionInfo] = None,
|
396
386
|
/,
|
397
387
|
) -> WriteCallable:
|
@@ -460,7 +450,7 @@ class Body:
|
|
460
450
|
self.buffer.clear()
|
461
451
|
return result
|
462
452
|
|
463
|
-
def readlines(self, hint: int = -1) ->
|
453
|
+
def readlines(self, hint: int = -1) -> list[bytes]:
|
464
454
|
if not self.has_more:
|
465
455
|
return []
|
466
456
|
if hint == -1:
|
@@ -626,7 +616,7 @@ class WSGIResponder:
|
|
626
616
|
def start_response(
|
627
617
|
self,
|
628
618
|
status: str,
|
629
|
-
response_headers:
|
619
|
+
response_headers: list[tuple[str, str]],
|
630
620
|
exc_info: typing.Optional[ExceptionInfo] = None,
|
631
621
|
) -> WriteCallable:
|
632
622
|
self.exc_info = exc_info
|
modal/_vendor/cloudpickle.py
CHANGED
@@ -256,7 +256,7 @@ def _should_pickle_by_reference(obj, name=None):
|
|
256
256
|
return False
|
257
257
|
return obj.__name__ in sys.modules
|
258
258
|
else:
|
259
|
-
raise TypeError("cannot check importability of {
|
259
|
+
raise TypeError(f"cannot check importability of {type(obj).__name__} instances")
|
260
260
|
|
261
261
|
|
262
262
|
def _lookup_module_and_qualname(obj, name=None):
|
modal/_watcher.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Copyright Modal Labs 2022
|
2
2
|
from collections import defaultdict
|
3
|
+
from collections.abc import AsyncGenerator
|
3
4
|
from pathlib import Path
|
4
|
-
from typing import
|
5
|
+
from typing import Optional
|
5
6
|
|
6
7
|
from rich.tree import Tree
|
7
8
|
from watchfiles import Change, DefaultFilter, awatch
|
@@ -21,7 +22,7 @@ class AppFilesFilter(DefaultFilter):
|
|
21
22
|
# Watching specific files is discouraged on Linux, so to watch a file we watch its
|
22
23
|
# containing directory and then filter that directory's changes for relevant files.
|
23
24
|
# https://github.com/notify-rs/notify/issues/394
|
24
|
-
dir_filters:
|
25
|
+
dir_filters: dict[Path, Optional[set[Path]]],
|
25
26
|
) -> None:
|
26
27
|
self.dir_filters = dir_filters
|
27
28
|
super().__init__()
|
@@ -54,7 +55,7 @@ class AppFilesFilter(DefaultFilter):
|
|
54
55
|
return super().__call__(change, path)
|
55
56
|
|
56
57
|
|
57
|
-
async def _watch_paths(paths:
|
58
|
+
async def _watch_paths(paths: set[Path], watch_filter: AppFilesFilter) -> AsyncGenerator[set[str], None]:
|
58
59
|
try:
|
59
60
|
async for changes in awatch(*paths, step=500, watch_filter=watch_filter):
|
60
61
|
changed_paths = {stringpath for _, stringpath in changes}
|
@@ -64,7 +65,7 @@ async def _watch_paths(paths: Set[Path], watch_filter: AppFilesFilter) -> AsyncG
|
|
64
65
|
pass
|
65
66
|
|
66
67
|
|
67
|
-
def _print_watched_paths(paths:
|
68
|
+
def _print_watched_paths(paths: set[Path]):
|
68
69
|
msg = "️️⚡️ Serving... hit Ctrl-C to stop!"
|
69
70
|
|
70
71
|
output_tree = Tree(msg, guide_style="gray50")
|
@@ -76,9 +77,9 @@ def _print_watched_paths(paths: Set[Path]):
|
|
76
77
|
output_mgr.print(output_tree)
|
77
78
|
|
78
79
|
|
79
|
-
def _watch_args_from_mounts(mounts:
|
80
|
+
def _watch_args_from_mounts(mounts: list[_Mount]) -> tuple[set[Path], AppFilesFilter]:
|
80
81
|
paths = set()
|
81
|
-
dir_filters:
|
82
|
+
dir_filters: dict[Path, Optional[set[Path]]] = defaultdict(set)
|
82
83
|
for mount in mounts:
|
83
84
|
# TODO(elias): Make this part of the mount class instead, since it uses so much internals
|
84
85
|
for entry in mount._entries:
|
@@ -94,7 +95,7 @@ def _watch_args_from_mounts(mounts: List[_Mount]) -> Tuple[Set[Path], AppFilesFi
|
|
94
95
|
return paths, watch_filter
|
95
96
|
|
96
97
|
|
97
|
-
async def watch(mounts:
|
98
|
+
async def watch(mounts: list[_Mount]) -> AsyncGenerator[set[str], None]:
|
98
99
|
paths, watch_filter = _watch_args_from_mounts(mounts)
|
99
100
|
|
100
101
|
_print_watched_paths(paths)
|
modal/app.py
CHANGED
@@ -2,19 +2,14 @@
|
|
2
2
|
import inspect
|
3
3
|
import typing
|
4
4
|
import warnings
|
5
|
+
from collections.abc import AsyncGenerator, Coroutine, Sequence
|
5
6
|
from pathlib import PurePosixPath
|
6
7
|
from textwrap import dedent
|
7
8
|
from typing import (
|
8
9
|
Any,
|
9
|
-
AsyncGenerator,
|
10
10
|
Callable,
|
11
11
|
ClassVar,
|
12
|
-
Coroutine,
|
13
|
-
Dict,
|
14
|
-
List,
|
15
12
|
Optional,
|
16
|
-
Sequence,
|
17
|
-
Tuple,
|
18
13
|
Union,
|
19
14
|
overload,
|
20
15
|
)
|
@@ -87,14 +82,14 @@ class _LocalEntrypoint:
|
|
87
82
|
LocalEntrypoint = synchronize_api(_LocalEntrypoint)
|
88
83
|
|
89
84
|
|
90
|
-
def check_sequence(items: typing.Sequence[typing.Any], item_type:
|
85
|
+
def check_sequence(items: typing.Sequence[typing.Any], item_type: type[typing.Any], error_msg: str) -> None:
|
91
86
|
if not isinstance(items, (list, tuple)):
|
92
87
|
raise InvalidError(error_msg)
|
93
88
|
if not all(isinstance(v, item_type) for v in items):
|
94
89
|
raise InvalidError(error_msg)
|
95
90
|
|
96
91
|
|
97
|
-
CLS_T = typing.TypeVar("CLS_T", bound=
|
92
|
+
CLS_T = typing.TypeVar("CLS_T", bound=type[Any])
|
98
93
|
|
99
94
|
|
100
95
|
P = typing_extensions.ParamSpec("P")
|
@@ -172,20 +167,20 @@ class _App:
|
|
172
167
|
In this example, the secret and schedule are registered with the app.
|
173
168
|
"""
|
174
169
|
|
175
|
-
_all_apps: ClassVar[
|
170
|
+
_all_apps: ClassVar[dict[Optional[str], list["_App"]]] = {}
|
176
171
|
_container_app: ClassVar[Optional[RunningApp]] = None
|
177
172
|
|
178
173
|
_name: Optional[str]
|
179
174
|
_description: Optional[str]
|
180
|
-
_functions:
|
181
|
-
_classes:
|
175
|
+
_functions: dict[str, _Function]
|
176
|
+
_classes: dict[str, _Cls]
|
182
177
|
|
183
178
|
_image: Optional[_Image]
|
184
179
|
_mounts: Sequence[_Mount]
|
185
180
|
_secrets: Sequence[_Secret]
|
186
|
-
_volumes:
|
187
|
-
_web_endpoints:
|
188
|
-
_local_entrypoints:
|
181
|
+
_volumes: dict[Union[str, PurePosixPath], _Volume]
|
182
|
+
_web_endpoints: list[str] # Used by the CLI
|
183
|
+
_local_entrypoints: dict[str, _LocalEntrypoint]
|
189
184
|
|
190
185
|
# Running apps only (container apps or running local)
|
191
186
|
_app_id: Optional[str] # Kept after app finishes
|
@@ -199,7 +194,7 @@ class _App:
|
|
199
194
|
image: Optional[_Image] = None, # default image for all functions (default is `modal.Image.debian_slim()`)
|
200
195
|
mounts: Sequence[_Mount] = [], # default mounts for all functions
|
201
196
|
secrets: Sequence[_Secret] = [], # default secrets for all functions
|
202
|
-
volumes:
|
197
|
+
volumes: dict[Union[str, PurePosixPath], _Volume] = {}, # default volumes for all functions
|
203
198
|
) -> None:
|
204
199
|
"""Construct a new app, optionally with default image, mounts, secrets, or volumes.
|
205
200
|
|
@@ -509,22 +504,22 @@ class _App:
|
|
509
504
|
hydrate_objects(self._classes)
|
510
505
|
|
511
506
|
@property
|
512
|
-
def registered_functions(self) ->
|
507
|
+
def registered_functions(self) -> dict[str, _Function]:
|
513
508
|
"""All modal.Function objects registered on the app."""
|
514
509
|
return self._functions
|
515
510
|
|
516
511
|
@property
|
517
|
-
def registered_classes(self) ->
|
512
|
+
def registered_classes(self) -> dict[str, _Function]:
|
518
513
|
"""All modal.Cls objects registered on the app."""
|
519
514
|
return self._classes
|
520
515
|
|
521
516
|
@property
|
522
|
-
def registered_entrypoints(self) ->
|
517
|
+
def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]:
|
523
518
|
"""All local CLI entrypoints registered on the app."""
|
524
519
|
return self._local_entrypoints
|
525
520
|
|
526
521
|
@property
|
527
|
-
def indexed_objects(self) ->
|
522
|
+
def indexed_objects(self) -> dict[str, _Object]:
|
528
523
|
deprecation_warning(
|
529
524
|
(2024, 11, 25),
|
530
525
|
"`app.indexed_objects` is deprecated! Use `app.registered_functions` or `app.registered_classes` instead.",
|
@@ -532,7 +527,7 @@ class _App:
|
|
532
527
|
return dict(**self._functions, **self._classes)
|
533
528
|
|
534
529
|
@property
|
535
|
-
def registered_web_endpoints(self) ->
|
530
|
+
def registered_web_endpoints(self) -> list[str]:
|
536
531
|
"""Names of web endpoint (ie. webhook) functions registered on the app."""
|
537
532
|
return self._web_endpoints
|
538
533
|
|
@@ -611,24 +606,24 @@ class _App:
|
|
611
606
|
schedule: Optional[Schedule] = None, # An optional Modal Schedule for the function
|
612
607
|
secrets: Sequence[_Secret] = (), # Optional Modal Secret objects with environment variables for the container
|
613
608
|
gpu: Union[
|
614
|
-
GPU_T,
|
609
|
+
GPU_T, list[GPU_T]
|
615
610
|
] = None, # GPU request as string ("any", "T4", ...), object (`modal.GPU.A100()`, ...), or a list of either
|
616
611
|
serialized: bool = False, # Whether to send the function over using cloudpickle.
|
617
612
|
mounts: Sequence[_Mount] = (), # Modal Mounts added to the container
|
618
|
-
network_file_systems:
|
613
|
+
network_file_systems: dict[
|
619
614
|
Union[str, PurePosixPath], _NetworkFileSystem
|
620
615
|
] = {}, # Mountpoints for Modal NetworkFileSystems
|
621
|
-
volumes:
|
616
|
+
volumes: dict[
|
622
617
|
Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]
|
623
618
|
] = {}, # Mount points for Modal Volumes & CloudBucketMounts
|
624
619
|
allow_cross_region_volumes: bool = False, # Whether using network file systems from other regions is allowed.
|
625
620
|
# Specify, in fractional CPU cores, how many CPU cores to request.
|
626
621
|
# Or, pass (request, limit) to additionally specify a hard limit in fractional CPU cores.
|
627
622
|
# CPU throttling will prevent a container from exceeding its specified limit.
|
628
|
-
cpu: Optional[Union[float,
|
623
|
+
cpu: Optional[Union[float, tuple[float, float]]] = None,
|
629
624
|
# Specify, in MiB, a memory request which is the minimum memory required.
|
630
625
|
# Or, pass (request, limit) to additionally specify a hard limit in MiB.
|
631
|
-
memory: Optional[Union[int,
|
626
|
+
memory: Optional[Union[int, tuple[int, int]]] = None,
|
632
627
|
ephemeral_disk: Optional[int] = None, # Specify, in MiB, the ephemeral disk size for the Function.
|
633
628
|
proxy: Optional[_Proxy] = None, # Reference to a Modal Proxy to use in front of this function.
|
634
629
|
retries: Optional[Union[int, Retries]] = None, # Number of times to retry each input in case of failure.
|
@@ -817,24 +812,24 @@ class _App:
|
|
817
812
|
image: Optional[_Image] = None, # The image to run as the container for the function
|
818
813
|
secrets: Sequence[_Secret] = (), # Optional Modal Secret objects with environment variables for the container
|
819
814
|
gpu: Union[
|
820
|
-
GPU_T,
|
815
|
+
GPU_T, list[GPU_T]
|
821
816
|
] = None, # GPU request as string ("any", "T4", ...), object (`modal.GPU.A100()`, ...), or a list of either
|
822
817
|
serialized: bool = False, # Whether to send the function over using cloudpickle.
|
823
818
|
mounts: Sequence[_Mount] = (),
|
824
|
-
network_file_systems:
|
819
|
+
network_file_systems: dict[
|
825
820
|
Union[str, PurePosixPath], _NetworkFileSystem
|
826
821
|
] = {}, # Mountpoints for Modal NetworkFileSystems
|
827
|
-
volumes:
|
822
|
+
volumes: dict[
|
828
823
|
Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]
|
829
824
|
] = {}, # Mount points for Modal Volumes & CloudBucketMounts
|
830
825
|
allow_cross_region_volumes: bool = False, # Whether using network file systems from other regions is allowed.
|
831
826
|
# Specify, in fractional CPU cores, how many CPU cores to request.
|
832
827
|
# Or, pass (request, limit) to additionally specify a hard limit in fractional CPU cores.
|
833
828
|
# CPU throttling will prevent a container from exceeding its specified limit.
|
834
|
-
cpu: Optional[Union[float,
|
829
|
+
cpu: Optional[Union[float, tuple[float, float]]] = None,
|
835
830
|
# Specify, in MiB, a memory request which is the minimum memory required.
|
836
831
|
# Or, pass (request, limit) to additionally specify a hard limit in MiB.
|
837
|
-
memory: Optional[Union[int,
|
832
|
+
memory: Optional[Union[int, tuple[int, int]]] = None,
|
838
833
|
ephemeral_disk: Optional[int] = None, # Specify, in MiB, the ephemeral disk size for the Function.
|
839
834
|
proxy: Optional[_Proxy] = None, # Reference to a Modal Proxy to use in front of this function.
|
840
835
|
retries: Optional[Union[int, Retries]] = None, # Number of times to retry each input in case of failure.
|
@@ -948,7 +943,7 @@ class _App:
|
|
948
943
|
image: Optional[_Image] = None, # The image to run as the container for the sandbox.
|
949
944
|
mounts: Sequence[_Mount] = (), # Mounts to attach to the sandbox.
|
950
945
|
secrets: Sequence[_Secret] = (), # Environment variables to inject into the sandbox.
|
951
|
-
network_file_systems:
|
946
|
+
network_file_systems: dict[Union[str, PurePosixPath], _NetworkFileSystem] = {},
|
952
947
|
timeout: Optional[int] = None, # Maximum execution time of the sandbox in seconds.
|
953
948
|
workdir: Optional[str] = None, # Working directory of the sandbox.
|
954
949
|
gpu: GPU_T = None,
|
@@ -957,12 +952,12 @@ class _App:
|
|
957
952
|
# Specify, in fractional CPU cores, how many CPU cores to request.
|
958
953
|
# Or, pass (request, limit) to additionally specify a hard limit in fractional CPU cores.
|
959
954
|
# CPU throttling will prevent a container from exceeding its specified limit.
|
960
|
-
cpu: Optional[Union[float,
|
955
|
+
cpu: Optional[Union[float, tuple[float, float]]] = None,
|
961
956
|
# Specify, in MiB, a memory request which is the minimum memory required.
|
962
957
|
# Or, pass (request, limit) to additionally specify a hard limit in MiB.
|
963
|
-
memory: Optional[Union[int,
|
958
|
+
memory: Optional[Union[int, tuple[int, int]]] = None,
|
964
959
|
block_network: bool = False, # Whether to block network access
|
965
|
-
volumes:
|
960
|
+
volumes: dict[
|
966
961
|
Union[str, PurePosixPath], Union[_Volume, _CloudBucketMount]
|
967
962
|
] = {}, # Mount points for Modal Volumes and CloudBucketMounts
|
968
963
|
pty_info: Optional[api_pb2.PTYInfo] = None,
|