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