modal 0.67.6__py3-none-any.whl → 0.67.11__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.
Files changed (103) hide show
  1. modal/_clustered_functions.py +2 -2
  2. modal/_clustered_functions.pyi +2 -2
  3. modal/_container_entrypoint.py +5 -4
  4. modal/_output.py +29 -28
  5. modal/_pty.py +2 -2
  6. modal/_resolver.py +6 -5
  7. modal/_resources.py +3 -3
  8. modal/_runtime/asgi.py +7 -6
  9. modal/_runtime/container_io_manager.py +22 -26
  10. modal/_runtime/execution_context.py +2 -2
  11. modal/_runtime/telemetry.py +1 -2
  12. modal/_runtime/user_code_imports.py +12 -14
  13. modal/_serialization.py +3 -7
  14. modal/_traceback.py +5 -5
  15. modal/_tunnel.py +4 -3
  16. modal/_tunnel.pyi +2 -2
  17. modal/_utils/async_utils.py +8 -15
  18. modal/_utils/blob_utils.py +4 -3
  19. modal/_utils/function_utils.py +14 -10
  20. modal/_utils/grpc_testing.py +7 -6
  21. modal/_utils/grpc_utils.py +2 -3
  22. modal/_utils/hash_utils.py +2 -2
  23. modal/_utils/mount_utils.py +5 -4
  24. modal/_utils/package_utils.py +2 -3
  25. modal/_utils/pattern_matcher.py +6 -6
  26. modal/_utils/rand_pb_testing.py +3 -3
  27. modal/_utils/shell_utils.py +2 -1
  28. modal/_vendor/a2wsgi_wsgi.py +62 -72
  29. modal/_vendor/cloudpickle.py +1 -1
  30. modal/_watcher.py +8 -7
  31. modal/app.py +29 -34
  32. modal/app.pyi +102 -97
  33. modal/call_graph.py +6 -6
  34. modal/cli/_download.py +3 -2
  35. modal/cli/_traceback.py +4 -4
  36. modal/cli/app.py +4 -4
  37. modal/cli/container.py +4 -4
  38. modal/cli/dict.py +1 -1
  39. modal/cli/environment.py +2 -3
  40. modal/cli/launch.py +2 -2
  41. modal/cli/network_file_system.py +1 -1
  42. modal/cli/profile.py +1 -1
  43. modal/cli/programs/run_jupyter.py +2 -2
  44. modal/cli/programs/vscode.py +3 -3
  45. modal/cli/queues.py +1 -1
  46. modal/cli/run.py +6 -6
  47. modal/cli/secret.py +3 -3
  48. modal/cli/utils.py +2 -1
  49. modal/cli/volume.py +3 -3
  50. modal/client.py +6 -11
  51. modal/client.pyi +18 -27
  52. modal/cloud_bucket_mount.py +3 -3
  53. modal/cloud_bucket_mount.pyi +2 -2
  54. modal/cls.py +30 -30
  55. modal/cls.pyi +35 -34
  56. modal/config.py +3 -2
  57. modal/dict.py +4 -3
  58. modal/dict.pyi +10 -9
  59. modal/environments.py +3 -3
  60. modal/environments.pyi +3 -3
  61. modal/exception.py +2 -3
  62. modal/functions.py +105 -35
  63. modal/functions.pyi +71 -48
  64. modal/image.py +45 -48
  65. modal/image.pyi +102 -101
  66. modal/io_streams.py +4 -7
  67. modal/io_streams.pyi +14 -13
  68. modal/mount.py +23 -22
  69. modal/mount.pyi +28 -29
  70. modal/network_file_system.py +7 -6
  71. modal/network_file_system.pyi +12 -11
  72. modal/object.py +9 -8
  73. modal/object.pyi +47 -34
  74. modal/output.py +2 -1
  75. modal/parallel_map.py +4 -4
  76. modal/partial_function.py +9 -13
  77. modal/partial_function.pyi +17 -18
  78. modal/queue.py +9 -8
  79. modal/queue.pyi +23 -22
  80. modal/retries.py +38 -0
  81. modal/runner.py +8 -7
  82. modal/runner.pyi +8 -14
  83. modal/running_app.py +3 -3
  84. modal/sandbox.py +14 -13
  85. modal/sandbox.pyi +67 -72
  86. modal/scheduler_placement.py +2 -1
  87. modal/secret.py +7 -7
  88. modal/secret.pyi +12 -12
  89. modal/serving.py +4 -3
  90. modal/serving.pyi +5 -4
  91. modal/token_flow.py +3 -2
  92. modal/token_flow.pyi +3 -3
  93. modal/volume.py +7 -12
  94. modal/volume.pyi +17 -16
  95. {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/METADATA +1 -1
  96. modal-0.67.11.dist-info/RECORD +168 -0
  97. modal_docs/mdmd/signatures.py +1 -2
  98. modal_version/_version_generated.py +1 -1
  99. modal-0.67.6.dist-info/RECORD +0 -168
  100. {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/LICENSE +0 -0
  101. {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/WHEEL +0 -0
  102. {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/entry_points.txt +0 -0
  103. {modal-0.67.6.dist-info → modal-0.67.11.dist-info}/top_level.txt +0 -0
modal/retries.py CHANGED
@@ -1,10 +1,14 @@
1
1
  # Copyright Modal Labs 2022
2
+ import asyncio
2
3
  from datetime import timedelta
3
4
 
4
5
  from modal_proto import api_pb2
5
6
 
6
7
  from .exception import InvalidError
7
8
 
9
+ MIN_INPUT_RETRY_DELAY_MS = 1000
10
+ MAX_INPUT_RETRY_DELAY_MS = 24 * 60 * 60 * 1000
11
+
8
12
 
9
13
  class Retries:
10
14
  """Adds a retry policy to a Modal function.
@@ -103,3 +107,37 @@ class Retries:
103
107
  initial_delay_ms=self.initial_delay // timedelta(milliseconds=1),
104
108
  max_delay_ms=self.max_delay // timedelta(milliseconds=1),
105
109
  )
110
+
111
+
112
+ class RetryManager:
113
+ """
114
+ Helper class to apply the specified retry policy.
115
+ """
116
+
117
+ def __init__(self, retry_policy: api_pb2.FunctionRetryPolicy):
118
+ self.retry_policy = retry_policy
119
+ self.attempt_count = 0
120
+
121
+ async def raise_or_sleep(self, exc: Exception):
122
+ """
123
+ Raises an exception if the maximum retry count has been reached, otherwise sleeps for calculated delay.
124
+ """
125
+ self.attempt_count += 1
126
+ if self.attempt_count > self.retry_policy.retries:
127
+ raise exc
128
+ delay_ms = self._retry_delay_ms(self.attempt_count, self.retry_policy)
129
+ await asyncio.sleep(delay_ms / 1000)
130
+
131
+ @staticmethod
132
+ def _retry_delay_ms(attempt_count: int, retry_policy: api_pb2.FunctionRetryPolicy) -> float:
133
+ """
134
+ Computes the amount of time to sleep before retrying based on the backend_coefficient and initial_delay_ms args.
135
+ """
136
+ if attempt_count < 1:
137
+ raise ValueError(f"Cannot compute retry delay. attempt_count must be at least 1, but was {attempt_count}")
138
+ delay_ms = retry_policy.initial_delay_ms * (retry_policy.backoff_coefficient ** (attempt_count - 1))
139
+ if delay_ms < MIN_INPUT_RETRY_DELAY_MS:
140
+ return MIN_INPUT_RETRY_DELAY_MS
141
+ if delay_ms > MAX_INPUT_RETRY_DELAY_MS:
142
+ return MAX_INPUT_RETRY_DELAY_MS
143
+ return delay_ms
modal/runner.py CHANGED
@@ -4,8 +4,9 @@ import dataclasses
4
4
  import os
5
5
  import time
6
6
  import typing
7
+ from collections.abc import AsyncGenerator
7
8
  from multiprocessing.synchronize import Event
8
- from typing import TYPE_CHECKING, Any, AsyncGenerator, Callable, Dict, List, Optional, Tuple, TypeVar
9
+ from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar
9
10
 
10
11
  from grpclib import GRPCError, Status
11
12
  from synchronicity.async_wrap import asynccontextmanager
@@ -123,7 +124,7 @@ async def _init_local_app_from_name(
123
124
  async def _create_all_objects(
124
125
  client: _Client,
125
126
  running_app: RunningApp,
126
- indexed_objects: Dict[str, _Object],
127
+ indexed_objects: dict[str, _Object],
127
128
  environment_name: str,
128
129
  ) -> None:
129
130
  """Create objects that have been defined but not created on the server."""
@@ -171,15 +172,15 @@ async def _publish_app(
171
172
  client: _Client,
172
173
  running_app: RunningApp,
173
174
  app_state: int, # api_pb2.AppState.value
174
- indexed_objects: Dict[str, _Object],
175
+ indexed_objects: dict[str, _Object],
175
176
  name: str = "", # Only relevant for deployments
176
177
  tag: str = "", # Only relevant for deployments
177
- ) -> Tuple[str, List[str]]:
178
+ ) -> tuple[str, list[str]]:
178
179
  """Wrapper for AppPublish RPC."""
179
180
 
180
181
  # Could simplify this function some changing the internal representation to use
181
182
  # function_ids / class_ids rather than the current tag_to_object_id (i.e. "indexed_objects")
182
- def filter_values(full_dict: Dict[str, V], condition: Callable[[V], bool]) -> Dict[str, V]:
183
+ def filter_values(full_dict: dict[str, V], condition: Callable[[V], bool]) -> dict[str, V]:
183
184
  return {k: v for k, v in full_dict.items() if condition(v)}
184
185
 
185
186
  function_ids = filter_values(running_app.tag_to_object_id, _Function._is_id_type)
@@ -453,7 +454,7 @@ class DeployResult:
453
454
  app_id: str
454
455
  app_page_url: str
455
456
  app_logs_url: str
456
- warnings: List[str]
457
+ warnings: list[str]
457
458
 
458
459
 
459
460
  async def _deploy_app(
@@ -556,7 +557,7 @@ async def _deploy_app(
556
557
  )
557
558
 
558
559
 
559
- async def _interactive_shell(_app: _App, cmds: List[str], environment_name: str = "", **kwargs: Any) -> None:
560
+ async def _interactive_shell(_app: _App, cmds: list[str], environment_name: str = "", **kwargs: Any) -> None:
560
561
  """Run an interactive shell (like `bash`) within the image for this app.
561
562
 
562
563
  This is useful for online debugging and interactive exploration of the
modal/runner.pyi CHANGED
@@ -27,17 +27,17 @@ async def _init_local_app_from_name(
27
27
  async def _create_all_objects(
28
28
  client: modal.client._Client,
29
29
  running_app: modal.running_app.RunningApp,
30
- indexed_objects: typing.Dict[str, modal.object._Object],
30
+ indexed_objects: dict[str, modal.object._Object],
31
31
  environment_name: str,
32
32
  ) -> None: ...
33
33
  async def _publish_app(
34
34
  client: modal.client._Client,
35
35
  running_app: modal.running_app.RunningApp,
36
36
  app_state: int,
37
- indexed_objects: typing.Dict[str, modal.object._Object],
37
+ indexed_objects: dict[str, modal.object._Object],
38
38
  name: str = "",
39
39
  tag: str = "",
40
- ) -> typing.Tuple[str, typing.List[str]]: ...
40
+ ) -> tuple[str, list[str]]: ...
41
41
  async def _disconnect(client: modal.client._Client, app_id: str, reason: int, exc_str: str = "") -> None: ...
42
42
  async def _status_based_disconnect(
43
43
  client: modal.client._Client, app_id: str, exc_info: typing.Optional[BaseException] = None
@@ -58,9 +58,9 @@ class DeployResult:
58
58
  app_id: str
59
59
  app_page_url: str
60
60
  app_logs_url: str
61
- warnings: typing.List[str]
61
+ warnings: list[str]
62
62
 
63
- def __init__(self, app_id: str, app_page_url: str, app_logs_url: str, warnings: typing.List[str]) -> None: ...
63
+ def __init__(self, app_id: str, app_page_url: str, app_logs_url: str, warnings: list[str]) -> None: ...
64
64
  def __repr__(self): ...
65
65
  def __eq__(self, other): ...
66
66
  def __setattr__(self, name, value): ...
@@ -75,9 +75,7 @@ async def _deploy_app(
75
75
  environment_name: typing.Optional[str] = None,
76
76
  tag: str = "",
77
77
  ) -> DeployResult: ...
78
- async def _interactive_shell(
79
- _app: _App, cmds: typing.List[str], environment_name: str = "", **kwargs: typing.Any
80
- ) -> None: ...
78
+ async def _interactive_shell(_app: _App, cmds: list[str], environment_name: str = "", **kwargs: typing.Any) -> None: ...
81
79
  def _run_stub(*args: typing.Any, **kwargs: typing.Any): ...
82
80
  def _deploy_stub(*args: typing.Any, **kwargs: typing.Any): ...
83
81
 
@@ -136,12 +134,8 @@ class __deploy_app_spec(typing_extensions.Protocol):
136
134
  deploy_app: __deploy_app_spec
137
135
 
138
136
  class __interactive_shell_spec(typing_extensions.Protocol):
139
- def __call__(
140
- self, _app: _App, cmds: typing.List[str], environment_name: str = "", **kwargs: typing.Any
141
- ) -> None: ...
142
- async def aio(
143
- self, _app: _App, cmds: typing.List[str], environment_name: str = "", **kwargs: typing.Any
144
- ) -> None: ...
137
+ def __call__(self, _app: _App, cmds: list[str], environment_name: str = "", **kwargs: typing.Any) -> None: ...
138
+ async def aio(self, _app: _App, cmds: list[str], environment_name: str = "", **kwargs: typing.Any) -> None: ...
145
139
 
146
140
  interactive_shell: __interactive_shell_spec
147
141
 
modal/running_app.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Copyright Modal Labs 2024
2
2
  from dataclasses import dataclass, field
3
- from typing import Dict, Optional
3
+ from typing import Optional
4
4
 
5
5
  from google.protobuf.message import Message
6
6
 
@@ -13,7 +13,7 @@ class RunningApp:
13
13
  environment_name: Optional[str] = None
14
14
  app_page_url: Optional[str] = None
15
15
  app_logs_url: Optional[str] = None
16
- tag_to_object_id: Dict[str, str] = field(default_factory=dict)
17
- object_handle_metadata: Dict[str, Optional[Message]] = field(default_factory=dict)
16
+ tag_to_object_id: dict[str, str] = field(default_factory=dict)
17
+ object_handle_metadata: dict[str, Optional[Message]] = field(default_factory=dict)
18
18
  interactive: bool = False
19
19
  client: Optional[_Client] = None
modal/sandbox.py CHANGED
@@ -1,7 +1,8 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import asyncio
3
3
  import os
4
- from typing import TYPE_CHECKING, AsyncGenerator, Dict, List, Literal, Optional, Sequence, Tuple, Union, overload
4
+ from collections.abc import AsyncGenerator, Sequence
5
+ from typing import TYPE_CHECKING, Literal, Optional, Union, overload
5
6
 
6
7
  from google.protobuf.message import Message
7
8
  from grpclib import GRPCError, Status
@@ -50,7 +51,7 @@ class _Sandbox(_Object, type_prefix="sb"):
50
51
  _stderr: _StreamReader[str]
51
52
  _stdin: _StreamWriter
52
53
  _task_id: Optional[str] = None
53
- _tunnels: Optional[Dict[int, Tunnel]] = None
54
+ _tunnels: Optional[dict[int, Tunnel]] = None
54
55
 
55
56
  @staticmethod
56
57
  def _new(
@@ -64,11 +65,11 @@ class _Sandbox(_Object, type_prefix="sb"):
64
65
  cloud: Optional[str] = None,
65
66
  region: Optional[Union[str, Sequence[str]]] = None,
66
67
  cpu: Optional[float] = None,
67
- memory: Optional[Union[int, Tuple[int, int]]] = None,
68
- network_file_systems: Dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
68
+ memory: Optional[Union[int, tuple[int, int]]] = None,
69
+ network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
69
70
  block_network: bool = False,
70
71
  cidr_allowlist: Optional[Sequence[str]] = None,
71
- volumes: Dict[Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]] = {},
72
+ volumes: dict[Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]] = {},
72
73
  pty_info: Optional[api_pb2.PTYInfo] = None,
73
74
  encrypted_ports: Sequence[int] = [],
74
75
  unencrypted_ports: Sequence[int] = [],
@@ -101,8 +102,8 @@ class _Sandbox(_Object, type_prefix="sb"):
101
102
  cloud_bucket_mounts = [(k, v) for k, v in validated_volumes if isinstance(v, _CloudBucketMount)]
102
103
  validated_volumes = [(k, v) for k, v in validated_volumes if isinstance(v, _Volume)]
103
104
 
104
- def _deps() -> List[_Object]:
105
- deps: List[_Object] = [image] + list(mounts) + list(secrets)
105
+ def _deps() -> list[_Object]:
106
+ deps: list[_Object] = [image] + list(mounts) + list(secrets)
106
107
  for _, vol in validated_network_file_systems:
107
108
  deps.append(vol)
108
109
  for _, vol in validated_volumes:
@@ -186,7 +187,7 @@ class _Sandbox(_Object, type_prefix="sb"):
186
187
  image: Optional[_Image] = None, # The image to run as the container for the sandbox.
187
188
  mounts: Sequence[_Mount] = (), # Mounts to attach to the sandbox.
188
189
  secrets: Sequence[_Secret] = (), # Environment variables to inject into the sandbox.
189
- network_file_systems: Dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
190
+ network_file_systems: dict[Union[str, os.PathLike], _NetworkFileSystem] = {},
190
191
  timeout: Optional[int] = None, # Maximum execution time of the sandbox in seconds.
191
192
  workdir: Optional[str] = None, # Working directory of the sandbox.
192
193
  gpu: GPU_T = None,
@@ -195,11 +196,11 @@ class _Sandbox(_Object, type_prefix="sb"):
195
196
  cpu: Optional[float] = None, # How many CPU cores to request. This is a soft limit.
196
197
  # Specify, in MiB, a memory request which is the minimum memory required.
197
198
  # Or, pass (request, limit) to additionally specify a hard limit in MiB.
198
- memory: Optional[Union[int, Tuple[int, int]]] = None,
199
+ memory: Optional[Union[int, tuple[int, int]]] = None,
199
200
  block_network: bool = False, # Whether to block network access
200
201
  # List of CIDRs the sandbox is allowed to access. If None, all CIDRs are allowed.
201
202
  cidr_allowlist: Optional[Sequence[str]] = None,
202
- volumes: Dict[
203
+ volumes: dict[
203
204
  Union[str, os.PathLike], Union[_Volume, _CloudBucketMount]
204
205
  ] = {}, # Mount points for Modal Volumes and CloudBucketMounts
205
206
  pty_info: Optional[api_pb2.PTYInfo] = None,
@@ -306,7 +307,7 @@ class _Sandbox(_Object, type_prefix="sb"):
306
307
 
307
308
  return obj
308
309
 
309
- async def set_tags(self, tags: Dict[str, str], *, client: Optional[_Client] = None):
310
+ async def set_tags(self, tags: dict[str, str], *, client: Optional[_Client] = None):
310
311
  """Set tags (key-value pairs) on the Sandbox. Tags can be used to filter results in `Sandbox.list`."""
311
312
  environment_name = _get_environment_name()
312
313
  if client is None:
@@ -341,7 +342,7 @@ class _Sandbox(_Object, type_prefix="sb"):
341
342
  raise SandboxTerminatedError()
342
343
  break
343
344
 
344
- async def tunnels(self, timeout: int = 50) -> Dict[int, Tunnel]:
345
+ async def tunnels(self, timeout: int = 50) -> dict[int, Tunnel]:
345
346
  """Get tunnel metadata for the sandbox.
346
347
 
347
348
  Raises `SandboxTimeoutError` if the tunnels are not available after the timeout.
@@ -531,7 +532,7 @@ class _Sandbox(_Object, type_prefix="sb"):
531
532
 
532
533
  @staticmethod
533
534
  async def list(
534
- *, app_id: Optional[str] = None, tags: Optional[Dict[str, str]] = None, client: Optional[_Client] = None
535
+ *, app_id: Optional[str] = None, tags: Optional[dict[str, str]] = None, client: Optional[_Client] = None
535
536
  ) -> AsyncGenerator["_Sandbox", None]:
536
537
  """List all sandboxes for the current environment or app ID (if specified). If tags are specified, only
537
538
  sandboxes that have at least those tags are returned. Returns an iterator over `Sandbox` objects."""
modal/sandbox.pyi CHANGED
@@ -1,3 +1,4 @@
1
+ import collections.abc
1
2
  import google.protobuf.message
2
3
  import modal._tunnel
3
4
  import modal.app
@@ -25,33 +26,31 @@ class _Sandbox(modal.object._Object):
25
26
  _stderr: modal.io_streams._StreamReader[str]
26
27
  _stdin: modal.io_streams._StreamWriter
27
28
  _task_id: typing.Optional[str]
28
- _tunnels: typing.Optional[typing.Dict[int, modal._tunnel.Tunnel]]
29
+ _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
29
30
 
30
31
  @staticmethod
31
32
  def _new(
32
- entrypoint_args: typing.Sequence[str],
33
+ entrypoint_args: collections.abc.Sequence[str],
33
34
  image: modal.image._Image,
34
- mounts: typing.Sequence[modal.mount._Mount],
35
- secrets: typing.Sequence[modal.secret._Secret],
35
+ mounts: collections.abc.Sequence[modal.mount._Mount],
36
+ secrets: collections.abc.Sequence[modal.secret._Secret],
36
37
  timeout: typing.Optional[int] = None,
37
38
  workdir: typing.Optional[str] = None,
38
39
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
39
40
  cloud: typing.Optional[str] = None,
40
- region: typing.Union[str, typing.Sequence[str], None] = None,
41
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
41
42
  cpu: typing.Optional[float] = None,
42
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
43
- network_file_systems: typing.Dict[
44
- typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem
45
- ] = {},
43
+ memory: typing.Union[int, tuple[int, int], None] = None,
44
+ network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
46
45
  block_network: bool = False,
47
- cidr_allowlist: typing.Optional[typing.Sequence[str]] = None,
48
- volumes: typing.Dict[
46
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
47
+ volumes: dict[
49
48
  typing.Union[str, os.PathLike],
50
49
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
51
50
  ] = {},
52
51
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
53
- encrypted_ports: typing.Sequence[int] = [],
54
- unencrypted_ports: typing.Sequence[int] = [],
52
+ encrypted_ports: collections.abc.Sequence[int] = [],
53
+ unencrypted_ports: collections.abc.Sequence[int] = [],
55
54
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
56
55
  ) -> _Sandbox: ...
57
56
  @staticmethod
@@ -60,36 +59,34 @@ class _Sandbox(modal.object._Object):
60
59
  app: typing.Optional[modal.app._App] = None,
61
60
  environment_name: typing.Optional[str] = None,
62
61
  image: typing.Optional[modal.image._Image] = None,
63
- mounts: typing.Sequence[modal.mount._Mount] = (),
64
- secrets: typing.Sequence[modal.secret._Secret] = (),
65
- network_file_systems: typing.Dict[
66
- typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem
67
- ] = {},
62
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
63
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
64
+ network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system._NetworkFileSystem] = {},
68
65
  timeout: typing.Optional[int] = None,
69
66
  workdir: typing.Optional[str] = None,
70
67
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
71
68
  cloud: typing.Optional[str] = None,
72
- region: typing.Union[str, typing.Sequence[str], None] = None,
69
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
73
70
  cpu: typing.Optional[float] = None,
74
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
71
+ memory: typing.Union[int, tuple[int, int], None] = None,
75
72
  block_network: bool = False,
76
- cidr_allowlist: typing.Optional[typing.Sequence[str]] = None,
77
- volumes: typing.Dict[
73
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
74
+ volumes: dict[
78
75
  typing.Union[str, os.PathLike],
79
76
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
80
77
  ] = {},
81
78
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
82
- encrypted_ports: typing.Sequence[int] = [],
83
- unencrypted_ports: typing.Sequence[int] = [],
79
+ encrypted_ports: collections.abc.Sequence[int] = [],
80
+ unencrypted_ports: collections.abc.Sequence[int] = [],
84
81
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
85
82
  client: typing.Optional[modal.client._Client] = None,
86
83
  ) -> _Sandbox: ...
87
84
  def _hydrate_metadata(self, handle_metadata: typing.Optional[google.protobuf.message.Message]): ...
88
85
  @staticmethod
89
86
  async def from_id(sandbox_id: str, client: typing.Optional[modal.client._Client] = None) -> _Sandbox: ...
90
- async def set_tags(self, tags: typing.Dict[str, str], *, client: typing.Optional[modal.client._Client] = None): ...
87
+ async def set_tags(self, tags: dict[str, str], *, client: typing.Optional[modal.client._Client] = None): ...
91
88
  async def wait(self, raise_on_termination: bool = True): ...
92
- async def tunnels(self, timeout: int = 50) -> typing.Dict[int, modal._tunnel.Tunnel]: ...
89
+ async def tunnels(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
93
90
  async def terminate(self): ...
94
91
  async def poll(self) -> typing.Optional[int]: ...
95
92
  async def _get_task_id(self): ...
@@ -102,7 +99,7 @@ class _Sandbox(modal.object._Object):
102
99
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
103
100
  timeout: typing.Optional[int] = None,
104
101
  workdir: typing.Optional[str] = None,
105
- secrets: typing.Sequence[modal.secret._Secret] = (),
102
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
106
103
  text: typing.Literal[True] = True,
107
104
  bufsize: typing.Literal[-1, 1] = -1,
108
105
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -116,7 +113,7 @@ class _Sandbox(modal.object._Object):
116
113
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
117
114
  timeout: typing.Optional[int] = None,
118
115
  workdir: typing.Optional[str] = None,
119
- secrets: typing.Sequence[modal.secret._Secret] = (),
116
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
120
117
  text: typing.Literal[False] = False,
121
118
  bufsize: typing.Literal[-1, 1] = -1,
122
119
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -133,9 +130,9 @@ class _Sandbox(modal.object._Object):
133
130
  def list(
134
131
  *,
135
132
  app_id: typing.Optional[str] = None,
136
- tags: typing.Optional[typing.Dict[str, str]] = None,
133
+ tags: typing.Optional[dict[str, str]] = None,
137
134
  client: typing.Optional[modal.client._Client] = None,
138
- ) -> typing.AsyncGenerator[_Sandbox, None]: ...
135
+ ) -> collections.abc.AsyncGenerator[_Sandbox, None]: ...
139
136
 
140
137
  class Sandbox(modal.object.Object):
141
138
  _result: typing.Optional[modal_proto.api_pb2.GenericResult]
@@ -143,33 +140,31 @@ class Sandbox(modal.object.Object):
143
140
  _stderr: modal.io_streams.StreamReader[str]
144
141
  _stdin: modal.io_streams.StreamWriter
145
142
  _task_id: typing.Optional[str]
146
- _tunnels: typing.Optional[typing.Dict[int, modal._tunnel.Tunnel]]
143
+ _tunnels: typing.Optional[dict[int, modal._tunnel.Tunnel]]
147
144
 
148
145
  def __init__(self, *args, **kwargs): ...
149
146
  @staticmethod
150
147
  def _new(
151
- entrypoint_args: typing.Sequence[str],
148
+ entrypoint_args: collections.abc.Sequence[str],
152
149
  image: modal.image.Image,
153
- mounts: typing.Sequence[modal.mount.Mount],
154
- secrets: typing.Sequence[modal.secret.Secret],
150
+ mounts: collections.abc.Sequence[modal.mount.Mount],
151
+ secrets: collections.abc.Sequence[modal.secret.Secret],
155
152
  timeout: typing.Optional[int] = None,
156
153
  workdir: typing.Optional[str] = None,
157
154
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
158
155
  cloud: typing.Optional[str] = None,
159
- region: typing.Union[str, typing.Sequence[str], None] = None,
156
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
160
157
  cpu: typing.Optional[float] = None,
161
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
162
- network_file_systems: typing.Dict[
163
- typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
164
- ] = {},
158
+ memory: typing.Union[int, tuple[int, int], None] = None,
159
+ network_file_systems: dict[typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem] = {},
165
160
  block_network: bool = False,
166
- cidr_allowlist: typing.Optional[typing.Sequence[str]] = None,
167
- volumes: typing.Dict[
161
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
162
+ volumes: dict[
168
163
  typing.Union[str, os.PathLike], typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount]
169
164
  ] = {},
170
165
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
171
- encrypted_ports: typing.Sequence[int] = [],
172
- unencrypted_ports: typing.Sequence[int] = [],
166
+ encrypted_ports: collections.abc.Sequence[int] = [],
167
+ unencrypted_ports: collections.abc.Sequence[int] = [],
173
168
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
174
169
  ) -> Sandbox: ...
175
170
 
@@ -180,27 +175,27 @@ class Sandbox(modal.object.Object):
180
175
  app: typing.Optional[modal.app.App] = None,
181
176
  environment_name: typing.Optional[str] = None,
182
177
  image: typing.Optional[modal.image.Image] = None,
183
- mounts: typing.Sequence[modal.mount.Mount] = (),
184
- secrets: typing.Sequence[modal.secret.Secret] = (),
185
- network_file_systems: typing.Dict[
178
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
179
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
180
+ network_file_systems: dict[
186
181
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
187
182
  ] = {},
188
183
  timeout: typing.Optional[int] = None,
189
184
  workdir: typing.Optional[str] = None,
190
185
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
191
186
  cloud: typing.Optional[str] = None,
192
- region: typing.Union[str, typing.Sequence[str], None] = None,
187
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
193
188
  cpu: typing.Optional[float] = None,
194
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
189
+ memory: typing.Union[int, tuple[int, int], None] = None,
195
190
  block_network: bool = False,
196
- cidr_allowlist: typing.Optional[typing.Sequence[str]] = None,
197
- volumes: typing.Dict[
191
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
192
+ volumes: dict[
198
193
  typing.Union[str, os.PathLike],
199
194
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
200
195
  ] = {},
201
196
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
202
- encrypted_ports: typing.Sequence[int] = [],
203
- unencrypted_ports: typing.Sequence[int] = [],
197
+ encrypted_ports: collections.abc.Sequence[int] = [],
198
+ unencrypted_ports: collections.abc.Sequence[int] = [],
204
199
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
205
200
  client: typing.Optional[modal.client.Client] = None,
206
201
  ) -> Sandbox: ...
@@ -210,27 +205,27 @@ class Sandbox(modal.object.Object):
210
205
  app: typing.Optional[modal.app.App] = None,
211
206
  environment_name: typing.Optional[str] = None,
212
207
  image: typing.Optional[modal.image.Image] = None,
213
- mounts: typing.Sequence[modal.mount.Mount] = (),
214
- secrets: typing.Sequence[modal.secret.Secret] = (),
215
- network_file_systems: typing.Dict[
208
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
209
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
210
+ network_file_systems: dict[
216
211
  typing.Union[str, os.PathLike], modal.network_file_system.NetworkFileSystem
217
212
  ] = {},
218
213
  timeout: typing.Optional[int] = None,
219
214
  workdir: typing.Optional[str] = None,
220
215
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
221
216
  cloud: typing.Optional[str] = None,
222
- region: typing.Union[str, typing.Sequence[str], None] = None,
217
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
223
218
  cpu: typing.Optional[float] = None,
224
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
219
+ memory: typing.Union[int, tuple[int, int], None] = None,
225
220
  block_network: bool = False,
226
- cidr_allowlist: typing.Optional[typing.Sequence[str]] = None,
227
- volumes: typing.Dict[
221
+ cidr_allowlist: typing.Optional[collections.abc.Sequence[str]] = None,
222
+ volumes: dict[
228
223
  typing.Union[str, os.PathLike],
229
224
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
230
225
  ] = {},
231
226
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
232
- encrypted_ports: typing.Sequence[int] = [],
233
- unencrypted_ports: typing.Sequence[int] = [],
227
+ encrypted_ports: collections.abc.Sequence[int] = [],
228
+ unencrypted_ports: collections.abc.Sequence[int] = [],
234
229
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
235
230
  client: typing.Optional[modal.client.Client] = None,
236
231
  ) -> Sandbox: ...
@@ -246,8 +241,8 @@ class Sandbox(modal.object.Object):
246
241
  from_id: __from_id_spec
247
242
 
248
243
  class __set_tags_spec(typing_extensions.Protocol):
249
- def __call__(self, tags: typing.Dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
250
- async def aio(self, tags: typing.Dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
244
+ def __call__(self, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
245
+ async def aio(self, tags: dict[str, str], *, client: typing.Optional[modal.client.Client] = None): ...
251
246
 
252
247
  set_tags: __set_tags_spec
253
248
 
@@ -258,8 +253,8 @@ class Sandbox(modal.object.Object):
258
253
  wait: __wait_spec
259
254
 
260
255
  class __tunnels_spec(typing_extensions.Protocol):
261
- def __call__(self, timeout: int = 50) -> typing.Dict[int, modal._tunnel.Tunnel]: ...
262
- async def aio(self, timeout: int = 50) -> typing.Dict[int, modal._tunnel.Tunnel]: ...
256
+ def __call__(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
257
+ async def aio(self, timeout: int = 50) -> dict[int, modal._tunnel.Tunnel]: ...
263
258
 
264
259
  tunnels: __tunnels_spec
265
260
 
@@ -291,7 +286,7 @@ class Sandbox(modal.object.Object):
291
286
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
292
287
  timeout: typing.Optional[int] = None,
293
288
  workdir: typing.Optional[str] = None,
294
- secrets: typing.Sequence[modal.secret.Secret] = (),
289
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
295
290
  text: typing.Literal[True] = True,
296
291
  bufsize: typing.Literal[-1, 1] = -1,
297
292
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -305,7 +300,7 @@ class Sandbox(modal.object.Object):
305
300
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
306
301
  timeout: typing.Optional[int] = None,
307
302
  workdir: typing.Optional[str] = None,
308
- secrets: typing.Sequence[modal.secret.Secret] = (),
303
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
309
304
  text: typing.Literal[False] = False,
310
305
  bufsize: typing.Literal[-1, 1] = -1,
311
306
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -319,7 +314,7 @@ class Sandbox(modal.object.Object):
319
314
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
320
315
  timeout: typing.Optional[int] = None,
321
316
  workdir: typing.Optional[str] = None,
322
- secrets: typing.Sequence[modal.secret.Secret] = (),
317
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
323
318
  text: typing.Literal[True] = True,
324
319
  bufsize: typing.Literal[-1, 1] = -1,
325
320
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -333,7 +328,7 @@ class Sandbox(modal.object.Object):
333
328
  stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
334
329
  timeout: typing.Optional[int] = None,
335
330
  workdir: typing.Optional[str] = None,
336
- secrets: typing.Sequence[modal.secret.Secret] = (),
331
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
337
332
  text: typing.Literal[False] = False,
338
333
  bufsize: typing.Literal[-1, 1] = -1,
339
334
  _pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
@@ -355,16 +350,16 @@ class Sandbox(modal.object.Object):
355
350
  self,
356
351
  *,
357
352
  app_id: typing.Optional[str] = None,
358
- tags: typing.Optional[typing.Dict[str, str]] = None,
353
+ tags: typing.Optional[dict[str, str]] = None,
359
354
  client: typing.Optional[modal.client.Client] = None,
360
355
  ) -> typing.Generator[Sandbox, None, None]: ...
361
356
  def aio(
362
357
  self,
363
358
  *,
364
359
  app_id: typing.Optional[str] = None,
365
- tags: typing.Optional[typing.Dict[str, str]] = None,
360
+ tags: typing.Optional[dict[str, str]] = None,
366
361
  client: typing.Optional[modal.client.Client] = None,
367
- ) -> typing.AsyncGenerator[Sandbox, None]: ...
362
+ ) -> collections.abc.AsyncGenerator[Sandbox, None]: ...
368
363
 
369
364
  list: __list_spec
370
365
 
@@ -1,5 +1,6 @@
1
1
  # Copyright Modal Labs 2024
2
- from typing import Optional, Sequence, Union
2
+ from collections.abc import Sequence
3
+ from typing import Optional, Union
3
4
 
4
5
  from modal_proto import api_pb2
5
6