modal 1.0.4.dev10__py3-none-any.whl → 1.0.5__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.pyi +13 -3
- modal/_functions.py +84 -46
- modal/_partial_function.py +1 -1
- modal/_runtime/container_io_manager.pyi +222 -40
- modal/_runtime/execution_context.pyi +60 -6
- modal/_serialization.py +25 -2
- modal/_tunnel.pyi +380 -12
- modal/_utils/async_utils.py +1 -1
- modal/_utils/blob_utils.py +56 -19
- modal/_utils/function_utils.py +33 -7
- modal/_utils/grpc_utils.py +11 -4
- modal/app.py +5 -5
- modal/app.pyi +658 -48
- modal/cli/run.py +2 -1
- modal/client.pyi +224 -36
- modal/cloud_bucket_mount.pyi +192 -4
- modal/cls.py +57 -16
- modal/cls.pyi +442 -34
- modal/container_process.pyi +103 -14
- modal/dict.py +4 -4
- modal/dict.pyi +453 -51
- modal/environments.pyi +41 -9
- modal/exception.py +6 -2
- modal/experimental/__init__.py +90 -0
- modal/experimental/ipython.py +11 -7
- modal/file_io.pyi +236 -45
- modal/functions.pyi +573 -65
- modal/gpu.py +1 -1
- modal/image.py +1 -1
- modal/image.pyi +1256 -74
- modal/io_streams.py +8 -4
- modal/io_streams.pyi +348 -38
- modal/mount.pyi +261 -31
- modal/network_file_system.py +3 -3
- modal/network_file_system.pyi +307 -26
- modal/object.pyi +48 -9
- modal/parallel_map.py +93 -19
- modal/parallel_map.pyi +160 -15
- modal/partial_function.pyi +255 -14
- modal/proxy.py +1 -1
- modal/proxy.pyi +28 -3
- modal/queue.py +4 -4
- modal/queue.pyi +447 -30
- modal/runner.pyi +160 -22
- modal/sandbox.py +8 -7
- modal/sandbox.pyi +310 -50
- modal/schedule.py +1 -1
- modal/secret.py +2 -2
- modal/secret.pyi +164 -15
- modal/snapshot.pyi +25 -4
- modal/token_flow.pyi +28 -8
- modal/volume.py +41 -4
- modal/volume.pyi +693 -59
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/METADATA +3 -3
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/RECORD +67 -67
- modal_proto/api.proto +57 -0
- modal_proto/api_grpc.py +48 -0
- modal_proto/api_pb2.py +874 -780
- modal_proto/api_pb2.pyi +198 -9
- modal_proto/api_pb2_grpc.py +100 -0
- modal_proto/api_pb2_grpc.pyi +32 -0
- modal_proto/modal_api_grpc.py +3 -0
- modal_version/__init__.py +1 -1
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/WHEEL +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/entry_points.txt +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/licenses/LICENSE +0 -0
- {modal-1.0.4.dev10.dist-info → modal-1.0.5.dist-info}/top_level.txt +0 -0
modal/cls.pyi
CHANGED
@@ -24,6 +24,8 @@ def _use_annotation_parameters(user_cls: type) -> bool: ...
|
|
24
24
|
def _get_class_constructor_signature(user_cls: type) -> inspect.Signature: ...
|
25
25
|
|
26
26
|
class _ServiceOptions:
|
27
|
+
"""_ServiceOptions(secrets: Collection[modal.secret._Secret] = (), validated_volumes: Sequence[tuple[str, modal.volume._Volume]] = (), resources: Optional[modal_proto.api_pb2.Resources] = None, retry_policy: Optional[modal_proto.api_pb2.FunctionRetryPolicy] = None, max_containers: Optional[int] = None, buffer_containers: Optional[int] = None, scaledown_window: Optional[int] = None, timeout_secs: Optional[int] = None, max_concurrent_inputs: Optional[int] = None, target_concurrent_inputs: Optional[int] = None, batch_max_size: Optional[int] = None, batch_wait_ms: Optional[int] = None)"""
|
28
|
+
|
27
29
|
secrets: typing.Collection[modal.secret._Secret]
|
28
30
|
validated_volumes: typing.Sequence[tuple[str, modal.volume._Volume]]
|
29
31
|
resources: typing.Optional[modal_proto.api_pb2.Resources]
|
@@ -37,6 +39,13 @@ class _ServiceOptions:
|
|
37
39
|
batch_max_size: typing.Optional[int]
|
38
40
|
batch_wait_ms: typing.Optional[int]
|
39
41
|
|
42
|
+
def merge_options(self, new_options: _ServiceOptions) -> _ServiceOptions:
|
43
|
+
"""Implement protobuf-like MergeFrom semantics for this dataclass.
|
44
|
+
|
45
|
+
This mostly exists to support "stacking" of `.with_options()` calls.
|
46
|
+
"""
|
47
|
+
...
|
48
|
+
|
40
49
|
def __init__(
|
41
50
|
self,
|
42
51
|
secrets: typing.Collection[modal.secret._Secret] = (),
|
@@ -51,13 +60,32 @@ class _ServiceOptions:
|
|
51
60
|
target_concurrent_inputs: typing.Optional[int] = None,
|
52
61
|
batch_max_size: typing.Optional[int] = None,
|
53
62
|
batch_wait_ms: typing.Optional[int] = None,
|
54
|
-
) -> None:
|
55
|
-
|
56
|
-
|
63
|
+
) -> None:
|
64
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
65
|
+
...
|
66
|
+
|
67
|
+
def __repr__(self):
|
68
|
+
"""Return repr(self)."""
|
69
|
+
...
|
57
70
|
|
58
|
-
def
|
71
|
+
def __eq__(self, other):
|
72
|
+
"""Return self==value."""
|
73
|
+
...
|
74
|
+
|
75
|
+
def _bind_instance_method(cls: _Cls, service_function: modal._functions._Function, method_name: str):
|
76
|
+
"""Binds an "instance service function" to a specific method using metadata for that method
|
77
|
+
|
78
|
+
This "dummy" _Function gets no unique object_id and isn't backend-backed at all, since all
|
79
|
+
it does it forward invocations to the underlying instance_service_function with the specified method
|
80
|
+
"""
|
81
|
+
...
|
59
82
|
|
60
83
|
class _Obj:
|
84
|
+
"""An instance of a `Cls`, i.e. `Cls("foo", 42)` returns an `Obj`.
|
85
|
+
|
86
|
+
All this class does is to return `Function` objects.
|
87
|
+
"""
|
88
|
+
|
61
89
|
_cls: _Cls
|
62
90
|
_functions: dict[str, modal._functions._Function]
|
63
91
|
_has_entered: bool
|
@@ -69,7 +97,10 @@ class _Obj:
|
|
69
97
|
|
70
98
|
def __init__(
|
71
99
|
self, cls: _Cls, user_cls: typing.Optional[type], options: typing.Optional[_ServiceOptions], args, kwargs
|
72
|
-
):
|
100
|
+
):
|
101
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
102
|
+
...
|
103
|
+
|
73
104
|
def _cached_service_function(self) -> modal._functions._Function: ...
|
74
105
|
def _get_parameter_values(self) -> dict[str, typing.Any]: ...
|
75
106
|
def _new_user_cls_instance(self): ...
|
@@ -80,9 +111,59 @@ class _Obj:
|
|
80
111
|
max_containers: typing.Optional[int] = None,
|
81
112
|
scaledown_window: typing.Optional[int] = None,
|
82
113
|
buffer_containers: typing.Optional[int] = None,
|
83
|
-
) -> None:
|
84
|
-
|
85
|
-
|
114
|
+
) -> None:
|
115
|
+
"""Override the current autoscaler behavior for this Cls instance.
|
116
|
+
|
117
|
+
Unspecified parameters will retain their current value, i.e. either the static value
|
118
|
+
from the function decorator, or an override value from a previous call to this method.
|
119
|
+
|
120
|
+
Subsequent deployments of the App containing this Cls will reset the autoscaler back to
|
121
|
+
its static configuration.
|
122
|
+
|
123
|
+
Note: When calling this method on a Cls that is defined locally, static type checkers will
|
124
|
+
issue an error, because the object will appear to have the user-defined type.
|
125
|
+
|
126
|
+
Examples:
|
127
|
+
|
128
|
+
```python notest
|
129
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
130
|
+
model = Model() # This method is called on an *instance* of the class
|
131
|
+
|
132
|
+
# Always have at least 2 containers running, with an extra buffer when the Function is active
|
133
|
+
model.update_autoscaler(min_containers=2, buffer_containers=1)
|
134
|
+
|
135
|
+
# Limit this Function to avoid spinning up more than 5 containers
|
136
|
+
f.update_autoscaler(max_containers=5)
|
137
|
+
```
|
138
|
+
"""
|
139
|
+
...
|
140
|
+
|
141
|
+
async def keep_warm(self, warm_pool_size: int) -> None:
|
142
|
+
"""mdmd:hidden
|
143
|
+
Set the warm pool size for the class containers
|
144
|
+
|
145
|
+
DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
|
146
|
+
|
147
|
+
```python notest
|
148
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
149
|
+
model = Model() # This method is called on an *instance* of the class
|
150
|
+
|
151
|
+
# Old pattern (deprecated)
|
152
|
+
model.keep_warm(2)
|
153
|
+
|
154
|
+
# New pattern
|
155
|
+
model.update_autoscaler(min_containers=2)
|
156
|
+
```
|
157
|
+
"""
|
158
|
+
...
|
159
|
+
|
160
|
+
def _cached_user_cls_instance(self):
|
161
|
+
"""Get or construct the local object
|
162
|
+
|
163
|
+
Used for .local() calls and getting attributes of classes
|
164
|
+
"""
|
165
|
+
...
|
166
|
+
|
86
167
|
def _enter(self): ...
|
87
168
|
@property
|
88
169
|
def _entered(self) -> bool: ...
|
@@ -94,6 +175,11 @@ class _Obj:
|
|
94
175
|
SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
|
95
176
|
|
96
177
|
class Obj:
|
178
|
+
"""An instance of a `Cls`, i.e. `Cls("foo", 42)` returns an `Obj`.
|
179
|
+
|
180
|
+
All this class does is to return `Function` objects.
|
181
|
+
"""
|
182
|
+
|
97
183
|
_cls: Cls
|
98
184
|
_functions: dict[str, modal.functions.Function]
|
99
185
|
_has_entered: bool
|
@@ -119,7 +205,33 @@ class Obj:
|
|
119
205
|
max_containers: typing.Optional[int] = None,
|
120
206
|
scaledown_window: typing.Optional[int] = None,
|
121
207
|
buffer_containers: typing.Optional[int] = None,
|
122
|
-
) -> None:
|
208
|
+
) -> None:
|
209
|
+
"""Override the current autoscaler behavior for this Cls instance.
|
210
|
+
|
211
|
+
Unspecified parameters will retain their current value, i.e. either the static value
|
212
|
+
from the function decorator, or an override value from a previous call to this method.
|
213
|
+
|
214
|
+
Subsequent deployments of the App containing this Cls will reset the autoscaler back to
|
215
|
+
its static configuration.
|
216
|
+
|
217
|
+
Note: When calling this method on a Cls that is defined locally, static type checkers will
|
218
|
+
issue an error, because the object will appear to have the user-defined type.
|
219
|
+
|
220
|
+
Examples:
|
221
|
+
|
222
|
+
```python notest
|
223
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
224
|
+
model = Model() # This method is called on an *instance* of the class
|
225
|
+
|
226
|
+
# Always have at least 2 containers running, with an extra buffer when the Function is active
|
227
|
+
model.update_autoscaler(min_containers=2, buffer_containers=1)
|
228
|
+
|
229
|
+
# Limit this Function to avoid spinning up more than 5 containers
|
230
|
+
f.update_autoscaler(max_containers=5)
|
231
|
+
```
|
232
|
+
"""
|
233
|
+
...
|
234
|
+
|
123
235
|
async def aio(
|
124
236
|
self,
|
125
237
|
/,
|
@@ -128,17 +240,83 @@ class Obj:
|
|
128
240
|
max_containers: typing.Optional[int] = None,
|
129
241
|
scaledown_window: typing.Optional[int] = None,
|
130
242
|
buffer_containers: typing.Optional[int] = None,
|
131
|
-
) -> None:
|
243
|
+
) -> None:
|
244
|
+
"""Override the current autoscaler behavior for this Cls instance.
|
245
|
+
|
246
|
+
Unspecified parameters will retain their current value, i.e. either the static value
|
247
|
+
from the function decorator, or an override value from a previous call to this method.
|
248
|
+
|
249
|
+
Subsequent deployments of the App containing this Cls will reset the autoscaler back to
|
250
|
+
its static configuration.
|
251
|
+
|
252
|
+
Note: When calling this method on a Cls that is defined locally, static type checkers will
|
253
|
+
issue an error, because the object will appear to have the user-defined type.
|
254
|
+
|
255
|
+
Examples:
|
256
|
+
|
257
|
+
```python notest
|
258
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
259
|
+
model = Model() # This method is called on an *instance* of the class
|
260
|
+
|
261
|
+
# Always have at least 2 containers running, with an extra buffer when the Function is active
|
262
|
+
model.update_autoscaler(min_containers=2, buffer_containers=1)
|
263
|
+
|
264
|
+
# Limit this Function to avoid spinning up more than 5 containers
|
265
|
+
f.update_autoscaler(max_containers=5)
|
266
|
+
```
|
267
|
+
"""
|
268
|
+
...
|
132
269
|
|
133
270
|
update_autoscaler: __update_autoscaler_spec[typing_extensions.Self]
|
134
271
|
|
135
272
|
class __keep_warm_spec(typing_extensions.Protocol[SUPERSELF]):
|
136
|
-
def __call__(self, /, warm_pool_size: int) -> None:
|
137
|
-
|
273
|
+
def __call__(self, /, warm_pool_size: int) -> None:
|
274
|
+
"""mdmd:hidden
|
275
|
+
Set the warm pool size for the class containers
|
276
|
+
|
277
|
+
DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
|
278
|
+
|
279
|
+
```python notest
|
280
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
281
|
+
model = Model() # This method is called on an *instance* of the class
|
282
|
+
|
283
|
+
# Old pattern (deprecated)
|
284
|
+
model.keep_warm(2)
|
285
|
+
|
286
|
+
# New pattern
|
287
|
+
model.update_autoscaler(min_containers=2)
|
288
|
+
```
|
289
|
+
"""
|
290
|
+
...
|
291
|
+
|
292
|
+
async def aio(self, /, warm_pool_size: int) -> None:
|
293
|
+
"""mdmd:hidden
|
294
|
+
Set the warm pool size for the class containers
|
295
|
+
|
296
|
+
DEPRECATED: Please adapt your code to use the more general `update_autoscaler` method instead:
|
297
|
+
|
298
|
+
```python notest
|
299
|
+
Model = modal.Cls.from_name("my-app", "Model")
|
300
|
+
model = Model() # This method is called on an *instance* of the class
|
301
|
+
|
302
|
+
# Old pattern (deprecated)
|
303
|
+
model.keep_warm(2)
|
304
|
+
|
305
|
+
# New pattern
|
306
|
+
model.update_autoscaler(min_containers=2)
|
307
|
+
```
|
308
|
+
"""
|
309
|
+
...
|
138
310
|
|
139
311
|
keep_warm: __keep_warm_spec[typing_extensions.Self]
|
140
312
|
|
141
|
-
def _cached_user_cls_instance(self):
|
313
|
+
def _cached_user_cls_instance(self):
|
314
|
+
"""Get or construct the local object
|
315
|
+
|
316
|
+
Used for .local() calls and getting attributes of classes
|
317
|
+
"""
|
318
|
+
...
|
319
|
+
|
142
320
|
def _enter(self): ...
|
143
321
|
@property
|
144
322
|
def _entered(self) -> bool: ...
|
@@ -148,6 +326,13 @@ class Obj:
|
|
148
326
|
def __getattr__(self, k): ...
|
149
327
|
|
150
328
|
class _Cls(modal._object._Object):
|
329
|
+
"""Cls adds method pooling and [lifecycle hook](https://modal.com/docs/guide/lifecycle-functions) behavior
|
330
|
+
to [modal.Function](https://modal.com/docs/reference/modal.Function).
|
331
|
+
|
332
|
+
Generally, you will not construct a Cls directly.
|
333
|
+
Instead, use the [`@app.cls()`](https://modal.com/docs/reference/modal.App#cls) decorator on the App object.
|
334
|
+
"""
|
335
|
+
|
151
336
|
_class_service_function: typing.Optional[modal._functions._Function]
|
152
337
|
_options: _ServiceOptions
|
153
338
|
_app: typing.Optional[modal.app._App]
|
@@ -167,13 +352,31 @@ class _Cls(modal._object._Object):
|
|
167
352
|
def _get_method_names(self) -> collections.abc.Collection[str]: ...
|
168
353
|
def _hydrate_metadata(self, metadata: google.protobuf.message.Message): ...
|
169
354
|
@staticmethod
|
170
|
-
def validate_construction_mechanism(user_cls):
|
355
|
+
def validate_construction_mechanism(user_cls):
|
356
|
+
"""mdmd:hidden"""
|
357
|
+
...
|
358
|
+
|
171
359
|
@staticmethod
|
172
|
-
def from_local(user_cls, app: modal.app._App, class_service_function: modal._functions._Function) -> _Cls:
|
360
|
+
def from_local(user_cls, app: modal.app._App, class_service_function: modal._functions._Function) -> _Cls:
|
361
|
+
"""mdmd:hidden"""
|
362
|
+
...
|
363
|
+
|
173
364
|
@classmethod
|
174
365
|
def from_name(
|
175
366
|
cls: type[_Cls], app_name: str, name: str, *, namespace=1, environment_name: typing.Optional[str] = None
|
176
|
-
) -> _Cls:
|
367
|
+
) -> _Cls:
|
368
|
+
"""Reference a Cls from a deployed App by its name.
|
369
|
+
|
370
|
+
This is a lazy method that defers hydrating the local
|
371
|
+
object with metadata from Modal servers until the first
|
372
|
+
time it is actually used.
|
373
|
+
|
374
|
+
```python
|
375
|
+
Model = modal.Cls.from_name("other-app", "Model")
|
376
|
+
```
|
377
|
+
"""
|
378
|
+
...
|
379
|
+
|
177
380
|
def with_options(
|
178
381
|
self: _Cls,
|
179
382
|
*,
|
@@ -190,9 +393,62 @@ class _Cls(modal._object._Object):
|
|
190
393
|
concurrency_limit: typing.Optional[int] = None,
|
191
394
|
container_idle_timeout: typing.Optional[int] = None,
|
192
395
|
allow_concurrent_inputs: typing.Optional[int] = None,
|
193
|
-
) -> _Cls:
|
194
|
-
|
195
|
-
|
396
|
+
) -> _Cls:
|
397
|
+
"""Override the static Function configuration at runtime.
|
398
|
+
|
399
|
+
This method will return a new instance of the cls that will autoscale independently of the
|
400
|
+
original instance. Note that options cannot be "unset" with this method (i.e., if a GPU
|
401
|
+
is configured in the `@app.cls()` decorator, passing `gpu=None` here will not create a
|
402
|
+
CPU-only instance).
|
403
|
+
|
404
|
+
**Usage:**
|
405
|
+
|
406
|
+
You can use this method after looking up the Cls from a deployed App or if you have a
|
407
|
+
direct reference to a Cls from another Function or local entrypoint on its App:
|
408
|
+
|
409
|
+
```python notest
|
410
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
411
|
+
ModelUsingGPU = Model.with_options(gpu="A100")
|
412
|
+
ModelUsingGPU().generate.remote(input_prompt) # Run with an A100 GPU
|
413
|
+
```
|
414
|
+
|
415
|
+
The method can be called multiple times to "stack" updates:
|
416
|
+
|
417
|
+
```python notest
|
418
|
+
Model.with_options(gpu="A100").with_options(scaledown_window=300) # Use an A100 with slow scaledown
|
419
|
+
```
|
420
|
+
|
421
|
+
Note that container arguments (i.e. `volumes` and `secrets`) passed in subsequent calls
|
422
|
+
will not be merged.
|
423
|
+
"""
|
424
|
+
...
|
425
|
+
|
426
|
+
def with_concurrency(self: _Cls, *, max_inputs: int, target_inputs: typing.Optional[int] = None) -> _Cls:
|
427
|
+
"""Create an instance of the Cls with input concurrency enabled or overridden with new values.
|
428
|
+
|
429
|
+
**Usage:**
|
430
|
+
|
431
|
+
```python notest
|
432
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
433
|
+
ModelUsingGPU = Model.with_options(gpu="A100").with_concurrency(max_inputs=100)
|
434
|
+
ModelUsingGPU().generate.remote(42) # will run on an A100 GPU with input concurrency enabled
|
435
|
+
```
|
436
|
+
"""
|
437
|
+
...
|
438
|
+
|
439
|
+
def with_batching(self: _Cls, *, max_batch_size: int, wait_ms: int) -> _Cls:
|
440
|
+
"""Create an instance of the Cls with dynamic batching enabled or overridden with new values.
|
441
|
+
|
442
|
+
**Usage:**
|
443
|
+
|
444
|
+
```python notest
|
445
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
446
|
+
ModelUsingGPU = Model.with_options(gpu="A100").with_batching(max_batch_size=100, batch_wait_ms=1000)
|
447
|
+
ModelUsingGPU().generate.remote(42) # will run on an A100 GPU with input concurrency enabled
|
448
|
+
```
|
449
|
+
"""
|
450
|
+
...
|
451
|
+
|
196
452
|
@staticmethod
|
197
453
|
async def lookup(
|
198
454
|
app_name: str,
|
@@ -200,12 +456,38 @@ class _Cls(modal._object._Object):
|
|
200
456
|
namespace=1,
|
201
457
|
client: typing.Optional[modal.client._Client] = None,
|
202
458
|
environment_name: typing.Optional[str] = None,
|
203
|
-
) -> _Cls:
|
204
|
-
|
459
|
+
) -> _Cls:
|
460
|
+
"""mdmd:hidden
|
461
|
+
Lookup a Cls from a deployed App by its name.
|
462
|
+
|
463
|
+
DEPRECATED: This method is deprecated in favor of `modal.Cls.from_name`.
|
464
|
+
|
465
|
+
In contrast to `modal.Cls.from_name`, this is an eager method
|
466
|
+
that will hydrate the local object with metadata from Modal servers.
|
467
|
+
|
468
|
+
```python notest
|
469
|
+
Model = modal.Cls.from_name("other-app", "Model")
|
470
|
+
model = Model()
|
471
|
+
model.inference(...)
|
472
|
+
```
|
473
|
+
"""
|
474
|
+
...
|
475
|
+
|
476
|
+
def __call__(self, *args, **kwargs) -> _Obj:
|
477
|
+
"""This acts as the class constructor."""
|
478
|
+
...
|
479
|
+
|
205
480
|
def __getattr__(self, k): ...
|
206
481
|
def _is_local(self) -> bool: ...
|
207
482
|
|
208
483
|
class Cls(modal.object.Object):
|
484
|
+
"""Cls adds method pooling and [lifecycle hook](https://modal.com/docs/guide/lifecycle-functions) behavior
|
485
|
+
to [modal.Function](https://modal.com/docs/reference/modal.Function).
|
486
|
+
|
487
|
+
Generally, you will not construct a Cls directly.
|
488
|
+
Instead, use the [`@app.cls()`](https://modal.com/docs/reference/modal.App#cls) decorator on the App object.
|
489
|
+
"""
|
490
|
+
|
209
491
|
_class_service_function: typing.Optional[modal.functions.Function]
|
210
492
|
_options: _ServiceOptions
|
211
493
|
_app: typing.Optional[modal.app.App]
|
@@ -215,7 +497,10 @@ class Cls(modal.object.Object):
|
|
215
497
|
_method_partials: typing.Optional[dict[str, modal.partial_function.PartialFunction]]
|
216
498
|
_callables: dict[str, collections.abc.Callable[..., typing.Any]]
|
217
499
|
|
218
|
-
def __init__(self, *args, **kwargs):
|
500
|
+
def __init__(self, *args, **kwargs):
|
501
|
+
"""mdmd:hidden"""
|
502
|
+
...
|
503
|
+
|
219
504
|
def _initialize_from_empty(self): ...
|
220
505
|
def _initialize_from_other(self, other: Cls): ...
|
221
506
|
def _get_partial_functions(self) -> dict[str, modal.partial_function.PartialFunction]: ...
|
@@ -226,13 +511,31 @@ class Cls(modal.object.Object):
|
|
226
511
|
def _get_method_names(self) -> collections.abc.Collection[str]: ...
|
227
512
|
def _hydrate_metadata(self, metadata: google.protobuf.message.Message): ...
|
228
513
|
@staticmethod
|
229
|
-
def validate_construction_mechanism(user_cls):
|
514
|
+
def validate_construction_mechanism(user_cls):
|
515
|
+
"""mdmd:hidden"""
|
516
|
+
...
|
517
|
+
|
230
518
|
@staticmethod
|
231
|
-
def from_local(user_cls, app: modal.app.App, class_service_function: modal.functions.Function) -> Cls:
|
519
|
+
def from_local(user_cls, app: modal.app.App, class_service_function: modal.functions.Function) -> Cls:
|
520
|
+
"""mdmd:hidden"""
|
521
|
+
...
|
522
|
+
|
232
523
|
@classmethod
|
233
524
|
def from_name(
|
234
525
|
cls: type[Cls], app_name: str, name: str, *, namespace=1, environment_name: typing.Optional[str] = None
|
235
|
-
) -> Cls:
|
526
|
+
) -> Cls:
|
527
|
+
"""Reference a Cls from a deployed App by its name.
|
528
|
+
|
529
|
+
This is a lazy method that defers hydrating the local
|
530
|
+
object with metadata from Modal servers until the first
|
531
|
+
time it is actually used.
|
532
|
+
|
533
|
+
```python
|
534
|
+
Model = modal.Cls.from_name("other-app", "Model")
|
535
|
+
```
|
536
|
+
"""
|
537
|
+
...
|
538
|
+
|
236
539
|
def with_options(
|
237
540
|
self: Cls,
|
238
541
|
*,
|
@@ -249,9 +552,61 @@ class Cls(modal.object.Object):
|
|
249
552
|
concurrency_limit: typing.Optional[int] = None,
|
250
553
|
container_idle_timeout: typing.Optional[int] = None,
|
251
554
|
allow_concurrent_inputs: typing.Optional[int] = None,
|
252
|
-
) -> Cls:
|
253
|
-
|
254
|
-
|
555
|
+
) -> Cls:
|
556
|
+
"""Override the static Function configuration at runtime.
|
557
|
+
|
558
|
+
This method will return a new instance of the cls that will autoscale independently of the
|
559
|
+
original instance. Note that options cannot be "unset" with this method (i.e., if a GPU
|
560
|
+
is configured in the `@app.cls()` decorator, passing `gpu=None` here will not create a
|
561
|
+
CPU-only instance).
|
562
|
+
|
563
|
+
**Usage:**
|
564
|
+
|
565
|
+
You can use this method after looking up the Cls from a deployed App or if you have a
|
566
|
+
direct reference to a Cls from another Function or local entrypoint on its App:
|
567
|
+
|
568
|
+
```python notest
|
569
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
570
|
+
ModelUsingGPU = Model.with_options(gpu="A100")
|
571
|
+
ModelUsingGPU().generate.remote(input_prompt) # Run with an A100 GPU
|
572
|
+
```
|
573
|
+
|
574
|
+
The method can be called multiple times to "stack" updates:
|
575
|
+
|
576
|
+
```python notest
|
577
|
+
Model.with_options(gpu="A100").with_options(scaledown_window=300) # Use an A100 with slow scaledown
|
578
|
+
```
|
579
|
+
|
580
|
+
Note that container arguments (i.e. `volumes` and `secrets`) passed in subsequent calls
|
581
|
+
will not be merged.
|
582
|
+
"""
|
583
|
+
...
|
584
|
+
|
585
|
+
def with_concurrency(self: Cls, *, max_inputs: int, target_inputs: typing.Optional[int] = None) -> Cls:
|
586
|
+
"""Create an instance of the Cls with input concurrency enabled or overridden with new values.
|
587
|
+
|
588
|
+
**Usage:**
|
589
|
+
|
590
|
+
```python notest
|
591
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
592
|
+
ModelUsingGPU = Model.with_options(gpu="A100").with_concurrency(max_inputs=100)
|
593
|
+
ModelUsingGPU().generate.remote(42) # will run on an A100 GPU with input concurrency enabled
|
594
|
+
```
|
595
|
+
"""
|
596
|
+
...
|
597
|
+
|
598
|
+
def with_batching(self: Cls, *, max_batch_size: int, wait_ms: int) -> Cls:
|
599
|
+
"""Create an instance of the Cls with dynamic batching enabled or overridden with new values.
|
600
|
+
|
601
|
+
**Usage:**
|
602
|
+
|
603
|
+
```python notest
|
604
|
+
Model = modal.Cls.from_name("my_app", "Model")
|
605
|
+
ModelUsingGPU = Model.with_options(gpu="A100").with_batching(max_batch_size=100, batch_wait_ms=1000)
|
606
|
+
ModelUsingGPU().generate.remote(42) # will run on an A100 GPU with input concurrency enabled
|
607
|
+
```
|
608
|
+
"""
|
609
|
+
...
|
255
610
|
|
256
611
|
class __lookup_spec(typing_extensions.Protocol):
|
257
612
|
def __call__(
|
@@ -262,7 +617,23 @@ class Cls(modal.object.Object):
|
|
262
617
|
namespace=1,
|
263
618
|
client: typing.Optional[modal.client.Client] = None,
|
264
619
|
environment_name: typing.Optional[str] = None,
|
265
|
-
) -> Cls:
|
620
|
+
) -> Cls:
|
621
|
+
"""mdmd:hidden
|
622
|
+
Lookup a Cls from a deployed App by its name.
|
623
|
+
|
624
|
+
DEPRECATED: This method is deprecated in favor of `modal.Cls.from_name`.
|
625
|
+
|
626
|
+
In contrast to `modal.Cls.from_name`, this is an eager method
|
627
|
+
that will hydrate the local object with metadata from Modal servers.
|
628
|
+
|
629
|
+
```python notest
|
630
|
+
Model = modal.Cls.from_name("other-app", "Model")
|
631
|
+
model = Model()
|
632
|
+
model.inference(...)
|
633
|
+
```
|
634
|
+
"""
|
635
|
+
...
|
636
|
+
|
266
637
|
async def aio(
|
267
638
|
self,
|
268
639
|
/,
|
@@ -271,11 +642,29 @@ class Cls(modal.object.Object):
|
|
271
642
|
namespace=1,
|
272
643
|
client: typing.Optional[modal.client.Client] = None,
|
273
644
|
environment_name: typing.Optional[str] = None,
|
274
|
-
) -> Cls:
|
645
|
+
) -> Cls:
|
646
|
+
"""mdmd:hidden
|
647
|
+
Lookup a Cls from a deployed App by its name.
|
648
|
+
|
649
|
+
DEPRECATED: This method is deprecated in favor of `modal.Cls.from_name`.
|
650
|
+
|
651
|
+
In contrast to `modal.Cls.from_name`, this is an eager method
|
652
|
+
that will hydrate the local object with metadata from Modal servers.
|
653
|
+
|
654
|
+
```python notest
|
655
|
+
Model = modal.Cls.from_name("other-app", "Model")
|
656
|
+
model = Model()
|
657
|
+
model.inference(...)
|
658
|
+
```
|
659
|
+
"""
|
660
|
+
...
|
275
661
|
|
276
662
|
lookup: __lookup_spec
|
277
663
|
|
278
|
-
def __call__(self, *args, **kwargs) -> Obj:
|
664
|
+
def __call__(self, *args, **kwargs) -> Obj:
|
665
|
+
"""This acts as the class constructor."""
|
666
|
+
...
|
667
|
+
|
279
668
|
def __getattr__(self, k): ...
|
280
669
|
def _is_local(self) -> bool: ...
|
281
670
|
|
@@ -292,7 +681,9 @@ class ___get_method_schemas_spec(typing_extensions.Protocol):
|
|
292
681
|
_get_method_schemas: ___get_method_schemas_spec
|
293
682
|
|
294
683
|
class _NO_DEFAULT:
|
295
|
-
def __repr__(self):
|
684
|
+
def __repr__(self):
|
685
|
+
"""Return repr(self)."""
|
686
|
+
...
|
296
687
|
|
297
688
|
_no_default: _NO_DEFAULT
|
298
689
|
|
@@ -300,8 +691,25 @@ class _Parameter:
|
|
300
691
|
default: typing.Any
|
301
692
|
init: bool
|
302
693
|
|
303
|
-
def __init__(self, default: typing.Any, init: bool):
|
694
|
+
def __init__(self, default: typing.Any, init: bool):
|
695
|
+
"""Initialize self. See help(type(self)) for accurate signature."""
|
696
|
+
...
|
697
|
+
|
304
698
|
def __get__(self, obj, obj_type=None) -> typing.Any: ...
|
305
699
|
|
306
700
|
def is_parameter(p: typing.Any) -> bool: ...
|
307
|
-
def parameter(*, default: typing.Any = modal.cls._NO_DEFAULT(), init: bool = True) -> typing.Any:
|
701
|
+
def parameter(*, default: typing.Any = modal.cls._NO_DEFAULT(), init: bool = True) -> typing.Any:
|
702
|
+
"""Used to specify options for modal.cls parameters, similar to dataclass.field for dataclasses
|
703
|
+
```
|
704
|
+
class A:
|
705
|
+
a: str = modal.parameter()
|
706
|
+
|
707
|
+
```
|
708
|
+
|
709
|
+
If `init=False` is specified, the field is not considered a parameter for the
|
710
|
+
Modal class and not used in the synthesized constructor. This can be used to
|
711
|
+
optionally annotate the type of a field that's used internally, for example values
|
712
|
+
being set by @enter lifecycle methods, without breaking type checkers, but it has
|
713
|
+
no runtime effect on the class.
|
714
|
+
"""
|
715
|
+
...
|