modal 0.77.0__py3-none-any.whl → 1.0.0__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 (51) hide show
  1. modal/__init__.py +10 -4
  2. modal/_functions.py +15 -90
  3. modal/_object.py +0 -14
  4. modal/_partial_function.py +4 -14
  5. modal/_serialization.py +2 -2
  6. modal/_utils/function_utils.py +3 -6
  7. modal/_utils/grpc_utils.py +6 -1
  8. modal/app.py +1 -104
  9. modal/app.pyi +0 -127
  10. modal/cli/app.py +0 -19
  11. modal/cli/programs/run_jupyter.py +1 -1
  12. modal/cli/programs/vscode.py +1 -1
  13. modal/client.pyi +2 -2
  14. modal/cls.py +9 -14
  15. modal/cls.pyi +2 -17
  16. modal/config.py +5 -16
  17. modal/container_process.py +1 -9
  18. modal/container_process.pyi +3 -3
  19. modal/dict.py +3 -5
  20. modal/environments.py +1 -3
  21. modal/exception.py +1 -1
  22. modal/functions.pyi +8 -29
  23. modal/image.py +12 -36
  24. modal/image.pyi +2 -5
  25. modal/mount.py +2 -65
  26. modal/mount.pyi +0 -1
  27. modal/network_file_system.py +3 -5
  28. modal/object.pyi +0 -6
  29. modal/queue.py +3 -5
  30. modal/runner.py +2 -19
  31. modal/runner.pyi +0 -5
  32. modal/sandbox.py +78 -32
  33. modal/sandbox.pyi +102 -7
  34. modal/secret.py +1 -3
  35. modal/serving.py +0 -6
  36. modal/serving.pyi +0 -3
  37. modal/volume.py +8 -17
  38. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/METADATA +1 -1
  39. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/RECORD +51 -51
  40. modal_proto/api.proto +29 -1
  41. modal_proto/api_grpc.py +32 -0
  42. modal_proto/api_pb2.py +788 -756
  43. modal_proto/api_pb2.pyi +86 -9
  44. modal_proto/api_pb2_grpc.py +66 -0
  45. modal_proto/api_pb2_grpc.pyi +20 -0
  46. modal_proto/modal_api_grpc.py +2 -0
  47. modal_version/__init__.py +1 -1
  48. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/WHEEL +0 -0
  49. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/entry_points.txt +0 -0
  50. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/licenses/LICENSE +0 -0
  51. {modal-0.77.0.dist-info → modal-1.0.0.dist-info}/top_level.txt +0 -0
modal/mount.pyi CHANGED
@@ -308,7 +308,6 @@ def _create_client_mount(): ...
308
308
  def create_client_mount(): ...
309
309
  def _get_client_mount(): ...
310
310
  def _is_modal_path(remote_path: pathlib.PurePosixPath): ...
311
- def get_sys_modules_mounts() -> dict[str, _Mount]: ...
312
311
 
313
312
  ROOT_DIR: pathlib.PurePosixPath
314
313
 
