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.

Files changed (160) hide show
  1. modal/__init__.py +0 -2
  2. modal/__main__.py +3 -4
  3. modal/_billing.py +80 -0
  4. modal/_clustered_functions.py +7 -3
  5. modal/_clustered_functions.pyi +15 -3
  6. modal/_container_entrypoint.py +51 -69
  7. modal/_functions.py +508 -240
  8. modal/_grpc_client.py +171 -0
  9. modal/_load_context.py +105 -0
  10. modal/_object.py +81 -21
  11. modal/_output.py +58 -45
  12. modal/_partial_function.py +48 -73
  13. modal/_pty.py +7 -3
  14. modal/_resolver.py +26 -46
  15. modal/_runtime/asgi.py +4 -3
  16. modal/_runtime/container_io_manager.py +358 -220
  17. modal/_runtime/container_io_manager.pyi +296 -101
  18. modal/_runtime/execution_context.py +18 -2
  19. modal/_runtime/execution_context.pyi +64 -7
  20. modal/_runtime/gpu_memory_snapshot.py +262 -57
  21. modal/_runtime/user_code_imports.py +28 -58
  22. modal/_serialization.py +90 -6
  23. modal/_traceback.py +42 -1
  24. modal/_tunnel.pyi +380 -12
  25. modal/_utils/async_utils.py +84 -29
  26. modal/_utils/auth_token_manager.py +111 -0
  27. modal/_utils/blob_utils.py +181 -58
  28. modal/_utils/deprecation.py +19 -0
  29. modal/_utils/function_utils.py +91 -47
  30. modal/_utils/grpc_utils.py +89 -66
  31. modal/_utils/mount_utils.py +26 -1
  32. modal/_utils/name_utils.py +17 -3
  33. modal/_utils/task_command_router_client.py +536 -0
  34. modal/_utils/time_utils.py +34 -6
  35. modal/app.py +256 -88
  36. modal/app.pyi +909 -92
  37. modal/billing.py +5 -0
  38. modal/builder/2025.06.txt +18 -0
  39. modal/builder/PREVIEW.txt +18 -0
  40. modal/builder/base-images.json +58 -0
  41. modal/cli/_download.py +19 -3
  42. modal/cli/_traceback.py +3 -2
  43. modal/cli/app.py +4 -4
  44. modal/cli/cluster.py +15 -7
  45. modal/cli/config.py +5 -3
  46. modal/cli/container.py +7 -6
  47. modal/cli/dict.py +22 -16
  48. modal/cli/entry_point.py +12 -5
  49. modal/cli/environment.py +5 -4
  50. modal/cli/import_refs.py +3 -3
  51. modal/cli/launch.py +102 -5
  52. modal/cli/network_file_system.py +11 -12
  53. modal/cli/profile.py +3 -2
  54. modal/cli/programs/launch_instance_ssh.py +94 -0
  55. modal/cli/programs/run_jupyter.py +1 -1
  56. modal/cli/programs/run_marimo.py +95 -0
  57. modal/cli/programs/vscode.py +1 -1
  58. modal/cli/queues.py +57 -26
  59. modal/cli/run.py +91 -23
  60. modal/cli/secret.py +48 -22
  61. modal/cli/token.py +7 -8
  62. modal/cli/utils.py +4 -7
  63. modal/cli/volume.py +31 -25
  64. modal/client.py +15 -85
  65. modal/client.pyi +183 -62
  66. modal/cloud_bucket_mount.py +5 -3
  67. modal/cloud_bucket_mount.pyi +197 -5
  68. modal/cls.py +200 -126
  69. modal/cls.pyi +446 -68
  70. modal/config.py +29 -11
  71. modal/container_process.py +319 -19
  72. modal/container_process.pyi +190 -20
  73. modal/dict.py +290 -71
  74. modal/dict.pyi +835 -83
  75. modal/environments.py +15 -27
  76. modal/environments.pyi +46 -24
  77. modal/exception.py +14 -2
  78. modal/experimental/__init__.py +194 -40
  79. modal/experimental/flash.py +618 -0
  80. modal/experimental/flash.pyi +380 -0
  81. modal/experimental/ipython.py +11 -7
  82. modal/file_io.py +29 -36
  83. modal/file_io.pyi +251 -53
  84. modal/file_pattern_matcher.py +56 -16
  85. modal/functions.pyi +673 -92
  86. modal/gpu.py +1 -1
  87. modal/image.py +528 -176
  88. modal/image.pyi +1572 -145
  89. modal/io_streams.py +458 -128
  90. modal/io_streams.pyi +433 -52
  91. modal/mount.py +216 -151
  92. modal/mount.pyi +225 -78
  93. modal/network_file_system.py +45 -62
  94. modal/network_file_system.pyi +277 -56
  95. modal/object.pyi +93 -17
  96. modal/parallel_map.py +942 -129
  97. modal/parallel_map.pyi +294 -15
  98. modal/partial_function.py +0 -2
  99. modal/partial_function.pyi +234 -19
  100. modal/proxy.py +17 -8
  101. modal/proxy.pyi +36 -3
  102. modal/queue.py +270 -65
  103. modal/queue.pyi +817 -57
  104. modal/runner.py +115 -101
  105. modal/runner.pyi +205 -49
  106. modal/sandbox.py +512 -136
  107. modal/sandbox.pyi +845 -111
  108. modal/schedule.py +1 -1
  109. modal/secret.py +300 -70
  110. modal/secret.pyi +589 -34
  111. modal/serving.py +7 -11
  112. modal/serving.pyi +7 -8
  113. modal/snapshot.py +11 -8
  114. modal/snapshot.pyi +25 -4
  115. modal/token_flow.py +4 -4
  116. modal/token_flow.pyi +28 -8
  117. modal/volume.py +416 -158
  118. modal/volume.pyi +1117 -121
  119. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/METADATA +10 -9
  120. modal-1.2.3.dev7.dist-info/RECORD +195 -0
  121. modal_docs/mdmd/mdmd.py +17 -4
  122. modal_proto/api.proto +534 -79
  123. modal_proto/api_grpc.py +337 -1
  124. modal_proto/api_pb2.py +1522 -968
  125. modal_proto/api_pb2.pyi +1619 -134
  126. modal_proto/api_pb2_grpc.py +699 -4
  127. modal_proto/api_pb2_grpc.pyi +226 -14
  128. modal_proto/modal_api_grpc.py +175 -154
  129. modal_proto/sandbox_router.proto +145 -0
  130. modal_proto/sandbox_router_grpc.py +105 -0
  131. modal_proto/sandbox_router_pb2.py +149 -0
  132. modal_proto/sandbox_router_pb2.pyi +333 -0
  133. modal_proto/sandbox_router_pb2_grpc.py +203 -0
  134. modal_proto/sandbox_router_pb2_grpc.pyi +75 -0
  135. modal_proto/task_command_router.proto +144 -0
  136. modal_proto/task_command_router_grpc.py +105 -0
  137. modal_proto/task_command_router_pb2.py +149 -0
  138. modal_proto/task_command_router_pb2.pyi +333 -0
  139. modal_proto/task_command_router_pb2_grpc.py +203 -0
  140. modal_proto/task_command_router_pb2_grpc.pyi +75 -0
  141. modal_version/__init__.py +1 -1
  142. modal/requirements/PREVIEW.txt +0 -16
  143. modal/requirements/base-images.json +0 -26
  144. modal-1.0.3.dev10.dist-info/RECORD +0 -179
  145. modal_proto/modal_options_grpc.py +0 -3
  146. modal_proto/options.proto +0 -19
  147. modal_proto/options_grpc.py +0 -3
  148. modal_proto/options_pb2.py +0 -35
  149. modal_proto/options_pb2.pyi +0 -20
  150. modal_proto/options_pb2_grpc.py +0 -4
  151. modal_proto/options_pb2_grpc.pyi +0 -7
  152. /modal/{requirements → builder}/2023.12.312.txt +0 -0
  153. /modal/{requirements → builder}/2023.12.txt +0 -0
  154. /modal/{requirements → builder}/2024.04.txt +0 -0
  155. /modal/{requirements → builder}/2024.10.txt +0 -0
  156. /modal/{requirements → builder}/README.md +0 -0
  157. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/WHEEL +0 -0
  158. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/entry_points.txt +0 -0
  159. {modal-1.0.3.dev10.dist-info → modal-1.2.3.dev7.dist-info}/licenses/LICENSE +0 -0
  160. {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 os
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: typing.Collection[modal.secret._Secret]
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: typing.Collection[modal.secret._Secret] = (),
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
- ) -> None: ...
55
- def __repr__(self): ...
56
- def __eq__(self, other): ...
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 _bind_instance_method(cls: _Cls, service_function: modal._functions._Function, method_name: str): ...
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
- async def keep_warm(self, warm_pool_size: int) -> None: ...
85
- def _cached_user_cls_instance(self): ...
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
- async def aio(self, /, warm_pool_size: int) -> None: ...
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], app_name: str, name: str, *, namespace=1, environment_name: typing.Optional[str] = None
176
- ) -> _Cls: ...
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
- secrets: collections.abc.Collection[modal.secret._Secret] = (),
184
- volumes: dict[typing.Union[str, os.PathLike], modal.volume._Volume] = {},
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
- def with_concurrency(self: _Cls, *, max_inputs: int, target_inputs: typing.Optional[int] = None) -> _Cls: ...
195
- def with_batching(self: _Cls, *, max_batch_size: int, wait_ms: int) -> _Cls: ...
196
- @staticmethod
197
- async def lookup(
198
- app_name: str,
199
- name: str,
200
- namespace=1,
201
- client: typing.Optional[modal.client._Client] = None,
202
- environment_name: typing.Optional[str] = None,
203
- ) -> _Cls: ...
204
- def __call__(self, *args, **kwargs) -> _Obj: ...
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], app_name: str, name: str, *, namespace=1, environment_name: typing.Optional[str] = None
235
- ) -> Cls: ...
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
- secrets: collections.abc.Collection[modal.secret.Secret] = (),
243
- volumes: dict[typing.Union[str, os.PathLike], modal.volume.Volume] = {},
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
- def with_concurrency(self: Cls, *, max_inputs: int, target_inputs: typing.Optional[int] = None) -> Cls: ...
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
- class __lookup_spec(typing_extensions.Protocol):
257
- def __call__(
258
- self,
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
- lookup: __lookup_spec
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
+ ...