modal 0.62.115__py3-none-any.whl → 0.72.13__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 (220) hide show
  1. modal/__init__.py +13 -9
  2. modal/__main__.py +41 -3
  3. modal/_clustered_functions.py +80 -0
  4. modal/_clustered_functions.pyi +22 -0
  5. modal/_container_entrypoint.py +402 -398
  6. modal/_ipython.py +3 -13
  7. modal/_location.py +17 -10
  8. modal/_output.py +243 -99
  9. modal/_pty.py +2 -2
  10. modal/_resolver.py +55 -60
  11. modal/_resources.py +26 -7
  12. modal/_runtime/__init__.py +1 -0
  13. modal/_runtime/asgi.py +519 -0
  14. modal/_runtime/container_io_manager.py +1025 -0
  15. modal/{execution_context.py → _runtime/execution_context.py} +11 -2
  16. modal/_runtime/telemetry.py +169 -0
  17. modal/_runtime/user_code_imports.py +356 -0
  18. modal/_serialization.py +123 -6
  19. modal/_traceback.py +47 -187
  20. modal/_tunnel.py +50 -14
  21. modal/_tunnel.pyi +19 -36
  22. modal/_utils/app_utils.py +3 -17
  23. modal/_utils/async_utils.py +386 -104
  24. modal/_utils/blob_utils.py +157 -186
  25. modal/_utils/bytes_io_segment_payload.py +97 -0
  26. modal/_utils/deprecation.py +89 -0
  27. modal/_utils/docker_utils.py +98 -0
  28. modal/_utils/function_utils.py +299 -98
  29. modal/_utils/grpc_testing.py +47 -34
  30. modal/_utils/grpc_utils.py +54 -21
  31. modal/_utils/hash_utils.py +51 -10
  32. modal/_utils/http_utils.py +39 -9
  33. modal/_utils/logger.py +2 -1
  34. modal/_utils/mount_utils.py +34 -16
  35. modal/_utils/name_utils.py +58 -0
  36. modal/_utils/package_utils.py +14 -1
  37. modal/_utils/pattern_utils.py +205 -0
  38. modal/_utils/rand_pb_testing.py +3 -3
  39. modal/_utils/shell_utils.py +15 -49
  40. modal/_vendor/a2wsgi_wsgi.py +62 -72
  41. modal/_vendor/cloudpickle.py +1 -1
  42. modal/_watcher.py +12 -10
  43. modal/app.py +561 -323
  44. modal/app.pyi +474 -262
  45. modal/call_graph.py +7 -6
  46. modal/cli/_download.py +22 -6
  47. modal/cli/_traceback.py +200 -0
  48. modal/cli/app.py +203 -42
  49. modal/cli/config.py +12 -5
  50. modal/cli/container.py +61 -13
  51. modal/cli/dict.py +128 -0
  52. modal/cli/entry_point.py +26 -13
  53. modal/cli/environment.py +40 -9
  54. modal/cli/import_refs.py +21 -48
  55. modal/cli/launch.py +28 -14
  56. modal/cli/network_file_system.py +57 -21
  57. modal/cli/profile.py +1 -1
  58. modal/cli/programs/run_jupyter.py +34 -9
  59. modal/cli/programs/vscode.py +58 -8
  60. modal/cli/queues.py +131 -0
  61. modal/cli/run.py +199 -96
  62. modal/cli/secret.py +5 -4
  63. modal/cli/token.py +7 -2
  64. modal/cli/utils.py +74 -8
  65. modal/cli/volume.py +97 -56
  66. modal/client.py +248 -144
  67. modal/client.pyi +156 -124
  68. modal/cloud_bucket_mount.py +43 -30
  69. modal/cloud_bucket_mount.pyi +32 -25
  70. modal/cls.py +528 -141
  71. modal/cls.pyi +189 -145
  72. modal/config.py +32 -15
  73. modal/container_process.py +177 -0
  74. modal/container_process.pyi +82 -0
  75. modal/dict.py +50 -54
  76. modal/dict.pyi +120 -164
  77. modal/environments.py +106 -5
  78. modal/environments.pyi +77 -25
  79. modal/exception.py +30 -43
  80. modal/experimental.py +62 -2
  81. modal/file_io.py +537 -0
  82. modal/file_io.pyi +235 -0
  83. modal/file_pattern_matcher.py +196 -0
  84. modal/functions.py +846 -428
  85. modal/functions.pyi +446 -387
  86. modal/gpu.py +57 -44
  87. modal/image.py +943 -417
  88. modal/image.pyi +584 -245
  89. modal/io_streams.py +434 -0
  90. modal/io_streams.pyi +122 -0
  91. modal/mount.py +223 -90
  92. modal/mount.pyi +241 -243
  93. modal/network_file_system.py +85 -86
  94. modal/network_file_system.pyi +151 -110
  95. modal/object.py +66 -36
  96. modal/object.pyi +166 -143
  97. modal/output.py +63 -0
  98. modal/parallel_map.py +73 -47
  99. modal/parallel_map.pyi +51 -63
  100. modal/partial_function.py +272 -107
  101. modal/partial_function.pyi +219 -120
  102. modal/proxy.py +15 -12
  103. modal/proxy.pyi +3 -8
  104. modal/queue.py +96 -72
  105. modal/queue.pyi +210 -135
  106. modal/requirements/2024.04.txt +2 -1
  107. modal/requirements/2024.10.txt +16 -0
  108. modal/requirements/README.md +21 -0
  109. modal/requirements/base-images.json +22 -0
  110. modal/retries.py +45 -4
  111. modal/runner.py +325 -203
  112. modal/runner.pyi +124 -110
  113. modal/running_app.py +27 -4
  114. modal/sandbox.py +509 -231
  115. modal/sandbox.pyi +396 -169
  116. modal/schedule.py +2 -2
  117. modal/scheduler_placement.py +20 -3
  118. modal/secret.py +41 -25
  119. modal/secret.pyi +62 -42
  120. modal/serving.py +39 -49
  121. modal/serving.pyi +37 -43
  122. modal/stream_type.py +15 -0
  123. modal/token_flow.py +5 -3
  124. modal/token_flow.pyi +37 -32
  125. modal/volume.py +123 -137
  126. modal/volume.pyi +228 -221
  127. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/METADATA +5 -5
  128. modal-0.72.13.dist-info/RECORD +174 -0
  129. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/top_level.txt +0 -1
  130. modal_docs/gen_reference_docs.py +3 -1
  131. modal_docs/mdmd/mdmd.py +0 -1
  132. modal_docs/mdmd/signatures.py +1 -2
  133. modal_global_objects/images/base_images.py +28 -0
  134. modal_global_objects/mounts/python_standalone.py +2 -2
  135. modal_proto/__init__.py +1 -1
  136. modal_proto/api.proto +1231 -531
  137. modal_proto/api_grpc.py +750 -430
  138. modal_proto/api_pb2.py +2102 -1176
  139. modal_proto/api_pb2.pyi +8859 -0
  140. modal_proto/api_pb2_grpc.py +1329 -675
  141. modal_proto/api_pb2_grpc.pyi +1416 -0
  142. modal_proto/modal_api_grpc.py +149 -0
  143. modal_proto/modal_options_grpc.py +3 -0
  144. modal_proto/options_pb2.pyi +20 -0
  145. modal_proto/options_pb2_grpc.pyi +7 -0
  146. modal_proto/py.typed +0 -0
  147. modal_version/__init__.py +1 -1
  148. modal_version/_version_generated.py +2 -2
  149. modal/_asgi.py +0 -370
  150. modal/_container_exec.py +0 -128
  151. modal/_container_io_manager.py +0 -646
  152. modal/_container_io_manager.pyi +0 -412
  153. modal/_sandbox_shell.py +0 -49
  154. modal/app_utils.py +0 -20
  155. modal/app_utils.pyi +0 -17
  156. modal/execution_context.pyi +0 -37
  157. modal/shared_volume.py +0 -23
  158. modal/shared_volume.pyi +0 -24
  159. modal-0.62.115.dist-info/RECORD +0 -207
  160. modal_global_objects/images/conda.py +0 -15
  161. modal_global_objects/images/debian_slim.py +0 -15
  162. modal_global_objects/images/micromamba.py +0 -15
  163. test/__init__.py +0 -1
  164. test/aio_test.py +0 -12
  165. test/async_utils_test.py +0 -279
  166. test/blob_test.py +0 -67
  167. test/cli_imports_test.py +0 -149
  168. test/cli_test.py +0 -674
  169. test/client_test.py +0 -203
  170. test/cloud_bucket_mount_test.py +0 -22
  171. test/cls_test.py +0 -636
  172. test/config_test.py +0 -149
  173. test/conftest.py +0 -1485
  174. test/container_app_test.py +0 -50
  175. test/container_test.py +0 -1405
  176. test/cpu_test.py +0 -23
  177. test/decorator_test.py +0 -85
  178. test/deprecation_test.py +0 -34
  179. test/dict_test.py +0 -51
  180. test/e2e_test.py +0 -68
  181. test/error_test.py +0 -7
  182. test/function_serialization_test.py +0 -32
  183. test/function_test.py +0 -791
  184. test/function_utils_test.py +0 -101
  185. test/gpu_test.py +0 -159
  186. test/grpc_utils_test.py +0 -82
  187. test/helpers.py +0 -47
  188. test/image_test.py +0 -814
  189. test/live_reload_test.py +0 -80
  190. test/lookup_test.py +0 -70
  191. test/mdmd_test.py +0 -329
  192. test/mount_test.py +0 -162
  193. test/mounted_files_test.py +0 -327
  194. test/network_file_system_test.py +0 -188
  195. test/notebook_test.py +0 -66
  196. test/object_test.py +0 -41
  197. test/package_utils_test.py +0 -25
  198. test/queue_test.py +0 -115
  199. test/resolver_test.py +0 -59
  200. test/retries_test.py +0 -67
  201. test/runner_test.py +0 -85
  202. test/sandbox_test.py +0 -191
  203. test/schedule_test.py +0 -15
  204. test/scheduler_placement_test.py +0 -57
  205. test/secret_test.py +0 -89
  206. test/serialization_test.py +0 -50
  207. test/stub_composition_test.py +0 -10
  208. test/stub_test.py +0 -361
  209. test/test_asgi_wrapper.py +0 -234
  210. test/token_flow_test.py +0 -18
  211. test/traceback_test.py +0 -135
  212. test/tunnel_test.py +0 -29
  213. test/utils_test.py +0 -88
  214. test/version_test.py +0 -14
  215. test/volume_test.py +0 -397
  216. test/watcher_test.py +0 -58
  217. test/webhook_test.py +0 -145
  218. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/LICENSE +0 -0
  219. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/WHEEL +0 -0
  220. {modal-0.62.115.dist-info → modal-0.72.13.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,82 @@
1
+ import modal.client
2
+ import modal.io_streams
3
+ import modal.stream_type
4
+ import typing
5
+ import typing_extensions
6
+
7
+ T = typing.TypeVar("T")
8
+
9
+ class _ContainerProcess(typing.Generic[T]):
10
+ _process_id: typing.Optional[str]
11
+ _stdout: modal.io_streams._StreamReader[T]
12
+ _stderr: modal.io_streams._StreamReader[T]
13
+ _stdin: modal.io_streams._StreamWriter
14
+ _text: bool
15
+ _by_line: bool
16
+ _returncode: typing.Optional[int]
17
+
18
+ def __init__(
19
+ self,
20
+ process_id: str,
21
+ client: modal.client._Client,
22
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
23
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
24
+ text: bool = True,
25
+ by_line: bool = False,
26
+ ) -> None: ...
27
+ @property
28
+ def stdout(self) -> modal.io_streams._StreamReader[T]: ...
29
+ @property
30
+ def stderr(self) -> modal.io_streams._StreamReader[T]: ...
31
+ @property
32
+ def stdin(self) -> modal.io_streams._StreamWriter: ...
33
+ @property
34
+ def returncode(self) -> int: ...
35
+ async def poll(self) -> typing.Optional[int]: ...
36
+ async def wait(self) -> int: ...
37
+ async def attach(self, *, pty: typing.Optional[bool] = None): ...
38
+
39
+ class ContainerProcess(typing.Generic[T]):
40
+ _process_id: typing.Optional[str]
41
+ _stdout: modal.io_streams.StreamReader[T]
42
+ _stderr: modal.io_streams.StreamReader[T]
43
+ _stdin: modal.io_streams.StreamWriter
44
+ _text: bool
45
+ _by_line: bool
46
+ _returncode: typing.Optional[int]
47
+
48
+ def __init__(
49
+ self,
50
+ process_id: str,
51
+ client: modal.client.Client,
52
+ stdout: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
53
+ stderr: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
54
+ text: bool = True,
55
+ by_line: bool = False,
56
+ ) -> None: ...
57
+ @property
58
+ def stdout(self) -> modal.io_streams.StreamReader[T]: ...
59
+ @property
60
+ def stderr(self) -> modal.io_streams.StreamReader[T]: ...
61
+ @property
62
+ def stdin(self) -> modal.io_streams.StreamWriter: ...
63
+ @property
64
+ def returncode(self) -> int: ...
65
+
66
+ class __poll_spec(typing_extensions.Protocol):
67
+ def __call__(self) -> typing.Optional[int]: ...
68
+ async def aio(self) -> typing.Optional[int]: ...
69
+
70
+ poll: __poll_spec
71
+
72
+ class __wait_spec(typing_extensions.Protocol):
73
+ def __call__(self) -> int: ...
74
+ async def aio(self) -> int: ...
75
+
76
+ wait: __wait_spec
77
+
78
+ class __attach_spec(typing_extensions.Protocol):
79
+ def __call__(self, *, pty: typing.Optional[bool] = None): ...
80
+ async def aio(self, *, pty: typing.Optional[bool] = None): ...
81
+
82
+ attach: __attach_spec
modal/dict.py CHANGED
@@ -1,6 +1,8 @@
1
1
  # Copyright Modal Labs 2022
2
- from typing import Any, AsyncIterator, Optional, Tuple, Type
2
+ from collections.abc import AsyncIterator
3
+ from typing import Any, Optional
3
4
 
5
+ from grpclib import GRPCError
4
6
  from synchronicity.async_wrap import asynccontextmanager
5
7
 
6
8
  from modal_proto import api_pb2
@@ -8,10 +10,12 @@ from modal_proto import api_pb2
8
10
  from ._resolver import Resolver
9
11
  from ._serialization import deserialize, serialize
10
12
  from ._utils.async_utils import TaskContext, synchronize_api
11
- from ._utils.grpc_utils import retry_transient_errors, unary_stream
13
+ from ._utils.deprecation import renamed_parameter
14
+ from ._utils.grpc_utils import retry_transient_errors
15
+ from ._utils.name_utils import check_object_name
12
16
  from .client import _Client
13
17
  from .config import logger
14
- from .exception import deprecation_warning
18
+ from .exception import RequestSizeError
15
19
  from .object import EPHEMERAL_OBJECT_HEARTBEAT_SLEEP, _get_environment_name, _Object, live_method, live_method_gen
16
20
 
17
21
 
@@ -54,25 +58,6 @@ class _Dict(_Object, type_prefix="di"):
54
58
  For more examples, see the [guide](/docs/guide/dicts-and-queues#modal-dicts).
55
59
  """
56
60
 
57
- @staticmethod
58
- def new(data: Optional[dict] = None) -> "_Dict":
59
- """`Dict.new` is deprecated.
60
-
61
- Please use `Dict.from_name` (for persisted) or `Dict.ephemeral` (for ephemeral) dicts.
62
- """
63
- deprecation_warning((2024, 3, 19), Dict.new.__doc__)
64
-
65
- async def _load(self: _Dict, resolver: Resolver, existing_object_id: Optional[str]):
66
- serialized = _serialize_dict(data if data is not None else {})
67
- req = api_pb2.DictCreateRequest(
68
- app_id=resolver.app_id, data=serialized, existing_dict_id=existing_object_id
69
- )
70
- response = await resolver.client.stub.DictCreate(req)
71
- logger.debug(f"Created dict with id {response.dict_id}")
72
- self._hydrate(response.dict_id, resolver.client, None)
73
-
74
- return _Dict._from_loader(_load, "Dict()")
75
-
76
61
  def __init__(self, data={}):
77
62
  """mdmd:hidden"""
78
63
  raise RuntimeError(
@@ -82,7 +67,7 @@ class _Dict(_Object, type_prefix="di"):
82
67
  @classmethod
83
68
  @asynccontextmanager
84
69
  async def ephemeral(
85
- cls: Type["_Dict"],
70
+ cls: type["_Dict"],
86
71
  data: Optional[dict] = None,
87
72
  client: Optional[_Client] = None,
88
73
  environment_name: Optional[str] = None,
@@ -96,7 +81,9 @@ class _Dict(_Object, type_prefix="di"):
96
81
 
97
82
  with Dict.ephemeral() as d:
98
83
  d["foo"] = "bar"
84
+ ```
99
85
 
86
+ ```python notest
100
87
  async with Dict.ephemeral() as d:
101
88
  await d.put.aio("foo", "bar")
102
89
  ```
@@ -109,36 +96,38 @@ class _Dict(_Object, type_prefix="di"):
109
96
  environment_name=_get_environment_name(environment_name),
110
97
  data=serialized,
111
98
  )
112
- response = await client.stub.DictGetOrCreate(request)
99
+ response = await retry_transient_errors(client.stub.DictGetOrCreate, request, total_timeout=10.0)
113
100
  async with TaskContext() as tc:
114
101
  request = api_pb2.DictHeartbeatRequest(dict_id=response.dict_id)
115
102
  tc.infinite_loop(lambda: client.stub.DictHeartbeat(request), sleep=_heartbeat_sleep)
116
103
  yield cls._new_hydrated(response.dict_id, client, None, is_another_app=True)
117
104
 
118
105
  @staticmethod
106
+ @renamed_parameter((2024, 12, 18), "label", "name")
119
107
  def from_name(
120
- label: str,
108
+ name: str,
121
109
  data: Optional[dict] = None,
122
110
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
123
111
  environment_name: Optional[str] = None,
124
112
  create_if_missing: bool = False,
125
113
  ) -> "_Dict":
126
- """Create a reference to a persisted Dict
114
+ """Reference a named Dict, creating if necessary.
127
115
 
128
- **Examples**
116
+ In contrast to `modal.Dict.lookup`, this is a lazy method
117
+ that defers hydrating the local object with metadata from
118
+ Modal servers until the first time it is actually used.
129
119
 
130
120
  ```python
131
- from modal import Dict
132
-
133
- dict = Dict.from_name("my-dict", create_if_missing=True)
134
- dict[123] = 456
121
+ d = modal.Dict.from_name("my-dict", create_if_missing=True)
122
+ d[123] = 456
135
123
  ```
136
124
  """
125
+ check_object_name(name, "Dict")
137
126
 
138
127
  async def _load(self: _Dict, resolver: Resolver, existing_object_id: Optional[str]):
139
128
  serialized = _serialize_dict(data if data is not None else {})
140
129
  req = api_pb2.DictGetOrCreateRequest(
141
- deployment_name=label,
130
+ deployment_name=name,
142
131
  namespace=namespace,
143
132
  environment_name=_get_environment_name(environment_name, resolver),
144
133
  object_creation_type=(api_pb2.OBJECT_CREATION_TYPE_CREATE_IF_MISSING if create_if_missing else None),
@@ -151,33 +140,27 @@ class _Dict(_Object, type_prefix="di"):
151
140
  return _Dict._from_loader(_load, "Dict()", is_another_app=True, hydrate_lazily=True)
152
141
 
153
142
  @staticmethod
154
- def persisted(
155
- label: str, namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE, environment_name: Optional[str] = None
156
- ) -> "_Dict":
157
- """Deprecated! Use `Dict.from_name(name, create_if_missing=True)`."""
158
- deprecation_warning((2024, 3, 1), _Dict.persisted.__doc__)
159
- return _Dict.from_name(label, namespace, environment_name, create_if_missing=True)
160
-
161
- @staticmethod
143
+ @renamed_parameter((2024, 12, 18), "label", "name")
162
144
  async def lookup(
163
- label: str,
145
+ name: str,
164
146
  data: Optional[dict] = None,
165
147
  namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
166
148
  client: Optional[_Client] = None,
167
149
  environment_name: Optional[str] = None,
168
150
  create_if_missing: bool = False,
169
151
  ) -> "_Dict":
170
- """Lookup a dict with a given name and tag.
152
+ """Lookup a named Dict.
171
153
 
172
- ```python
173
- from modal import Dict
154
+ In contrast to `modal.Dict.from_name`, this is an eager method
155
+ that will hydrate the local object with metadata from Modal servers.
174
156
 
175
- d = Dict.lookup("my-dict")
157
+ ```python
158
+ d = modal.Dict.lookup("my-dict")
176
159
  d["xyz"] = 123
177
160
  ```
178
161
  """
179
162
  obj = _Dict.from_name(
180
- label,
163
+ name,
181
164
  data=data,
182
165
  namespace=namespace,
183
166
  environment_name=environment_name,
@@ -190,13 +173,14 @@ class _Dict(_Object, type_prefix="di"):
190
173
  return obj
191
174
 
192
175
  @staticmethod
176
+ @renamed_parameter((2024, 12, 18), "label", "name")
193
177
  async def delete(
194
- label: str,
178
+ name: str,
195
179
  *,
196
180
  client: Optional[_Client] = None,
197
181
  environment_name: Optional[str] = None,
198
182
  ):
199
- obj = await _Dict.lookup(label, client=client, environment_name=environment_name)
183
+ obj = await _Dict.lookup(name, client=client, environment_name=environment_name)
200
184
  req = api_pb2.DictDeleteRequest(dict_id=obj.object_id)
201
185
  await retry_transient_errors(obj._client.stub.DictDelete, req)
202
186
 
@@ -250,7 +234,13 @@ class _Dict(_Object, type_prefix="di"):
250
234
  """Update the dictionary with additional items."""
251
235
  serialized = _serialize_dict(kwargs)
252
236
  req = api_pb2.DictUpdateRequest(dict_id=self.object_id, updates=serialized)
253
- await retry_transient_errors(self._client.stub.DictUpdate, req)
237
+ try:
238
+ await retry_transient_errors(self._client.stub.DictUpdate, req)
239
+ except GRPCError as exc:
240
+ if "status = '413'" in exc.message:
241
+ raise RequestSizeError("Dict.update request is too large") from exc
242
+ else:
243
+ raise exc
254
244
 
255
245
  @live_method
256
246
  async def put(self, key: Any, value: Any) -> None:
@@ -258,7 +248,13 @@ class _Dict(_Object, type_prefix="di"):
258
248
  updates = {key: value}
259
249
  serialized = _serialize_dict(updates)
260
250
  req = api_pb2.DictUpdateRequest(dict_id=self.object_id, updates=serialized)
261
- await retry_transient_errors(self._client.stub.DictUpdate, req)
251
+ try:
252
+ await retry_transient_errors(self._client.stub.DictUpdate, req)
253
+ except GRPCError as exc:
254
+ if "status = '413'" in exc.message:
255
+ raise RequestSizeError("Dict.put request is too large") from exc
256
+ else:
257
+ raise exc
262
258
 
263
259
  @live_method
264
260
  async def __setitem__(self, key: Any, value: Any) -> None:
@@ -301,7 +297,7 @@ class _Dict(_Object, type_prefix="di"):
301
297
  and results are unordered.
302
298
  """
303
299
  req = api_pb2.DictContentsRequest(dict_id=self.object_id, keys=True)
304
- async for resp in unary_stream(self._client.stub.DictContents, req):
300
+ async for resp in self._client.stub.DictContents.unary_stream(req):
305
301
  yield deserialize(resp.key, self._client)
306
302
 
307
303
  @live_method_gen
@@ -312,18 +308,18 @@ class _Dict(_Object, type_prefix="di"):
312
308
  and results are unordered.
313
309
  """
314
310
  req = api_pb2.DictContentsRequest(dict_id=self.object_id, values=True)
315
- async for resp in unary_stream(self._client.stub.DictContents, req):
311
+ async for resp in self._client.stub.DictContents.unary_stream(req):
316
312
  yield deserialize(resp.value, self._client)
317
313
 
318
314
  @live_method_gen
319
- async def items(self) -> AsyncIterator[Tuple[Any, Any]]:
315
+ async def items(self) -> AsyncIterator[tuple[Any, Any]]:
320
316
  """Return an iterator over the (key, value) tuples in this dictionary.
321
317
 
322
318
  Note that (unlike with Python dicts) the return value is a simple iterator,
323
319
  and results are unordered.
324
320
  """
325
321
  req = api_pb2.DictContentsRequest(dict_id=self.object_id, keys=True, values=True)
326
- async for resp in unary_stream(self._client.stub.DictContents, req):
322
+ async for resp in self._client.stub.DictContents.unary_stream(req):
327
323
  yield (deserialize(resp.key, self._client), deserialize(resp.value, self._client))
328
324
 
329
325
 
modal/dict.pyi CHANGED
@@ -1,244 +1,200 @@
1
+ import collections.abc
1
2
  import modal.client
2
3
  import modal.object
3
4
  import synchronicity.combined_types
4
5
  import typing
5
6
  import typing_extensions
6
7
 
7
- def _serialize_dict(data):
8
- ...
9
-
8
+ def _serialize_dict(data): ...
10
9
 
11
10
  class _Dict(modal.object._Object):
12
- @staticmethod
13
- def new(data: typing.Union[dict, None] = None) -> _Dict:
14
- ...
15
-
16
- def __init__(self, data={}):
17
- ...
18
-
11
+ def __init__(self, data={}): ...
19
12
  @classmethod
20
- def ephemeral(cls: typing.Type[_Dict], data: typing.Union[dict, None] = None, client: typing.Union[modal.client._Client, None] = None, environment_name: typing.Union[str, None] = None, _heartbeat_sleep: float = 300) -> typing.AsyncContextManager[_Dict]:
21
- ...
22
-
23
- @staticmethod
24
- def from_name(label: str, data: typing.Union[dict, None] = None, namespace=1, environment_name: typing.Union[str, None] = None, create_if_missing: bool = False) -> _Dict:
25
- ...
26
-
13
+ def ephemeral(
14
+ cls: type[_Dict],
15
+ data: typing.Optional[dict] = None,
16
+ client: typing.Optional[modal.client._Client] = None,
17
+ environment_name: typing.Optional[str] = None,
18
+ _heartbeat_sleep: float = 300,
19
+ ) -> typing.AsyncContextManager[_Dict]: ...
27
20
  @staticmethod
28
- def persisted(label: str, namespace=1, environment_name: typing.Union[str, None] = None) -> _Dict:
29
- ...
30
-
21
+ def from_name(
22
+ name: str,
23
+ data: typing.Optional[dict] = None,
24
+ namespace=1,
25
+ environment_name: typing.Optional[str] = None,
26
+ create_if_missing: bool = False,
27
+ ) -> _Dict: ...
31
28
  @staticmethod
32
- async def lookup(label: str, data: typing.Union[dict, None] = None, namespace=1, client: typing.Union[modal.client._Client, None] = None, environment_name: typing.Union[str, None] = None, create_if_missing: bool = False) -> _Dict:
33
- ...
34
-
29
+ async def lookup(
30
+ name: str,
31
+ data: typing.Optional[dict] = None,
32
+ namespace=1,
33
+ client: typing.Optional[modal.client._Client] = None,
34
+ environment_name: typing.Optional[str] = None,
35
+ create_if_missing: bool = False,
36
+ ) -> _Dict: ...
35
37
  @staticmethod
36
- async def delete(label: str, *, client: typing.Union[modal.client._Client, None] = None, environment_name: typing.Union[str, None] = None):
37
- ...
38
-
39
- async def clear(self) -> None:
40
- ...
41
-
42
- async def get(self, key: typing.Any, default: typing.Union[typing.Any, None] = None) -> typing.Any:
43
- ...
44
-
45
- async def contains(self, key: typing.Any) -> bool:
46
- ...
47
-
48
- async def len(self) -> int:
49
- ...
50
-
51
- async def __getitem__(self, key: typing.Any) -> typing.Any:
52
- ...
53
-
54
- async def update(self, **kwargs) -> None:
55
- ...
56
-
57
- async def put(self, key: typing.Any, value: typing.Any) -> None:
58
- ...
59
-
60
- async def __setitem__(self, key: typing.Any, value: typing.Any) -> None:
61
- ...
62
-
63
- async def pop(self, key: typing.Any) -> typing.Any:
64
- ...
65
-
66
- async def __delitem__(self, key: typing.Any) -> typing.Any:
67
- ...
68
-
69
- async def __contains__(self, key: typing.Any) -> bool:
70
- ...
71
-
72
- def keys(self) -> typing.AsyncIterator[typing.Any]:
73
- ...
74
-
75
- def values(self) -> typing.AsyncIterator[typing.Any]:
76
- ...
77
-
78
- def items(self) -> typing.AsyncIterator[typing.Tuple[typing.Any, typing.Any]]:
79
- ...
80
-
38
+ async def delete(
39
+ name: str,
40
+ *,
41
+ client: typing.Optional[modal.client._Client] = None,
42
+ environment_name: typing.Optional[str] = None,
43
+ ): ...
44
+ async def clear(self) -> None: ...
45
+ async def get(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
46
+ async def contains(self, key: typing.Any) -> bool: ...
47
+ async def len(self) -> int: ...
48
+ async def __getitem__(self, key: typing.Any) -> typing.Any: ...
49
+ async def update(self, **kwargs) -> None: ...
50
+ async def put(self, key: typing.Any, value: typing.Any) -> None: ...
51
+ async def __setitem__(self, key: typing.Any, value: typing.Any) -> None: ...
52
+ async def pop(self, key: typing.Any) -> typing.Any: ...
53
+ async def __delitem__(self, key: typing.Any) -> typing.Any: ...
54
+ async def __contains__(self, key: typing.Any) -> bool: ...
55
+ def keys(self) -> collections.abc.AsyncIterator[typing.Any]: ...
56
+ def values(self) -> collections.abc.AsyncIterator[typing.Any]: ...
57
+ def items(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
81
58
 
82
59
  class Dict(modal.object.Object):
83
- def __init__(self, data={}):
84
- ...
85
-
86
- @staticmethod
87
- def new(data: typing.Union[dict, None] = None) -> Dict:
88
- ...
89
-
60
+ def __init__(self, data={}): ...
90
61
  @classmethod
91
- def ephemeral(cls: typing.Type[Dict], data: typing.Union[dict, None] = None, client: typing.Union[modal.client.Client, None] = None, environment_name: typing.Union[str, None] = None, _heartbeat_sleep: float = 300) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Dict]:
92
- ...
93
-
94
- @staticmethod
95
- def from_name(label: str, data: typing.Union[dict, None] = None, namespace=1, environment_name: typing.Union[str, None] = None, create_if_missing: bool = False) -> Dict:
96
- ...
97
-
62
+ def ephemeral(
63
+ cls: type[Dict],
64
+ data: typing.Optional[dict] = None,
65
+ client: typing.Optional[modal.client.Client] = None,
66
+ environment_name: typing.Optional[str] = None,
67
+ _heartbeat_sleep: float = 300,
68
+ ) -> synchronicity.combined_types.AsyncAndBlockingContextManager[Dict]: ...
98
69
  @staticmethod
99
- def persisted(label: str, namespace=1, environment_name: typing.Union[str, None] = None) -> Dict:
100
- ...
70
+ def from_name(
71
+ name: str,
72
+ data: typing.Optional[dict] = None,
73
+ namespace=1,
74
+ environment_name: typing.Optional[str] = None,
75
+ create_if_missing: bool = False,
76
+ ) -> Dict: ...
101
77
 
102
78
  class __lookup_spec(typing_extensions.Protocol):
103
- def __call__(self, label: str, data: typing.Union[dict, None] = None, namespace=1, client: typing.Union[modal.client.Client, None] = None, environment_name: typing.Union[str, None] = None, create_if_missing: bool = False) -> Dict:
104
- ...
105
-
106
- async def aio(self, *args, **kwargs) -> Dict:
107
- ...
79
+ def __call__(
80
+ self,
81
+ name: str,
82
+ data: typing.Optional[dict] = None,
83
+ namespace=1,
84
+ client: typing.Optional[modal.client.Client] = None,
85
+ environment_name: typing.Optional[str] = None,
86
+ create_if_missing: bool = False,
87
+ ) -> Dict: ...
88
+ async def aio(
89
+ self,
90
+ name: str,
91
+ data: typing.Optional[dict] = None,
92
+ namespace=1,
93
+ client: typing.Optional[modal.client.Client] = None,
94
+ environment_name: typing.Optional[str] = None,
95
+ create_if_missing: bool = False,
96
+ ) -> Dict: ...
108
97
 
109
98
  lookup: __lookup_spec
110
99
 
111
100
  class __delete_spec(typing_extensions.Protocol):
112
- def __call__(self, label: str, *, client: typing.Union[modal.client.Client, None] = None, environment_name: typing.Union[str, None] = None):
113
- ...
114
-
115
- async def aio(self, *args, **kwargs):
116
- ...
101
+ def __call__(
102
+ self,
103
+ name: str,
104
+ *,
105
+ client: typing.Optional[modal.client.Client] = None,
106
+ environment_name: typing.Optional[str] = None,
107
+ ): ...
108
+ async def aio(
109
+ self,
110
+ name: str,
111
+ *,
112
+ client: typing.Optional[modal.client.Client] = None,
113
+ environment_name: typing.Optional[str] = None,
114
+ ): ...
117
115
 
118
116
  delete: __delete_spec
119
117
 
120
118
  class __clear_spec(typing_extensions.Protocol):
121
- def __call__(self) -> None:
122
- ...
123
-
124
- async def aio(self, *args, **kwargs) -> None:
125
- ...
119
+ def __call__(self) -> None: ...
120
+ async def aio(self) -> None: ...
126
121
 
127
122
  clear: __clear_spec
128
123
 
129
124
  class __get_spec(typing_extensions.Protocol):
130
- def __call__(self, key: typing.Any, default: typing.Union[typing.Any, None] = None) -> typing.Any:
131
- ...
132
-
133
- async def aio(self, *args, **kwargs) -> typing.Any:
134
- ...
125
+ def __call__(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
126
+ async def aio(self, key: typing.Any, default: typing.Optional[typing.Any] = None) -> typing.Any: ...
135
127
 
136
128
  get: __get_spec
137
129
 
138
130
  class __contains_spec(typing_extensions.Protocol):
139
- def __call__(self, key: typing.Any) -> bool:
140
- ...
141
-
142
- async def aio(self, *args, **kwargs) -> bool:
143
- ...
131
+ def __call__(self, key: typing.Any) -> bool: ...
132
+ async def aio(self, key: typing.Any) -> bool: ...
144
133
 
145
134
  contains: __contains_spec
146
135
 
147
136
  class __len_spec(typing_extensions.Protocol):
148
- def __call__(self) -> int:
149
- ...
150
-
151
- async def aio(self, *args, **kwargs) -> int:
152
- ...
137
+ def __call__(self) -> int: ...
138
+ async def aio(self) -> int: ...
153
139
 
154
140
  len: __len_spec
155
141
 
156
142
  class ____getitem___spec(typing_extensions.Protocol):
157
- def __call__(self, key: typing.Any) -> typing.Any:
158
- ...
159
-
160
- async def aio(self, *args, **kwargs) -> typing.Any:
161
- ...
143
+ def __call__(self, key: typing.Any) -> typing.Any: ...
144
+ async def aio(self, key: typing.Any) -> typing.Any: ...
162
145
 
163
146
  __getitem__: ____getitem___spec
164
147
 
165
148
  class __update_spec(typing_extensions.Protocol):
166
- def __call__(self, **kwargs) -> None:
167
- ...
168
-
169
- async def aio(self, *args, **kwargs) -> None:
170
- ...
149
+ def __call__(self, **kwargs) -> None: ...
150
+ async def aio(self, **kwargs) -> None: ...
171
151
 
172
152
  update: __update_spec
173
153
 
174
154
  class __put_spec(typing_extensions.Protocol):
175
- def __call__(self, key: typing.Any, value: typing.Any) -> None:
176
- ...
177
-
178
- async def aio(self, *args, **kwargs) -> None:
179
- ...
155
+ def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
156
+ async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
180
157
 
181
158
  put: __put_spec
182
159
 
183
160
  class ____setitem___spec(typing_extensions.Protocol):
184
- def __call__(self, key: typing.Any, value: typing.Any) -> None:
185
- ...
186
-
187
- async def aio(self, *args, **kwargs) -> None:
188
- ...
161
+ def __call__(self, key: typing.Any, value: typing.Any) -> None: ...
162
+ async def aio(self, key: typing.Any, value: typing.Any) -> None: ...
189
163
 
190
164
  __setitem__: ____setitem___spec
191
165
 
192
166
  class __pop_spec(typing_extensions.Protocol):
193
- def __call__(self, key: typing.Any) -> typing.Any:
194
- ...
195
-
196
- async def aio(self, *args, **kwargs) -> typing.Any:
197
- ...
167
+ def __call__(self, key: typing.Any) -> typing.Any: ...
168
+ async def aio(self, key: typing.Any) -> typing.Any: ...
198
169
 
199
170
  pop: __pop_spec
200
171
 
201
172
  class ____delitem___spec(typing_extensions.Protocol):
202
- def __call__(self, key: typing.Any) -> typing.Any:
203
- ...
204
-
205
- async def aio(self, *args, **kwargs) -> typing.Any:
206
- ...
173
+ def __call__(self, key: typing.Any) -> typing.Any: ...
174
+ async def aio(self, key: typing.Any) -> typing.Any: ...
207
175
 
208
176
  __delitem__: ____delitem___spec
209
177
 
210
178
  class ____contains___spec(typing_extensions.Protocol):
211
- def __call__(self, key: typing.Any) -> bool:
212
- ...
213
-
214
- async def aio(self, *args, **kwargs) -> bool:
215
- ...
179
+ def __call__(self, key: typing.Any) -> bool: ...
180
+ async def aio(self, key: typing.Any) -> bool: ...
216
181
 
217
182
  __contains__: ____contains___spec
218
183
 
219
184
  class __keys_spec(typing_extensions.Protocol):
220
- def __call__(self) -> typing.Iterator[typing.Any]:
221
- ...
222
-
223
- def aio(self) -> typing.AsyncIterator[typing.Any]:
224
- ...
185
+ def __call__(self) -> typing.Iterator[typing.Any]: ...
186
+ def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
225
187
 
226
188
  keys: __keys_spec
227
189
 
228
190
  class __values_spec(typing_extensions.Protocol):
229
- def __call__(self) -> typing.Iterator[typing.Any]:
230
- ...
231
-
232
- def aio(self) -> typing.AsyncIterator[typing.Any]:
233
- ...
191
+ def __call__(self) -> typing.Iterator[typing.Any]: ...
192
+ def aio(self) -> collections.abc.AsyncIterator[typing.Any]: ...
234
193
 
235
194
  values: __values_spec
236
195
 
237
196
  class __items_spec(typing_extensions.Protocol):
238
- def __call__(self) -> typing.Iterator[typing.Tuple[typing.Any, typing.Any]]:
239
- ...
240
-
241
- def aio(self) -> typing.AsyncIterator[typing.Tuple[typing.Any, typing.Any]]:
242
- ...
197
+ def __call__(self) -> typing.Iterator[tuple[typing.Any, typing.Any]]: ...
198
+ def aio(self) -> collections.abc.AsyncIterator[tuple[typing.Any, typing.Any]]: ...
243
199
 
244
200
  items: __items_spec