@@ -22,7 +22,7 @@ from ._object import (
22
22
  from ._resolver import Resolver
23
23
  from ._utils.async_utils import TaskContext, aclosing, async_map, sync_or_async_iter, synchronize_api
24
24
  from ._utils.blob_utils import LARGE_FILE_LIMIT, blob_iter, blob_upload_file
25
- from ._utils.deprecation import deprecation_warning, renamed_parameter
25
+ from ._utils.deprecation import deprecation_warning
26
26
  from ._utils.grpc_utils import retry_transient_errors
27
27
  from ._utils.hash_utils import get_sha256_hex
28
28
  from ._utils.name_utils import check_object_name
@@ -89,7 +89,6 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
89
89
  """
90
90
 
91
91
  @staticmethod
92
- @renamed_parameter((2024, 12, 18), "label", "name")
93
92
  def from_name(
94
93
  name: str,
95
94
  *,
@@ -166,7 +165,6 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
166
165
  yield cls._new_hydrated(response.shared_volume_id, client, None, is_another_app=True)
167
166
 
168
167
  @staticmethod
169
- @renamed_parameter((2024, 12, 18), "label", "name")
170
168
  async def lookup(
171
169
  name: str,
172
170
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
@@ -174,7 +172,8 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
174
172
  environment_name: Optional[str] = None,
175
173
  create_if_missing: bool = False,
176
174
  ) -> "_NetworkFileSystem":
177
- """Lookup a named NetworkFileSystem.
175
+ """mdmd:hidden
176
+ Lookup a named NetworkFileSystem.
178
177
 
179
178
  DEPRECATED: This method is deprecated in favor of `modal.NetworkFileSystem.from_name`.
180
179
 
@@ -222,7 +221,6 @@ class _NetworkFileSystem(_Object, type_prefix="sv"):
222
221
  return resp.shared_volume_id
223
222
 
224
223
  @staticmethod
225
- @renamed_parameter((2024, 12, 18), "label", "name")
226
224
  async def delete(name: str, client: Optional[_Client] = None, environment_name: Optional[str] = None):
227
225
  obj = await _NetworkFileSystem.from_name(name, environment_name=environment_name).hydrate(client)
228
226
  req = api_pb2.SharedVolumeDeleteRequest(shared_volume_id=obj.object_id)
modal/object.pyi CHANGED
@@ -124,12 +124,6 @@ class Object:
124
124
  @property
125
125
  def deps(self) -> collections.abc.Callable[..., collections.abc.Sequence[Object]]: ...
126
126
 
127
- class __resolve_spec(typing_extensions.Protocol[SUPERSELF]):
128
- def __call__(self, /, client: typing.Optional[modal.client.Client] = None): ...
129
- async def aio(self, /, client: typing.Optional[modal.client.Client] = None): ...
130
-
131
- resolve: __resolve_spec[typing_extensions.Self]
132
-
133
127
  class __hydrate_spec(typing_extensions.Protocol[SUPERSELF]):
134
128
  def __call__(self, /, client: typing.Optional[modal.client.Client] = None) -> SUPERSELF: ...
135
129
  async def aio(self, /, client: typing.Optional[modal.client.Client] = None) -> SUPERSELF: ...
modal/queue.py CHANGED
@@ -14,7 +14,7 @@ from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _O
14
14
  from ._resolver import Resolver
15
15
  from ._serialization import deserialize, serialize
16
16
  from ._utils.async_utils import TaskContext, synchronize_api, warn_if_generator_is_not_consumed
17
- from ._utils.deprecation import deprecation_warning, renamed_parameter
17
+ from ._utils.deprecation import deprecation_warning
18
18
  from ._utils.grpc_utils import retry_transient_errors
19
19
  from ._utils.name_utils import check_object_name
20
20
  from .client import _Client
@@ -145,7 +145,6 @@ class _Queue(_Object, type_prefix="qu"):
145
145
  yield cls._new_hydrated(response.queue_id, client, None, is_another_app=True)
146
146
 
147
147
  @staticmethod
148
- @renamed_parameter((2024, 12, 18), "label", "name")
149
148
  def from_name(
150
149
  name: str,
151
150
  *,
@@ -179,7 +178,6 @@ class _Queue(_Object, type_prefix="qu"):
179
178
  return _Queue._from_loader(_load, "Queue()", is_another_app=True, hydrate_lazily=True)
180
179
 
181
180
  @staticmethod
182
- @renamed_parameter((2024, 12, 18), "label", "name")
183
181
  async def lookup(
184
182
  name: str,
185
183
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
@@ -187,7 +185,8 @@ class _Queue(_Object, type_prefix="qu"):
187
185
  environment_name: Optional[str] = None,
188
186
  create_if_missing: bool = False,
189
187
  ) -> "_Queue":
190
- """Lookup a named Queue.
188
+ """mdmd:hidden
189
+ Lookup a named Queue.
191
190
 
192
191
  DEPRECATED: This method is deprecated in favor of `modal.Queue.from_name`.
193
192
 
@@ -215,7 +214,6 @@ class _Queue(_Object, type_prefix="qu"):
215
214
  return obj
216
215
 
217
216
  @staticmethod
218
- @renamed_parameter((2024, 12, 18), "label", "name")
219
217
  async def delete(name: str, *, client: Optional[_Client] = None, environment_name: Optional[str] = None):
220
218
  obj = await _Queue.from_name(name, environment_name=environment_name).hydrate(client)
221
219
  req = api_pb2.QueueDeleteRequest(queue_id=obj.object_id)
modal/runner.py CHANGED
@@ -27,7 +27,6 @@ from ._pty import get_pty_info
27
27
  from ._resolver import Resolver
28
28
  from ._traceback import print_server_warnings, traceback_contains_remote_call
29
29
  from ._utils.async_utils import TaskContext, gather_cancel_on_exc, synchronize_api
30
- from ._utils.deprecation import deprecation_error
31
30
  from ._utils.git_utils import get_git_commit_info
32
31
  from ._utils.grpc_utils import retry_transient_errors
33
32
  from ._utils.name_utils import check_object_name, is_valid_tag
@@ -602,8 +601,9 @@ async def _interactive_shell(
602
601
  "MODAL_ENVIRONMENT": _get_environment_name(),
603
602
  }
604
603
  secrets = kwargs.pop("secrets", []) + [_Secret.from_dict(sandbox_env)]
604
+
605
605
  with enable_output(): # show any image build logs
606
- sandbox = await _Sandbox.create(
606
+ sandbox = await _Sandbox._create(
607
607
  "sleep",
608
608
  "100000",
609
609
  app=_app,
@@ -632,24 +632,7 @@ async def _interactive_shell(
632
632
  raise
633
633
 
634
634
 
635
- def _run_stub(*args: Any, **kwargs: Any):
636
- """mdmd:hidden
637
- `run_stub` has been renamed to `run_app` and is deprecated. Please update your code.
638
- """
639
- deprecation_error(
640
- (2024, 5, 1), "`run_stub` has been renamed to `run_app` and is deprecated. Please update your code."
641
- )
642
-
643
-
644
- def _deploy_stub(*args: Any, **kwargs: Any):
645
- """mdmd:hidden"""
646
- message = "`deploy_stub` has been renamed to `deploy_app`. Please update your code."
647
- deprecation_error((2024, 5, 1), message)
648
-
649
-
650
635
  run_app = synchronize_api(_run_app)
651
636
  serve_update = synchronize_api(_serve_update)
652
637
  deploy_app = synchronize_api(_deploy_app)
653
638
  interactive_shell = synchronize_api(_interactive_shell)
654
- run_stub = synchronize_api(_run_stub)
655
- deploy_stub = synchronize_api(_deploy_stub)
modal/runner.pyi CHANGED
@@ -83,8 +83,6 @@ async def _deploy_app(
83
83
  async def _interactive_shell(
84
84
  _app: _App, cmds: list[str], environment_name: str = "", pty: bool = True, **kwargs: typing.Any
85
85
  ) -> None: ...
86
- def _run_stub(*args: typing.Any, **kwargs: typing.Any): ...
87
- def _deploy_stub(*args: typing.Any, **kwargs: typing.Any): ...
88
86
 
89
87
  class __run_app_spec(typing_extensions.Protocol):
90
88
  def __call__(
@@ -153,6 +151,3 @@ class __interactive_shell_spec(typing_extensions.Protocol):
153
151
  ) -> None: ...
154
152
 
155
153
  interactive_shell: __interactive_shell_spec
156
-
157
- def run_stub(*args: typing.Any, **kwargs: typing.Any): ...
158
- def deploy_stub(*args: typing.Any, **kwargs: typing.Any): ...
modal/sandbox.py CHANGED
@@ -12,6 +12,7 @@ from grpclib import GRPCError, Status
12
12
 
13
13
  from modal._tunnel import Tunnel
14
14
  from modal.cloud_bucket_mount import _CloudBucketMount, cloud_bucket_mounts_to_proto
15
+ from modal.mount import _Mount
15
16
  from modal.volume import _Volume
16
17
  from modal_proto import api_pb2
17
18
 
@@ -19,7 +20,6 @@ from ._object import _get_environment_name, _Object
19
20
  from ._resolver import Resolver
20
21
  from ._resources import convert_fn_config_to_resources_config
21
22
  from ._utils.async_utils import TaskContext, synchronize_api
22
- from ._utils.deprecation import deprecation_error
23
23
  from ._utils.grpc_utils import retry_transient_errors
24
24
  from ._utils.mount_utils import validate_network_file_systems, validate_volumes
25
25
  from .client import _Client
@@ -30,7 +30,6 @@ from .file_io import FileWatchEvent, FileWatchEventType, _FileIO
30
30
  from .gpu import GPU_T
31
31
  from .image import _Image
32
32
  from .io_streams import StreamReader, StreamWriter, _StreamReader, _StreamWriter
33
- from .mount import _Mount
34
33
  from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
35
34
  from .proxy import _Proxy
36
35
  from .scheduler_placement import SchedulerPlacement
@@ -86,7 +85,6 @@ class _Sandbox(_Object, type_prefix="sb"):
86
85
  def _new(
87
86
  entrypoint_args: Sequence[str],
88
87
  image: _Image,
89
- mounts: Sequence[_Mount],
90
88
  secrets: Sequence[_Secret],
91
89
  timeout: Optional[int] = None,
92
90
  workdir: Optional[str] = None,
@@ -95,6 +93,7 @@ class _Sandbox(_Object, type_prefix="sb"):
95
93
  region: Optional[Union[str, Sequence[str]]] = None,
96
94
  cpu: Optional[float] = None,
97
95
  memory: Optional[Union[int, tuple[int, int]]] = None,
96
+ mounts: Sequence[_Mount] = (),
98
97
  network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
99
98
  block_network: bool = False,
100
99
  cidr_allowlist: Optional[Sequence[str]] = None,
@@ -218,7 +217,6 @@ class _Sandbox(_Object, type_prefix="sb"):
218
217
  app: Optional["modal.app._App"] = None, # Optionally associate the sandbox with an app
219
218
  environment_name: Optional[str] = None, # Optionally override the default environment
220
219
  image: Optional[_Image] = None, # The image to run as the container for the sandbox.
221
- mounts: Sequence[_Mount] = (), # Mounts to attach to the sandbox.
222
220
  secrets: Sequence[_Secret] = (), # Environment variables to inject into the sandbox.
223
221
  network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
224
222
  timeout: Optional[int] = None, # Maximum execution time of the sandbox in seconds.
@@ -265,6 +263,76 @@ class _Sandbox(_Object, type_prefix="sb"):
265
263
  sandbox.wait()
266
264
  ```
267
265
  """
266
+ return await _Sandbox._create(
267
+ *entrypoint_args,
268
+ app=app,
269
+ environment_name=environment_name,
270
+ image=image,
271
+ secrets=secrets,
272
+ network_file_systems=network_file_systems,
273
+ timeout=timeout,
274
+ workdir=workdir,
275
+ gpu=gpu,
276
+ cloud=cloud,
277
+ region=region,
278
+ cpu=cpu,
279
+ memory=memory,
280
+ block_network=block_network,
281
+ cidr_allowlist=cidr_allowlist,
282
+ volumes=volumes,
283
+ pty_info=pty_info,
284
+ encrypted_ports=encrypted_ports,
285
+ unencrypted_ports=unencrypted_ports,
286
+ proxy=proxy,
287
+ _experimental_enable_snapshot=_experimental_enable_snapshot,
288
+ _experimental_scheduler_placement=_experimental_scheduler_placement,
289
+ client=client,
290
+ )
291
+
292
+ @staticmethod
293
+ async def _create(
294
+ *entrypoint_args: str,
295
+ app: Optional["modal.app._App"] = None, # Optionally associate the sandbox with an app
296
+ environment_name: Optional[str] = None, # Optionally override the default environment
297
+ image: Optional[_Image] = None, # The image to run as the container for the sandbox.
298
+ secrets: Sequence[_Secret] = (), # Environment variables to inject into the sandbox.
299
+ mounts: Sequence[_Mount] = (),
300
+ network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
301
+ timeout: Optional[int] = None, # Maximum execution time of the sandbox in seconds.
302
+ workdir: Optional[str] = None, # Working directory of the sandbox.
303
+ gpu: GPU_T = None,
304
+ cloud: Optional[str] = None,
305
+ region: Optional[Union[str, Sequence[str]]] = None, # Region or regions to run the sandbox on.
306
+ # Specify, in fractional CPU cores, how many CPU cores to request.
307
+ # Or, pass (request, limit) to additionally specify a hard limit in fractional CPU cores.
308
+ # CPU throttling will prevent a container from exceeding its specified limit.
309
+ cpu: Optional[Union[float, tuple[float, float]]] = None,
310
+ # Specify, in MiB, a memory request which is the minimum memory required.
311
+ # Or, pass (request, limit) to additionally specify a hard limit in MiB.
312
+ memory: Optional[Union[int, tuple[int, int]]] = None,
313
+ block_network: bool = False, # Whether to block network access
314
+ # List of CIDRs the sandbox is allowed to access. If None, all CIDRs are allowed.
315
+ cidr_allowlist: Optional[Sequence[str]] = None,
316
+ volumes: dict[
317
+ Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]
318
+ ] = {}, # Mount points for Modal Volumes and CloudBucketMounts
319
+ pty_info: Optional[api_pb2.PTYInfo] = None,
320
+ # List of ports to tunnel into the sandbox. Encrypted ports are tunneled with TLS.
321
+ encrypted_ports: Sequence[int] = [],
322
+ # List of ports to tunnel into the sandbox without encryption.
323
+ unencrypted_ports: Sequence[int] = [],
324
+ # Reference to a Modal Proxy to use in front of this Sandbox.
325
+ proxy: Optional[_Proxy] = None,
326
+ # Enable memory snapshots.
327
+ _experimental_enable_snapshot: bool = False,
328
+ _experimental_scheduler_placement: Optional[
329
+ SchedulerPlacement
330
+ ] = None, # Experimental controls over fine-grained scheduling (alpha).
331
+ client: Optional[_Client] = None,
332
+ ):
333
+ # This method exposes some internal arguments (currently `mounts`) which are not in the public API
334
+ # `mounts` is currently only used by modal shell (cli) to provide a function's mounts to the
335
+ # sandbox that runs the shell session
268
336
  from .app import _App
