modal 1.0.3.dev10__py3-none-any.whl → 1.2.3.dev7__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.
Potentially problematic release.
This version of modal might be problematic. Click here for more details.
- modal/__init__.py +0 -2
- modal/__main__.py +3 -4
- modal/_billing.py +80 -0
- modal/_clustered_functions.py +7 -3
- modal/_clustered_functions.pyi +15 -3
- modal/_container_entrypoint.py +51 -69
- modal/_functions.py +508 -240
- modal/_grpc_client.py +171 -0
- modal/_load_context.py +105 -0
- modal/_object.py +81 -21
- modal/_output.py +58 -45
- modal/_partial_function.py +48 -73
- modal/_pty.py +7 -3
- modal/_resolver.py +26 -46
- modal/_runtime/asgi.py +4 -3
- modal/_runtime/container_io_manager.py +358 -220
- modal/_runtime/container_io_manager.pyi +296 -101
- modal/_runtime/execution_context.py +18 -2
- modal/_runtime/execution_context.pyi +64 -7
- modal/_runtime/gpu_memory_snapshot.py +262 -57
- modal/_runtime/user_code_imports.py +28 -58
- modal/_serialization.py +90 -6
- modal/_traceback.py +42 -1
- modal/_tunnel.pyi +380 -12
- modal/_utils/async_utils.py +84 -29
- modal/_utils/auth_token_manager.py +111 -0
- modal/_utils/blob_utils.py +181 -58
- modal/_utils/deprecation.py +19 -0
- modal/_utils/function_utils.py +91 -47
- modal/_utils/grpc_utils.py +89 -66
- modal/_utils/mount_utils.py +26 -1
- modal/_utils/name_utils.py +17 -3
- modal/_utils/task_command_router_client.py +536 -0
- modal/_utils/time_utils.py +34 -6
- modal/app.py +256 -88
- modal/app.pyi +909 -92
- modal/billing.py +5 -0
- modal/builder/2025.06.txt +18 -0
- modal/builder/PREVIEW.txt +18 -0
- modal/builder/base-images.json +58 -0
- modal/cli/_download.py +19 -3
- modal/cli/_traceback.py +3 -2
- modal/cli/app.py +4 -4
- modal/cli/cluster.py +15 -7
- modal/cli/config.py +5 -3
- modal/cli/container.py +7 -6
- modal/cli/dict.py +22 -16
- modal/cli/entry_point.py +12 -5
- modal/cli/environment.py +5 -4
- modal/cli/import_refs.py +3 -3
- modal/cli/launch.py +102 -5
- modal/cli/network_file_system.py +11 -12
- modal/cli/profile.py +3 -2
- modal/cli/programs/launch_instance_ssh.py +94 -0
- modal/cli/programs/run_jupyter.py +1 -1
- modal/cli/programs/run_marimo.py +95 -0
- modal/cli/programs/vscode.py +1 -1
- modal/cli/queues.py +57 -26
- modal/cli/run.py +91 -23
- modal/cli/secret.py +48 -22
- modal/cli/token.py +7 -8
- modal/cli/utils.py +4 -7
- modal/cli/volume.py +31 -25
- modal/client.py +15 -85
- modal/client.pyi +183 -62
- modal/cloud_bucket_mount.py +5 -3
- modal/cloud_bucket_mount.pyi +197 -5
- modal/cls.py +200 -126
- modal/cls.pyi +446 -68
- modal/config.py +29 -11
- modal/container_process.py +319 -19
- modal/container_process.pyi +190 -20
- modal/dict.py +290 -71
- modal/dict.pyi +835 -83
- modal/environments.py +15 -27
- modal/environments.pyi +46 -24
- modal/exception.py +14 -2
- modal/experimental/__init__.py +194 -40
- modal/experimental/flash.py +618 -0
- modal/experimental/flash.pyi +380 -0
- modal/experimental/ipython.py +11 -7
- modal/file_io.py +29 -36
- modal/file_io.pyi +251 -53
- modal/file_pattern_matcher.py +56 -16
- modal/functions.pyi +673 -92
- modal/gpu.py +1 -1
- modal/image.py +528 -176
- modal/image.pyi +1572 -145
- modal/io_streams.py +458 -128
- modal/io_streams.pyi +433 -52
- modal/mount.py +216 -151
- modal/mount.pyi +225 -78
- modal/network_file_system.py +45 -62
- modal/network_file_system.pyi +277 -56
- modal/object.pyi +93 -17
- modal/parallel_map.py +942 -129
- modal/parallel_map.pyi +294 -15
- modal/partial_function.py +0 -2
- modal/partial_function.pyi +234 -19
- modal/proxy.py +17 -8
- modal/proxy.pyi +36 -3
- modal/queue.py +270 -65
- modal/queue.pyi +817 -57
- modal/runner.py +115 -101
- modal/runner.pyi +205 -49
- modal/sandbox.py +512 -136
- modal/sandbox.pyi +845 -111
- modal/schedule.py +1 -1
- modal/secret.py +300 -70
- modal/secret.pyi +589 -34
- modal/serving.py +7 -11
- modal/serving.pyi +7 -8
- modal/snapshot.py +11 -8
- modal/snapshot.pyi +25 -4
- modal/token_flow.py +4 -4
- modal/token_flow.pyi +28 -8
- modal/volume.py +416 -158
- modal/volume.pyi +1117 -121
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
- modal-1.2.3.dev7.dist-info/RECORD +195 -0
- modal_docs/mdmd/mdmd.py +17 -4
- modal_proto/api.proto +534 -79
- modal_proto/api_grpc.py +337 -1
- modal_proto/api_pb2.py +1522 -968
- modal_proto/api_pb2.pyi +1619 -134
- modal_proto/api_pb2_grpc.py +699 -4
- modal_proto/api_pb2_grpc.pyi +226 -14
- modal_proto/modal_api_grpc.py +175 -154
- modal_proto/sandbox_router.proto +145 -0
- modal_proto/sandbox_router_grpc.py +105 -0
- modal_proto/sandbox_router_pb2.py +149 -0
- modal_proto/sandbox_router_pb2.pyi +333 -0
- modal_proto/sandbox_router_pb2_grpc.py +203 -0
- modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
- modal_proto/task_command_router.proto +144 -0
- modal_proto/task_command_router_grpc.py +105 -0
- modal_proto/task_command_router_pb2.py +149 -0
- modal_proto/task_command_router_pb2.pyi +333 -0
- modal_proto/task_command_router_pb2_grpc.py +203 -0
- modal_proto/task_command_router_pb2_grpc.pyi +75 -0
- modal_version/__init__.py +1 -1
- modal/requirements/PREVIEW.txt +0 -16
- modal/requirements/base-images.json +0 -26
- modal-1.0.3.dev10.dist-info/RECORD +0 -179
- modal_proto/modal_options_grpc.py +0 -3
- modal_proto/options.proto +0 -19
- modal_proto/options_grpc.py +0 -3
- modal_proto/options_pb2.py +0 -35
- modal_proto/options_pb2.pyi +0 -20
- modal_proto/options_pb2_grpc.py +0 -4
- modal_proto/options_pb2_grpc.pyi +0 -7
- /modal/{requirements → builder}/2023.12.312.txt +0 -0
- /modal/{requirements → builder}/2023.12.txt +0 -0
- /modal/{requirements → builder}/2024.04.txt +0 -0
- /modal/{requirements → builder}/2024.10.txt +0 -0
- /modal/{requirements → builder}/README.md +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/top_level.txt +0 -0
modal/partial_function.pyi
CHANGED
|
@@ -9,6 +9,11 @@ class PartialFunction(
|
|
|
9
9
|
modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.OriginalReturnType
|
|
10
10
|
]
|
|
11
11
|
):
|
|
12
|
+
"""Object produced by a decorator in the `modal` namespace
|
|
13
|
+
|
|
14
|
+
The object will eventually by consumed by an App decorator.
|
|
15
|
+
"""
|
|
16
|
+
|
|
12
17
|
raw_f: typing.Optional[collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]]
|
|
13
18
|
user_cls: typing.Optional[type]
|
|
14
19
|
flags: modal._partial_function._PartialFunctionFlags
|
|
@@ -27,11 +32,20 @@ class PartialFunction(
|
|
|
27
32
|
self,
|
|
28
33
|
flags: modal._partial_function._PartialFunctionFlags,
|
|
29
34
|
params: modal._partial_function._PartialFunctionParams,
|
|
30
|
-
) -> typing_extensions.Self:
|
|
31
|
-
|
|
35
|
+
) -> typing_extensions.Self:
|
|
36
|
+
"""Implement decorator composition by combining the flags and params."""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
def validate_flag_composition(self) -> None:
|
|
40
|
+
"""Validate decorator composition based on PartialFunctionFlags."""
|
|
41
|
+
...
|
|
42
|
+
|
|
32
43
|
def validate_obj_compatibility(
|
|
33
44
|
self, decorator_name: str, require_sync: bool = False, require_nullary: bool = False
|
|
34
|
-
) -> None:
|
|
45
|
+
) -> None:
|
|
46
|
+
"""Enforce compatibility with the wrapped object; called from individual decorator functions."""
|
|
47
|
+
...
|
|
48
|
+
|
|
35
49
|
def _get_raw_f(self) -> collections.abc.Callable[modal._partial_function.P, modal._partial_function.ReturnType]: ...
|
|
36
50
|
def _is_web_endpoint(self) -> bool: ...
|
|
37
51
|
def __get__(
|
|
@@ -43,7 +57,22 @@ class PartialFunction(
|
|
|
43
57
|
|
|
44
58
|
def method(
|
|
45
59
|
_warn_parentheses_missing=None, *, is_generator: typing.Optional[bool] = None
|
|
46
|
-
) -> modal._partial_function._MethodDecoratorType:
|
|
60
|
+
) -> modal._partial_function._MethodDecoratorType:
|
|
61
|
+
"""Decorator for methods that should be transformed into a Modal Function registered against this class's App.
|
|
62
|
+
|
|
63
|
+
**Usage:**
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
@app.cls(cpu=8)
|
|
67
|
+
class MyCls:
|
|
68
|
+
|
|
69
|
+
@modal.method()
|
|
70
|
+
def f(self):
|
|
71
|
+
...
|
|
72
|
+
```
|
|
73
|
+
"""
|
|
74
|
+
...
|
|
75
|
+
|
|
47
76
|
def web_endpoint(
|
|
48
77
|
_warn_parentheses_missing=None,
|
|
49
78
|
*,
|
|
@@ -62,7 +91,25 @@ def web_endpoint(
|
|
|
62
91
|
]
|
|
63
92
|
],
|
|
64
93
|
PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
|
|
65
|
-
]:
|
|
94
|
+
]:
|
|
95
|
+
"""Register a basic web endpoint with this application.
|
|
96
|
+
|
|
97
|
+
DEPRECATED: This decorator has been renamed to `@modal.fastapi_endpoint`.
|
|
98
|
+
|
|
99
|
+
This is the simple way to create a web endpoint on Modal. The function
|
|
100
|
+
behaves as a [FastAPI](https://fastapi.tiangolo.com/) handler and should
|
|
101
|
+
return a response object to the caller.
|
|
102
|
+
|
|
103
|
+
Endpoints created with `@modal.web_endpoint` are meant to be simple, single
|
|
104
|
+
request handlers and automatically have
|
|
105
|
+
[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) enabled.
|
|
106
|
+
For more flexibility, use `@modal.asgi_app`.
|
|
107
|
+
|
|
108
|
+
To learn how to use Modal with popular web frameworks, see the
|
|
109
|
+
[guide on web endpoints](https://modal.com/docs/guide/webhooks).
|
|
110
|
+
"""
|
|
111
|
+
...
|
|
112
|
+
|
|
66
113
|
def fastapi_endpoint(
|
|
67
114
|
_warn_parentheses_missing=None,
|
|
68
115
|
*,
|
|
@@ -81,7 +128,24 @@ def fastapi_endpoint(
|
|
|
81
128
|
]
|
|
82
129
|
],
|
|
83
130
|
PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
|
|
84
|
-
]:
|
|
131
|
+
]:
|
|
132
|
+
"""Convert a function into a basic web endpoint by wrapping it with a FastAPI App.
|
|
133
|
+
|
|
134
|
+
Modal will internally use [FastAPI](https://fastapi.tiangolo.com/) to expose a
|
|
135
|
+
simple, single request handler. If you are defining your own `FastAPI` application
|
|
136
|
+
(e.g. if you want to define multiple routes), use `@modal.asgi_app` instead.
|
|
137
|
+
|
|
138
|
+
The endpoint created with this decorator will automatically have
|
|
139
|
+
[CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) enabled
|
|
140
|
+
and can leverage many of FastAPI's features.
|
|
141
|
+
|
|
142
|
+
For more information on using Modal with popular web frameworks, see our
|
|
143
|
+
[guide on web endpoints](https://modal.com/docs/guide/webhooks).
|
|
144
|
+
|
|
145
|
+
*Added in v0.73.82*: This function replaces the deprecated `@web_endpoint` decorator.
|
|
146
|
+
"""
|
|
147
|
+
...
|
|
148
|
+
|
|
85
149
|
def asgi_app(
|
|
86
150
|
_warn_parentheses_missing=None,
|
|
87
151
|
*,
|
|
@@ -97,7 +161,30 @@ def asgi_app(
|
|
|
97
161
|
]
|
|
98
162
|
],
|
|
99
163
|
PartialFunction,
|
|
100
|
-
]:
|
|
164
|
+
]:
|
|
165
|
+
"""Decorator for registering an ASGI app with a Modal function.
|
|
166
|
+
|
|
167
|
+
Asynchronous Server Gateway Interface (ASGI) is a standard for Python
|
|
168
|
+
synchronous and asynchronous apps, supported by all popular Python web
|
|
169
|
+
libraries. This is an advanced decorator that gives full flexibility in
|
|
170
|
+
defining one or more web endpoints on Modal.
|
|
171
|
+
|
|
172
|
+
**Usage:**
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from typing import Callable
|
|
176
|
+
|
|
177
|
+
@app.function()
|
|
178
|
+
@modal.asgi_app()
|
|
179
|
+
def create_asgi() -> Callable:
|
|
180
|
+
...
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
To learn how to use Modal with popular web frameworks, see the
|
|
184
|
+
[guide on web endpoints](https://modal.com/docs/guide/webhooks).
|
|
185
|
+
"""
|
|
186
|
+
...
|
|
187
|
+
|
|
101
188
|
def wsgi_app(
|
|
102
189
|
_warn_parentheses_missing=None,
|
|
103
190
|
*,
|
|
@@ -113,7 +200,30 @@ def wsgi_app(
|
|
|
113
200
|
]
|
|
114
201
|
],
|
|
115
202
|
PartialFunction,
|
|
116
|
-
]:
|
|
203
|
+
]:
|
|
204
|
+
"""Decorator for registering a WSGI app with a Modal function.
|
|
205
|
+
|
|
206
|
+
Web Server Gateway Interface (WSGI) is a standard for synchronous Python web apps.
|
|
207
|
+
It has been [succeeded by the ASGI interface](https://asgi.readthedocs.io/en/latest/introduction.html#wsgi-compatibility)
|
|
208
|
+
which is compatible with ASGI and supports additional functionality such as web sockets.
|
|
209
|
+
Modal supports ASGI via [`asgi_app`](https://modal.com/docs/reference/modal.asgi_app).
|
|
210
|
+
|
|
211
|
+
**Usage:**
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from typing import Callable
|
|
215
|
+
|
|
216
|
+
@app.function()
|
|
217
|
+
@modal.wsgi_app()
|
|
218
|
+
def create_wsgi() -> Callable:
|
|
219
|
+
...
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
To learn how to use this decorator with popular web frameworks, see the
|
|
223
|
+
[guide on web endpoints](https://modal.com/docs/guide/webhooks).
|
|
224
|
+
"""
|
|
225
|
+
...
|
|
226
|
+
|
|
117
227
|
def web_server(
|
|
118
228
|
port: int,
|
|
119
229
|
*,
|
|
@@ -130,20 +240,55 @@ def web_server(
|
|
|
130
240
|
]
|
|
131
241
|
],
|
|
132
242
|
PartialFunction,
|
|
133
|
-
]:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
243
|
+
]:
|
|
244
|
+
"""Decorator that registers an HTTP web server inside the container.
|
|
245
|
+
|
|
246
|
+
This is similar to `@asgi_app` and `@wsgi_app`, but it allows you to expose a full HTTP server
|
|
247
|
+
listening on a container port. This is useful for servers written in other languages like Rust,
|
|
248
|
+
as well as integrating with non-ASGI frameworks like aiohttp and Tornado.
|
|
249
|
+
|
|
250
|
+
**Usage:**
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
import subprocess
|
|
254
|
+
|
|
255
|
+
@app.function()
|
|
256
|
+
@modal.web_server(8000)
|
|
257
|
+
def my_file_server():
|
|
258
|
+
subprocess.Popen("python -m http.server -d / 8000", shell=True)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The above example starts a simple file server, displaying the contents of the root directory.
|
|
262
|
+
Here, requests to the web endpoint will go to external port 8000 on the container. The
|
|
263
|
+
`http.server` module is included with Python, but you could run anything here.
|
|
264
|
+
|
|
265
|
+
Internally, the web server is transparently converted into a web endpoint by Modal, so it has
|
|
266
|
+
the same serverless autoscaling behavior as other web endpoints.
|
|
267
|
+
|
|
268
|
+
For more info, see the [guide on web endpoints](https://modal.com/docs/guide/webhooks).
|
|
269
|
+
"""
|
|
270
|
+
...
|
|
271
|
+
|
|
139
272
|
def enter(
|
|
140
273
|
_warn_parentheses_missing=None, *, snap: bool = False
|
|
141
274
|
) -> collections.abc.Callable[
|
|
142
275
|
[typing.Union[PartialFunction, collections.abc.Callable[[typing.Any], typing.Any]]], PartialFunction
|
|
143
|
-
]:
|
|
276
|
+
]:
|
|
277
|
+
"""Decorator for methods which should be executed when a new container is started.
|
|
278
|
+
|
|
279
|
+
See the [lifeycle function guide](https://modal.com/docs/guide/lifecycle-functions#enter) for more information.
|
|
280
|
+
"""
|
|
281
|
+
...
|
|
282
|
+
|
|
144
283
|
def exit(
|
|
145
284
|
_warn_parentheses_missing=None,
|
|
146
|
-
) -> collections.abc.Callable[[collections.abc.Callable[[typing.Any], typing.Any]], PartialFunction]:
|
|
285
|
+
) -> collections.abc.Callable[[collections.abc.Callable[[typing.Any], typing.Any]], PartialFunction]:
|
|
286
|
+
"""Decorator for methods which should be executed when a container is about to exit.
|
|
287
|
+
|
|
288
|
+
See the [lifeycle function guide](https://modal.com/docs/guide/lifecycle-functions#exit) for more information.
|
|
289
|
+
"""
|
|
290
|
+
...
|
|
291
|
+
|
|
147
292
|
def batched(
|
|
148
293
|
_warn_parentheses_missing=None, *, max_batch_size: int, wait_ms: int
|
|
149
294
|
) -> collections.abc.Callable[
|
|
@@ -156,9 +301,38 @@ def batched(
|
|
|
156
301
|
]
|
|
157
302
|
],
|
|
158
303
|
PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
|
|
159
|
-
]:
|
|
304
|
+
]:
|
|
305
|
+
"""Decorator for functions or class methods that should be batched.
|
|
306
|
+
|
|
307
|
+
**Usage**
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
# Stack the decorator under `@app.function()` to enable dynamic batching
|
|
311
|
+
@app.function()
|
|
312
|
+
@modal.batched(max_batch_size=4, wait_ms=1000)
|
|
313
|
+
async def batched_multiply(xs: list[int], ys: list[int]) -> list[int]:
|
|
314
|
+
return [x * y for x, y in zip(xs, ys)]
|
|
315
|
+
|
|
316
|
+
# call batched_multiply with individual inputs
|
|
317
|
+
# batched_multiply.remote.aio(2, 100)
|
|
318
|
+
|
|
319
|
+
# With `@app.cls()`, apply the decorator to a method (this may change in the future)
|
|
320
|
+
@app.cls()
|
|
321
|
+
class BatchedClass:
|
|
322
|
+
@modal.batched(max_batch_size=4, wait_ms=1000)
|
|
323
|
+
def batched_multiply(self, xs: list[int], ys: list[int]) -> list[int]:
|
|
324
|
+
return [x * y for x, y in zip(xs, ys)]
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
See the [dynamic batching guide](https://modal.com/docs/guide/dynamic-batching) for more information.
|
|
328
|
+
"""
|
|
329
|
+
...
|
|
330
|
+
|
|
160
331
|
def concurrent(
|
|
161
|
-
_warn_parentheses_missing=None,
|
|
332
|
+
_warn_parentheses_missing=None,
|
|
333
|
+
*,
|
|
334
|
+
max_inputs: typing.Optional[int] = None,
|
|
335
|
+
target_inputs: typing.Optional[int] = None,
|
|
162
336
|
) -> collections.abc.Callable[
|
|
163
337
|
[
|
|
164
338
|
typing.Union[
|
|
@@ -169,4 +343,45 @@ def concurrent(
|
|
|
169
343
|
]
|
|
170
344
|
],
|
|
171
345
|
PartialFunction[modal._partial_function.P, modal._partial_function.ReturnType, modal._partial_function.ReturnType],
|
|
172
|
-
]:
|
|
346
|
+
]:
|
|
347
|
+
"""Decorator that allows individual containers to handle multiple inputs concurrently.
|
|
348
|
+
|
|
349
|
+
The concurrency mechanism depends on whether the function is async or not:
|
|
350
|
+
- Async functions will run inputs on a single thread as asyncio tasks.
|
|
351
|
+
- Synchronous functions will use multi-threading. The code must be thread-safe.
|
|
352
|
+
|
|
353
|
+
Input concurrency will be most useful for workflows that are IO-bound
|
|
354
|
+
(e.g., making network requests) or when running an inference server that supports
|
|
355
|
+
dynamic batching.
|
|
356
|
+
|
|
357
|
+
When `target_inputs` is set, Modal's autoscaler will try to provision resources
|
|
358
|
+
such that each container is running that many inputs concurrently, rather than
|
|
359
|
+
autoscaling based on `max_inputs`. Containers may burst up to up to `max_inputs`
|
|
360
|
+
if resources are insufficient to remain at the target concurrency, e.g. when the
|
|
361
|
+
arrival rate of inputs increases. This can trade-off a small increase in average
|
|
362
|
+
latency to avoid larger tail latencies from input queuing.
|
|
363
|
+
|
|
364
|
+
**Examples:**
|
|
365
|
+
```python
|
|
366
|
+
# Stack the decorator under `@app.function()` to enable input concurrency
|
|
367
|
+
@app.function()
|
|
368
|
+
@modal.concurrent(max_inputs=100)
|
|
369
|
+
async def f(data):
|
|
370
|
+
# Async function; will be scheduled as asyncio task
|
|
371
|
+
...
|
|
372
|
+
|
|
373
|
+
# With `@app.cls()`, apply the decorator at the class level, not on individual methods
|
|
374
|
+
@app.cls()
|
|
375
|
+
@modal.concurrent(max_inputs=100, target_inputs=80)
|
|
376
|
+
class C:
|
|
377
|
+
@modal.method()
|
|
378
|
+
def f(self, data):
|
|
379
|
+
# Sync function; must be thread-safe
|
|
380
|
+
...
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
*Added in v0.73.148:* This decorator replaces the `allow_concurrent_inputs` parameter
|
|
385
|
+
in `@app.function()` and `@app.cls()`.
|
|
386
|
+
"""
|
|
387
|
+
...
|
modal/proxy.py
CHANGED
|
@@ -3,16 +3,18 @@ from typing import Optional
|
|
|
3
3
|
|
|
4
4
|
from modal_proto import api_pb2
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from ._load_context import LoadContext
|
|
7
|
+
from ._object import _Object
|
|
7
8
|
from ._resolver import Resolver
|
|
8
9
|
from ._utils.async_utils import synchronize_api
|
|
10
|
+
from .client import _Client
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
class _Proxy(_Object, type_prefix="pr"):
|
|
12
14
|
"""Proxy objects give your Modal containers a static outbound IP address.
|
|
13
15
|
|
|
14
16
|
This can be used for connecting to a remote address with network whitelist, for example
|
|
15
|
-
a database. See [the guide](/docs/guide/proxy-ips) for more information.
|
|
17
|
+
a database. See [the guide](https://modal.com/docs/guide/proxy-ips) for more information.
|
|
16
18
|
"""
|
|
17
19
|
|
|
18
20
|
@staticmethod
|
|
@@ -20,6 +22,7 @@ class _Proxy(_Object, type_prefix="pr"):
|
|
|
20
22
|
name: str,
|
|
21
23
|
*,
|
|
22
24
|
environment_name: Optional[str] = None,
|
|
25
|
+
client: Optional[_Client] = None,
|
|
23
26
|
) -> "_Proxy":
|
|
24
27
|
"""Reference a Proxy by its name.
|
|
25
28
|
|
|
@@ -28,15 +31,21 @@ class _Proxy(_Object, type_prefix="pr"):
|
|
|
28
31
|
|
|
29
32
|
"""
|
|
30
33
|
|
|
31
|
-
async def _load(self: _Proxy, resolver: Resolver, existing_object_id: Optional[str]):
|
|
34
|
+
async def _load(self: _Proxy, resolver: Resolver, load_context: LoadContext, existing_object_id: Optional[str]):
|
|
32
35
|
req = api_pb2.ProxyGetRequest(
|
|
33
36
|
name=name,
|
|
34
|
-
environment_name=
|
|
37
|
+
environment_name=load_context.environment_name,
|
|
35
38
|
)
|
|
36
|
-
response: api_pb2.ProxyGetResponse = await
|
|
37
|
-
self._hydrate(response.proxy.proxy_id,
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
response: api_pb2.ProxyGetResponse = await load_context.client.stub.ProxyGet(req)
|
|
40
|
+
self._hydrate(response.proxy.proxy_id, load_context.client, None)
|
|
41
|
+
|
|
42
|
+
rep = _Proxy._repr(name, environment_name)
|
|
43
|
+
return _Proxy._from_loader(
|
|
44
|
+
_load,
|
|
45
|
+
rep,
|
|
46
|
+
is_another_app=True,
|
|
47
|
+
load_context_overrides=LoadContext(client=client, environment_name=environment_name),
|
|
48
|
+
)
|
|
40
49
|
|
|
41
50
|
|
|
42
51
|
Proxy = synchronize_api(_Proxy, target_module=__name__)
|
modal/proxy.pyi
CHANGED
|
@@ -1,12 +1,45 @@
|
|
|
1
1
|
import modal._object
|
|
2
|
+
import modal.client
|
|
2
3
|
import modal.object
|
|
3
4
|
import typing
|
|
4
5
|
|
|
5
6
|
class _Proxy(modal._object._Object):
|
|
7
|
+
"""Proxy objects give your Modal containers a static outbound IP address.
|
|
8
|
+
|
|
9
|
+
This can be used for connecting to a remote address with network whitelist, for example
|
|
10
|
+
a database. See [the guide](https://modal.com/docs/guide/proxy-ips) for more information.
|
|
11
|
+
"""
|
|
6
12
|
@staticmethod
|
|
7
|
-
def from_name(
|
|
13
|
+
def from_name(
|
|
14
|
+
name: str,
|
|
15
|
+
*,
|
|
16
|
+
environment_name: typing.Optional[str] = None,
|
|
17
|
+
client: typing.Optional[modal.client._Client] = None,
|
|
18
|
+
) -> _Proxy:
|
|
19
|
+
"""Reference a Proxy by its name.
|
|
20
|
+
|
|
21
|
+
In contrast to most other Modal objects, new Proxy objects must be
|
|
22
|
+
provisioned via the Dashboard and cannot be created on the fly from code.
|
|
23
|
+
"""
|
|
24
|
+
...
|
|
8
25
|
|
|
9
26
|
class Proxy(modal.object.Object):
|
|
10
|
-
|
|
27
|
+
"""Proxy objects give your Modal containers a static outbound IP address.
|
|
28
|
+
|
|
29
|
+
This can be used for connecting to a remote address with network whitelist, for example
|
|
30
|
+
a database. See [the guide](https://modal.com/docs/guide/proxy-ips) for more information.
|
|
31
|
+
"""
|
|
32
|
+
def __init__(self, *args, **kwargs):
|
|
33
|
+
"""mdmd:hidden"""
|
|
34
|
+
...
|
|
35
|
+
|
|
11
36
|
@staticmethod
|
|
12
|
-
def from_name(
|
|
37
|
+
def from_name(
|
|
38
|
+
name: str, *, environment_name: typing.Optional[str] = None, client: typing.Optional[modal.client.Client] = None
|
|
39
|
+
) -> Proxy:
|
|
40
|
+
"""Reference a Proxy by its name.
|
|
41
|
+
|
|
42
|
+
In contrast to most other Modal objects, new Proxy objects must be
|
|
43
|
+
provisioned via the Dashboard and cannot be created on the fly from code.
|
|
44
|
+
"""
|
|
45
|
+
...
|