269
337
 
270
338
  environment_name = _get_environment_name(environment_name)
@@ -275,7 +343,6 @@ class _Sandbox(_Object, type_prefix="sb"):
275
343
  obj = _Sandbox._new(
276
344
  entrypoint_args,
277
345
  image=image or _default_image,
278
- mounts=mounts,
279
346
  secrets=secrets,
280
347
  timeout=timeout,
281
348
  workdir=workdir,
@@ -284,6 +351,7 @@ class _Sandbox(_Object, type_prefix="sb"):
284
351
  region=region,
285
352
  cpu=cpu,
286
353
  memory=memory,
354
+ mounts=mounts,
287
355
  network_file_systems=network_file_systems,
288
356
  block_network=block_network,
289
357
  cidr_allowlist=cidr_allowlist,
@@ -315,14 +383,12 @@ class _Sandbox(_Object, type_prefix="sb"):
315
383
  app_id = container_app.app_id
316
384
  app_client = container_app._client
317
385
  else:
318
- arglist = ", ".join(repr(s) for s in entrypoint_args)
319
- deprecation_error(
320
- (2024, 9, 14),
321
- "Creating a `Sandbox` without an `App` is deprecated.\n\n"
322
- "You may pass in an `App` object, or reference one by name with `App.lookup`:\n\n"
386
+ raise InvalidError(
387
+ "Sandboxes require an App when created outside of a Modal container.\n\n"
388
+ "Run an ephemeral App (`with app.run(): ...`), or reference a deployed App using `App.lookup`:\n\n"
323
389
  "```\n"
324
- "app = modal.App.lookup('sandbox-app', create_if_missing=True)\n"
325
- f"sb = modal.Sandbox.create({arglist}, app=app)\n"
390
+ 'app = modal.App.lookup("sandbox-app", create_if_missing=True)\n'
391
+ "sb = modal.Sandbox.create(..., app=app)\n"
326
392
  "```",
327
393
  )
328
394
 
@@ -762,23 +828,3 @@ class _Sandbox(_Object, type_prefix="sb"):
762
828
 
763
829
 
764
830
  Sandbox = synchronize_api(_Sandbox)
765
-
766
-
767
- def __getattr__(name):
768
- if name == "LogsReader":
769
- deprecation_error(
770
- (2024, 8, 12),
771
- "`modal.sandbox.LogsReader` is deprecated. Please import `modal.io_streams.StreamReader` instead.",
772
- )
773
- from .io_streams import StreamReader
774
-
775
- return StreamReader
776
- elif name == "StreamWriter":
777
- deprecation_error(
778
- (2024, 8, 12),
779
- "`modal.sandbox.StreamWriter` is deprecated. Please import `modal.io_streams.StreamWriter` instead.",
780
- )
781
- from .io_streams import StreamWriter
782
-
783
- return StreamWriter
784
- raise AttributeError(f"module {__name__} has no attribute {name}")
modal/sandbox.pyi CHANGED
@@ -40,7 +40,6 @@ class _Sandbox(modal._object._Object):
40
40
  def _new(
41
41
  entrypoint_args: collections.abc.Sequence[str],
42
42
  image: modal.image._Image,
43
- mounts: collections.abc.Sequence[modal.mount._Mount],
44
43
  secrets: collections.abc.Sequence[modal.secret._Secret],
45
44
  timeout: typing.Optional[int] = None,
46
45
  workdir: typing.Optional[str] = None,
@@ -49,6 +48,7 @@ class _Sandbox(modal._object._Object):
49
48
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
50
49
  cpu: typing.Optional[float] = None,
51
50
  memory: typing.Union[int, tuple[int, int], None] = None,
51
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
52
52
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
53
53
  block_network: bool = False,
54
54
  cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
@@ -69,7 +69,6 @@ class _Sandbox(modal._object._Object):
69
69
  app: typing.Optional[modal.app._App] = None,
70
70
  environment_name: typing.Optional[str] = None,
71
71
  image: typing.Optional[modal.image._Image] = None,
72
- mounts: collections.abc.Sequence[modal.mount._Mount] = (),
73
72
  secrets: collections.abc.Sequence[modal.secret._Secret] = (),
74
73
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
75
74
  timeout: typing.Optional[int] = None,
@@ -93,6 +92,36 @@ class _Sandbox(modal._object._Object):
93
92
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
94
93
  client: typing.Optional[modal.client._Client] = None,
95
94
  ) -> _Sandbox: ...
95
+ @staticmethod
96
+ async def _create(
97
+ *entrypoint_args: str,
98
+ app: typing.Optional[modal.app._App] = None,
99
+ environment_name: typing.Optional[str] = None,
100
+ image: typing.Optional[modal.image._Image] = None,
101
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
102
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
103
+ network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
104
+ timeout: typing.Optional[int] = None,
105
+ workdir: typing.Optional[str] = None,
106
+ gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
107
+ cloud: typing.Optional[str] = None,
108
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
109
+ cpu: typing.Union[float, tuple[float, float], None] = None,
110
+ memory: typing.Union[int, tuple[int, int], None] = None,
111
+ block_network: bool = False,
112
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
113
+ volumes: dict[
114
+ typing.Union[str, os.PathLike],
115
+ typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
116
+ ] = {},
117
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
118
+ encrypted_ports: collections.abc.Sequence[int] = [],
119
+ unencrypted_ports: collections.abc.Sequence[int] = [],
120
+ proxy: typing.Optional[modal.proxy._Proxy] = None,
121
+ _experimental_enable_snapshot: bool = False,
122
+ _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
123
+ client: typing.Optional[modal.client._Client] = None,
124
+ ): ...
96
125
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
97
126
  @staticmethod
98
127
  async def from_id(sandbox_id: str, client: typing.Optional[modal.client._Client] = None) -> _Sandbox: ...
@@ -182,7 +211,6 @@ class Sandbox(modal.object.Object):
182
211
  def _new(
183
212
  entrypoint_args: collections.abc.Sequence[str],
184
213
  image: modal.image.Image,
185
- mounts: collections.abc.Sequence[modal.mount.Mount],
186
214
  secrets: collections.abc.Sequence[modal.secret.Secret],
187
215
  timeout: typing.Optional[int] = None,
188
216
  workdir: typing.Optional[str] = None,
@@ -191,6 +219,7 @@ class Sandbox(modal.object.Object):
191
219
  region: typing.Union[str, collections.abc.Sequence[str], None] = None,
192
220
  cpu: typing.Optional[float] = None,
193
221
  memory: typing.Union[int, tuple[int, int], None] = None,
222
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
194
223
  network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem] = {},
195
224
  block_network: bool = False,
196
225
  cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
@@ -213,7 +242,6 @@ class Sandbox(modal.object.Object):
213
242
  app: typing.Optional[modal.app.App] = None,
214
243
  environment_name: typing.Optional[str] = None,
215
244
  image: typing.Optional[modal.image.Image] = None,
216
- mounts: collections.abc.Sequence[modal.mount.Mount] = (),
217
245
  secrets: collections.abc.Sequence[modal.secret.Secret] = (),
218
246
  network_file_systems: dict[
219
247
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
@@ -246,7 +274,6 @@ class Sandbox(modal.object.Object):
246
274
  app: typing.Optional[modal.app.App] = None,
247
275
  environment_name: typing.Optional[str] = None,
248
276
  image: typing.Optional[modal.image.Image] = None,
249
- mounts: collections.abc.Sequence[modal.mount.Mount] = (),
250
277
  secrets: collections.abc.Sequence[modal.secret.Secret] = (),
251
278
  network_file_systems: dict[
252
279
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
@@ -275,6 +302,76 @@ class Sandbox(modal.object.Object):
275
302
 
276
303
  create: __create_spec
277
304
 
305
+ class ___create_spec(typing_extensions.Protocol):
306
+ def __call__(
307
+ self,
308
+ /,
309
+ *entrypoint_args: str,
310
+ app: typing.Optional[modal.app.App] = None,
311
+ environment_name: typing.Optional[str] = None,
312
+ image: typing.Optional[modal.image.Image] = None,
313
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
314
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
315
+ network_file_systems: dict[
316
+ typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
317
+ ] = {},
318
+ timeout: typing.Optional[int] = None,
319
+ workdir: typing.Optional[str] = None,
320
+ gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
321
+ cloud: typing.Optional[str] = None,
322
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
323
+ cpu: typing.Union[float, tuple[float, float], None] = None,
324
+ memory: typing.Union[int, tuple[int, int], None] = None,
325
+ block_network: bool = False,
326
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
327
+ volumes: dict[
328
+ typing.Union[str, os.PathLike],
329
+ typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
330
+ ] = {},
331
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
332
+ encrypted_ports: collections.abc.Sequence[int] = [],
333
+ unencrypted_ports: collections.abc.Sequence[int] = [],
334
+ proxy: typing.Optional[modal.proxy.Proxy] = None,
335
+ _experimental_enable_snapshot: bool = False,
336
+ _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
337
+ client: typing.Optional[modal.client.Client] = None,
338
+ ): ...
339
+ async def aio(
340
+ self,
341
+ /,
342
+ *entrypoint_args: str,
343
+ app: typing.Optional[modal.app.App] = None,
344
+ environment_name: typing.Optional[str] = None,
345
+ image: typing.Optional[modal.image.Image] = None,
346
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
347
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
348
+ network_file_systems: dict[
349
+ typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
350
+ ] = {},
351
+ timeout: typing.Optional[int] = None,
352
+ workdir: typing.Optional[str] = None,
353
+ gpu: typing.Union[None, str, modal.gpu._GPUConfig] = None,
354
+ cloud: typing.Optional[str] = None,
355
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
356
+ cpu: typing.Union[float, tuple[float, float], None] = None,
357
+ memory: typing.Union[int, tuple[int, int], None] = None,
358
+ block_network: bool = False,
359
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
360
+ volumes: dict[
361
+ typing.Union[str, os.PathLike],
362
+ typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
363
+ ] = {},
364
+ pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
365
+ encrypted_ports: collections.abc.Sequence[int] = [],
366
+ unencrypted_ports: collections.abc.Sequence[int] = [],
367
+ proxy: typing.Optional[modal.proxy.Proxy] = None,
368
+ _experimental_enable_snapshot: bool = False,
369
+ _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
370
+ client: typing.Optional[modal.client.Client] = None,
371
+ ): ...
372
+
373
+ _create: ___create_spec
374
+
278
375
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
279
376
 
280
377
  class __from_id_spec(typing_extensions.Protocol):
@@ -484,6 +581,4 @@ class Sandbox(modal.object.Object):
484
581
 
485
582
  list: __list_spec
486
583
 
487
- def __getattr__(name): ...
488
-
489
584
  _default_image: modal.image._Image
modal/secret.py CHANGED
@@ -10,7 +10,7 @@ from ._object import _get_environment_name, _Object
10
10
  from ._resolver import Resolver
11
11
  from ._runtime.execution_context import is_local
12
12
  from ._utils.async_utils import synchronize_api
13
- from ._utils.deprecation import deprecation_warning, renamed_parameter
13
+ from ._utils.deprecation import deprecation_warning
14
14
  from ._utils.grpc_utils import retry_transient_errors
15
15
  from ._utils.name_utils import check_object_name
16
16
  from .client import _Client
@@ -162,7 +162,6 @@ class _Secret(_Object, type_prefix="st"):
162
162
  return _Secret._from_loader(_load, "Secret.from_dotenv()", hydrate_lazily=True)
163
163
 
164
164
  @staticmethod
165
- @renamed_parameter((2024, 12, 18), "label", "name")
166
165
  def from_name(
167
166
  name: str,
168
167
  *,
@@ -206,7 +205,6 @@ class _Secret(_Object, type_prefix="st"):
206
205
  return _Secret._from_loader(_load, "Secret()", hydrate_lazily=True)
207
206
 
208
207
  @staticmethod
209
- @renamed_parameter((2024, 12, 18), "label", "name")
210
208
  async def lookup(
211
209
  name: str,
212
210
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
modal/serving.py CHANGED
@@ -11,7 +11,6 @@ from synchronicity.async_wrap import asynccontextmanager
11
11
  from modal._output import OutputManager
12
12
 
13
13
  from ._utils.async_utils import TaskContext, asyncify, synchronize_api, synchronizer
14
- from ._utils.deprecation import deprecation_error
15
14
  from ._utils.logger import logger
16
15
  from ._watcher import watch
17
16
  from .cli.import_refs import ImportRef, import_app_from_ref
@@ -122,9 +121,4 @@ async def _serve_app(
122
121
  yield app
123
122
 
124
123
 
125
- def _serve_stub(*args, **kwargs):
126
- deprecation_error((2024, 5, 1), "`serve_stub` is deprecated. Please use `serve_app` instead.")
127
-
128
-
129
124
  serve_app = synchronize_api(_serve_app)
130
- serve_stub = synchronize_api(_serve_stub)
modal/serving.pyi CHANGED
@@ -33,7 +33,6 @@ def _serve_app(
33
33
  _watcher: typing.Optional[collections.abc.AsyncGenerator[set[str], None]] = None,
34
34
  environment_name: typing.Optional[str] = None,
35
35
  ) -> typing.AsyncContextManager[_App]: ...
36
- def _serve_stub(*args, **kwargs): ...
37
36
 
38
37
  class __serve_app_spec(typing_extensions.Protocol):
39
38
  def __call__(
@@ -56,5 +55,3 @@ class __serve_app_spec(typing_extensions.Protocol):
56
55
  ) -> typing.AsyncContextManager[_App]: ...
57
56
 
58
57
  serve_app: __serve_app_spec
59
-
60
- def serve_stub(*args, **kwargs): ...
modal/volume.py CHANGED
@@ -27,7 +27,7 @@ from grpclib import GRPCError, Status
27
27
  from synchronicity.async_wrap import asynccontextmanager
28
28
 
29
29
  import modal_proto.api_pb2
30
- from modal.exception import VolumeUploadTimeoutError
30
+ from modal.exception import InvalidError, VolumeUploadTimeoutError
31
31
  from modal_proto import api_pb2
32
32
 
33
33
  from ._object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
@@ -49,7 +49,7 @@ from ._utils.blob_utils import (
49
49
  get_file_upload_spec_from_fileobj,
50
50
  get_file_upload_spec_from_path,
51
51
  )
52
- from ._utils.deprecation import deprecation_error, deprecation_warning, renamed_parameter
52
+ from ._utils.deprecation import deprecation_warning
53
53
  from ._utils.grpc_utils import retry_transient_errors
54
54
  from ._utils.http_utils import ClientSessionRegistry
55
55
  from ._utils.name_utils import check_object_name
@@ -149,7 +149,6 @@ class _Volume(_Object, type_prefix="vo"):
149
149
  return self._lock
150
150
 
151
151
  @staticmethod
152
- @renamed_parameter((2024, 12, 18), "label", "name")
153
152
  def from_name(
154
153
  name: str,
155
154
  *,
@@ -244,7 +243,6 @@ class _Volume(_Object, type_prefix="vo"):
244
243
  yield cls._new_hydrated(response.volume_id, client, response.metadata, is_another_app=True)
245
244
 
246
245
  @staticmethod
247
- @renamed_parameter((2024, 12, 18), "label", "name")
248
246
  async def lookup(
249
247
  name: str,
250
248
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
@@ -253,7 +251,8 @@ class _Volume(_Object, type_prefix="vo"):
253
251
  create_if_missing: bool = False,
254
252
  version: "typing.Optional[modal_proto.api_pb2.VolumeFsVersion.ValueType]" = None,
255
253
  ) -> "_Volume":
256
- """Lookup a named Volume.
254
+ """mdmd:hidden
255
+ Lookup a named Volume.
257
256
 
258
257
  DEPRECATED: This method is deprecated in favor of `modal.Volume.from_name`.
259
258
 
@@ -366,21 +365,14 @@ class _Volume(_Object, type_prefix="vo"):
366
365
  recursively.
367
366
  """
368
367
  if path.endswith("**"):
369
- msg = (
368
+ raise InvalidError(
370
369
  "Glob patterns in `volume get` and `Volume.listdir()` are deprecated. "
371
370
  "Please pass recursive=True instead. For the CLI, just remove the glob suffix."
372
371
  )
373
- deprecation_error(
374
- (2024, 4, 23),
375
- msg,
376
- )
377
372
  elif path.endswith("*"):
378
- deprecation_error(
379
- (2024, 4, 23),
380
- (
381
- "Glob patterns in `volume get` and `Volume.listdir()` are deprecated. "
382
- "Please remove the glob `*` suffix."
383
- ),
373
+ raise InvalidError(
374
+ "Glob patterns in `volume get` and `Volume.listdir()` are deprecated. "
375
+ "Please remove the glob `*` suffix."
384
376
  )
385
377
 
386
378
  req = api_pb2.VolumeListFilesRequest(volume_id=self.object_id, path=path, recursive=recursive)
@@ -595,7 +587,6 @@ class _Volume(_Object, type_prefix="vo"):
595
587
  )
596
588
 
597
589
  @staticmethod
598
- @renamed_parameter((2024, 12, 18), "label", "name")
599
590
  async def delete(name: str, client: Optional[_Client] = None, environment_name: Optional[str] = None):
600
591
  obj = await _Volume.from_name(name, environment_name=environment_name).hydrate(client)
601
592
  req = api_pb2.VolumeDeleteRequest(volume_id=obj.object_id)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 0.77.0
3
+ Version: 1.0.0
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0