modal 0.67.1__py3-none-any.whl → 0.67.33__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 (113) hide show
  1. modal/_clustered_functions.py +2 -2
  2. modal/_clustered_functions.pyi +2 -2
  3. modal/_container_entrypoint.py +8 -5
  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 +46 -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 +5 -4
  16. modal/_tunnel.pyi +2 -2
  17. modal/_utils/async_utils.py +53 -17
  18. modal/_utils/blob_utils.py +22 -7
  19. modal/_utils/function_utils.py +20 -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 +68 -62
  32. modal/app.pyi +104 -99
  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/import_refs.py +1 -1
  41. modal/cli/launch.py +2 -2
  42. modal/cli/network_file_system.py +1 -1
  43. modal/cli/profile.py +1 -1
  44. modal/cli/programs/run_jupyter.py +2 -2
  45. modal/cli/programs/vscode.py +3 -3
  46. modal/cli/queues.py +1 -1
  47. modal/cli/run.py +6 -6
  48. modal/cli/secret.py +3 -3
  49. modal/cli/utils.py +2 -1
  50. modal/cli/volume.py +3 -3
  51. modal/client.py +6 -11
  52. modal/client.pyi +18 -27
  53. modal/cloud_bucket_mount.py +3 -3
  54. modal/cloud_bucket_mount.pyi +2 -2
  55. modal/cls.py +100 -47
  56. modal/cls.pyi +40 -40
  57. modal/config.py +3 -2
  58. modal/container_process.py +6 -2
  59. modal/dict.py +6 -3
  60. modal/dict.pyi +10 -9
  61. modal/environments.py +3 -3
  62. modal/environments.pyi +3 -3
  63. modal/exception.py +2 -3
  64. modal/functions.py +112 -104
  65. modal/functions.pyi +77 -58
  66. modal/image.py +59 -57
  67. modal/image.pyi +104 -103
  68. modal/io_streams.py +20 -12
  69. modal/io_streams.pyi +24 -14
  70. modal/mount.py +24 -24
  71. modal/mount.pyi +28 -29
  72. modal/network_file_system.py +14 -11
  73. modal/network_file_system.pyi +12 -11
  74. modal/object.py +9 -8
  75. modal/object.pyi +47 -34
  76. modal/output.py +2 -1
  77. modal/parallel_map.py +4 -4
  78. modal/partial_function.py +10 -14
  79. modal/partial_function.pyi +17 -18
  80. modal/queue.py +11 -8
  81. modal/queue.pyi +23 -22
  82. modal/retries.py +38 -0
  83. modal/runner.py +8 -7
  84. modal/runner.pyi +8 -14
  85. modal/running_app.py +3 -3
  86. modal/sandbox.py +20 -13
  87. modal/sandbox.pyi +73 -72
  88. modal/scheduler_placement.py +2 -1
  89. modal/secret.py +7 -7
  90. modal/secret.pyi +12 -12
  91. modal/serving.py +4 -3
  92. modal/serving.pyi +5 -4
  93. modal/token_flow.py +3 -2
  94. modal/token_flow.pyi +3 -3
  95. modal/volume.py +16 -23
  96. modal/volume.pyi +17 -16
  97. {modal-0.67.1.dist-info → modal-0.67.33.dist-info}/METADATA +2 -2
  98. modal-0.67.33.dist-info/RECORD +168 -0
  99. modal_docs/mdmd/signatures.py +1 -2
  100. modal_global_objects/mounts/python_standalone.py +1 -1
  101. modal_proto/api.proto +15 -0
  102. modal_proto/api_grpc.py +32 -0
  103. modal_proto/api_pb2.py +674 -654
  104. modal_proto/api_pb2.pyi +45 -1
  105. modal_proto/api_pb2_grpc.py +66 -0
  106. modal_proto/api_pb2_grpc.pyi +20 -0
  107. modal_proto/modal_api_grpc.py +2 -0
  108. modal_version/_version_generated.py +1 -1
  109. modal-0.67.1.dist-info/RECORD +0 -168
  110. {modal-0.67.1.dist-info → modal-0.67.33.dist-info}/LICENSE +0 -0
  111. {modal-0.67.1.dist-info → modal-0.67.33.dist-info}/WHEEL +0 -0
  112. {modal-0.67.1.dist-info → modal-0.67.33.dist-info}/entry_points.txt +0 -0
  113. {modal-0.67.1.dist-info → modal-0.67.33.dist-info}/top_level.txt +0 -0
modal/app.pyi CHANGED
@@ -1,3 +1,4 @@
1
+ import collections.abc
1
2
  import modal._utils.function_utils
2
3
  import modal.client
3
4
  import modal.cloud_bucket_mount
@@ -49,9 +50,9 @@ class LocalEntrypoint:
49
50
  @property
50
51
  def stub(self) -> App: ...
51
52
 
52
- def check_sequence(items: typing.Sequence[typing.Any], item_type: typing.Type[typing.Any], error_msg: str) -> None: ...
53
+ def check_sequence(items: typing.Sequence[typing.Any], item_type: type[typing.Any], error_msg: str) -> None: ...
53
54
 
54
- CLS_T = typing.TypeVar("CLS_T", bound="typing.Type[typing.Any]")
55
+ CLS_T = typing.TypeVar("CLS_T", bound="type[typing.Any]")
55
56
 
56
57
  P = typing_extensions.ParamSpec("P")
57
58
 
@@ -66,24 +67,24 @@ class _FunctionDecoratorType:
66
67
  ) -> modal.functions.Function[P, ReturnType, OriginalReturnType]: ...
67
68
  @typing.overload
68
69
  def __call__(
69
- self, func: typing.Callable[P, typing.Coroutine[typing.Any, typing.Any, ReturnType]]
70
- ) -> modal.functions.Function[P, ReturnType, typing.Coroutine[typing.Any, typing.Any, ReturnType]]: ...
70
+ self, func: typing.Callable[P, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]
71
+ ) -> modal.functions.Function[P, ReturnType, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]: ...
71
72
  @typing.overload
72
73
  def __call__(self, func: typing.Callable[P, ReturnType]) -> modal.functions.Function[P, ReturnType, ReturnType]: ...
73
74
 
74
75
  class _App:
75
- _all_apps: typing.ClassVar[typing.Dict[typing.Optional[str], typing.List[_App]]]
76
+ _all_apps: typing.ClassVar[dict[typing.Optional[str], list[_App]]]
76
77
  _container_app: typing.ClassVar[typing.Optional[modal.running_app.RunningApp]]
77
78
  _name: typing.Optional[str]
78
79
  _description: typing.Optional[str]
79
- _functions: typing.Dict[str, modal.functions._Function]
80
- _classes: typing.Dict[str, modal.cls._Cls]
80
+ _functions: dict[str, modal.functions._Function]
81
+ _classes: dict[str, modal.cls._Cls]
81
82
  _image: typing.Optional[modal.image._Image]
82
- _mounts: typing.Sequence[modal.mount._Mount]
83
- _secrets: typing.Sequence[modal.secret._Secret]
84
- _volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume]
85
- _web_endpoints: typing.List[str]
86
- _local_entrypoints: typing.Dict[str, _LocalEntrypoint]
83
+ _mounts: collections.abc.Sequence[modal.mount._Mount]
84
+ _secrets: collections.abc.Sequence[modal.secret._Secret]
85
+ _volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume]
86
+ _web_endpoints: list[str]
87
+ _local_entrypoints: dict[str, _LocalEntrypoint]
87
88
  _app_id: typing.Optional[str]
88
89
  _running_app: typing.Optional[modal.running_app.RunningApp]
89
90
  _client: typing.Optional[modal.client._Client]
@@ -93,9 +94,9 @@ class _App:
93
94
  name: typing.Optional[str] = None,
94
95
  *,
95
96
  image: typing.Optional[modal.image._Image] = None,
96
- mounts: typing.Sequence[modal.mount._Mount] = [],
97
- secrets: typing.Sequence[modal.secret._Secret] = [],
98
- volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
97
+ mounts: collections.abc.Sequence[modal.mount._Mount] = [],
98
+ secrets: collections.abc.Sequence[modal.secret._Secret] = [],
99
+ volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
99
100
  ) -> None: ...
100
101
  @property
101
102
  def name(self) -> typing.Optional[str]: ...
@@ -114,7 +115,6 @@ class _App:
114
115
  ) -> _App: ...
115
116
  def set_description(self, description: str): ...
116
117
  def _validate_blueprint_value(self, key: str, value: typing.Any): ...
117
- def _add_object(self, tag, obj): ...
118
118
  def __getitem__(self, tag: str): ...
119
119
  def __setitem__(self, tag: str, obj: modal.object._Object): ...
120
120
  def __getattr__(self, tag: str): ...
@@ -137,17 +137,18 @@ class _App:
137
137
  def _get_default_image(self): ...
138
138
  def _get_watch_mounts(self): ...
139
139
  def _add_function(self, function: modal.functions._Function, is_web_endpoint: bool): ...
140
+ def _add_class(self, tag: str, cls: modal.cls._Cls): ...
140
141
  def _init_container(self, client: modal.client._Client, running_app: modal.running_app.RunningApp): ...
141
142
  @property
142
- def registered_functions(self) -> typing.Dict[str, modal.functions._Function]: ...
143
+ def registered_functions(self) -> dict[str, modal.functions._Function]: ...
143
144
  @property
144
- def registered_classes(self) -> typing.Dict[str, modal.functions._Function]: ...
145
+ def registered_classes(self) -> dict[str, modal.functions._Function]: ...
145
146
  @property
146
- def registered_entrypoints(self) -> typing.Dict[str, _LocalEntrypoint]: ...
147
+ def registered_entrypoints(self) -> dict[str, _LocalEntrypoint]: ...
147
148
  @property
148
- def indexed_objects(self) -> typing.Dict[str, modal.object._Object]: ...
149
+ def indexed_objects(self) -> dict[str, modal.object._Object]: ...
149
150
  @property
150
- def registered_web_endpoints(self) -> typing.List[str]: ...
151
+ def registered_web_endpoints(self) -> list[str]: ...
151
152
  def local_entrypoint(
152
153
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
153
154
  ) -> typing.Callable[[typing.Callable[..., typing.Any]], _LocalEntrypoint]: ...
@@ -157,22 +158,22 @@ class _App:
157
158
  *,
158
159
  image: typing.Optional[modal.image._Image] = None,
159
160
  schedule: typing.Optional[modal.schedule.Schedule] = None,
160
- secrets: typing.Sequence[modal.secret._Secret] = (),
161
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
161
162
  gpu: typing.Union[
162
- None, bool, str, modal.gpu._GPUConfig, typing.List[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
163
+ None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
163
164
  ] = None,
164
165
  serialized: bool = False,
165
- mounts: typing.Sequence[modal.mount._Mount] = (),
166
- network_file_systems: typing.Dict[
166
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
167
+ network_file_systems: dict[
167
168
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system._NetworkFileSystem
168
169
  ] = {},
169
- volumes: typing.Dict[
170
+ volumes: dict[
170
171
  typing.Union[str, pathlib.PurePosixPath],
171
172
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
172
173
  ] = {},
173
174
  allow_cross_region_volumes: bool = False,
174
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
175
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
175
+ cpu: typing.Union[float, tuple[float, float], None] = None,
176
+ memory: typing.Union[int, tuple[int, int], None] = None,
176
177
  ephemeral_disk: typing.Optional[int] = None,
177
178
  proxy: typing.Optional[modal.proxy._Proxy] = None,
178
179
  retries: typing.Union[int, modal.retries.Retries, None] = None,
@@ -184,7 +185,7 @@ class _App:
184
185
  name: typing.Optional[str] = None,
185
186
  is_generator: typing.Optional[bool] = None,
186
187
  cloud: typing.Optional[str] = None,
187
- region: typing.Union[str, typing.Sequence[str], None] = None,
188
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
188
189
  enable_memory_snapshot: bool = False,
189
190
  block_network: bool = False,
190
191
  max_inputs: typing.Optional[int] = None,
@@ -203,22 +204,22 @@ class _App:
203
204
  _warn_parentheses_missing: typing.Optional[bool] = None,
204
205
  *,
205
206
  image: typing.Optional[modal.image._Image] = None,
206
- secrets: typing.Sequence[modal.secret._Secret] = (),
207
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
207
208
  gpu: typing.Union[
208
- None, bool, str, modal.gpu._GPUConfig, typing.List[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
209
+ None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
209
210
  ] = None,
210
211
  serialized: bool = False,
211
- mounts: typing.Sequence[modal.mount._Mount] = (),
212
- network_file_systems: typing.Dict[
212
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
213
+ network_file_systems: dict[
213
214
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system._NetworkFileSystem
214
215
  ] = {},
215
- volumes: typing.Dict[
216
+ volumes: dict[
216
217
  typing.Union[str, pathlib.PurePosixPath],
217
218
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
218
219
  ] = {},
219
220
  allow_cross_region_volumes: bool = False,
220
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
221
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
221
+ cpu: typing.Union[float, tuple[float, float], None] = None,
222
+ memory: typing.Union[int, tuple[int, int], None] = None,
222
223
  ephemeral_disk: typing.Optional[int] = None,
223
224
  proxy: typing.Optional[modal.proxy._Proxy] = None,
224
225
  retries: typing.Union[int, modal.retries.Retries, None] = None,
@@ -228,7 +229,7 @@ class _App:
228
229
  timeout: typing.Optional[int] = None,
229
230
  keep_warm: typing.Optional[int] = None,
230
231
  cloud: typing.Optional[str] = None,
231
- region: typing.Union[str, typing.Sequence[str], None] = None,
232
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
232
233
  enable_memory_snapshot: bool = False,
233
234
  block_network: bool = False,
234
235
  max_inputs: typing.Optional[int] = None,
@@ -241,20 +242,20 @@ class _App:
241
242
  self,
242
243
  *entrypoint_args: str,
243
244
  image: typing.Optional[modal.image._Image] = None,
244
- mounts: typing.Sequence[modal.mount._Mount] = (),
245
- secrets: typing.Sequence[modal.secret._Secret] = (),
246
- network_file_systems: typing.Dict[
245
+ mounts: collections.abc.Sequence[modal.mount._Mount] = (),
246
+ secrets: collections.abc.Sequence[modal.secret._Secret] = (),
247
+ network_file_systems: dict[
247
248
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system._NetworkFileSystem
248
249
  ] = {},
249
250
  timeout: typing.Optional[int] = None,
250
251
  workdir: typing.Optional[str] = None,
251
252
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
252
253
  cloud: typing.Optional[str] = None,
253
- region: typing.Union[str, typing.Sequence[str], None] = None,
254
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
255
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
254
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
255
+ cpu: typing.Union[float, tuple[float, float], None] = None,
256
+ memory: typing.Union[int, tuple[int, int], None] = None,
256
257
  block_network: bool = False,
257
- volumes: typing.Dict[
258
+ volumes: dict[
258
259
  typing.Union[str, pathlib.PurePosixPath],
259
260
  typing.Union[modal.volume._Volume, modal.cloud_bucket_mount._CloudBucketMount],
260
261
  ] = {},
@@ -262,23 +263,25 @@ class _App:
262
263
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
263
264
  ) -> modal.sandbox._Sandbox: ...
264
265
  def include(self, /, other_app: _App): ...
265
- def _logs(self, client: typing.Optional[modal.client._Client] = None) -> typing.AsyncGenerator[str, None]: ...
266
+ def _logs(
267
+ self, client: typing.Optional[modal.client._Client] = None
268
+ ) -> collections.abc.AsyncGenerator[str, None]: ...
266
269
  @classmethod
267
270
  def _reset_container_app(cls): ...
268
271
 
269
272
  class App:
270
- _all_apps: typing.ClassVar[typing.Dict[typing.Optional[str], typing.List[App]]]
273
+ _all_apps: typing.ClassVar[dict[typing.Optional[str], list[App]]]
271
274
  _container_app: typing.ClassVar[typing.Optional[modal.running_app.RunningApp]]
272
275
  _name: typing.Optional[str]
273
276
  _description: typing.Optional[str]
274
- _functions: typing.Dict[str, modal.functions.Function]
275
- _classes: typing.Dict[str, modal.cls.Cls]
277
+ _functions: dict[str, modal.functions.Function]
278
+ _classes: dict[str, modal.cls.Cls]
276
279
  _image: typing.Optional[modal.image.Image]
277
- _mounts: typing.Sequence[modal.mount.Mount]
278
- _secrets: typing.Sequence[modal.secret.Secret]
279
- _volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume]
280
- _web_endpoints: typing.List[str]
281
- _local_entrypoints: typing.Dict[str, LocalEntrypoint]
280
+ _mounts: collections.abc.Sequence[modal.mount.Mount]
281
+ _secrets: collections.abc.Sequence[modal.secret.Secret]
282
+ _volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume]
283
+ _web_endpoints: list[str]
284
+ _local_entrypoints: dict[str, LocalEntrypoint]
282
285
  _app_id: typing.Optional[str]
283
286
  _running_app: typing.Optional[modal.running_app.RunningApp]
284
287
  _client: typing.Optional[modal.client.Client]
@@ -288,9 +291,9 @@ class App:
288
291
  name: typing.Optional[str] = None,
289
292
  *,
290
293
  image: typing.Optional[modal.image.Image] = None,
291
- mounts: typing.Sequence[modal.mount.Mount] = [],
292
- secrets: typing.Sequence[modal.secret.Secret] = [],
293
- volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
294
+ mounts: collections.abc.Sequence[modal.mount.Mount] = [],
295
+ secrets: collections.abc.Sequence[modal.secret.Secret] = [],
296
+ volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
294
297
  ) -> None: ...
295
298
  @property
296
299
  def name(self) -> typing.Optional[str]: ...
@@ -321,7 +324,6 @@ class App:
321
324
 
322
325
  def set_description(self, description: str): ...
323
326
  def _validate_blueprint_value(self, key: str, value: typing.Any): ...
324
- def _add_object(self, tag, obj): ...
325
327
  def __getitem__(self, tag: str): ...
326
328
  def __setitem__(self, tag: str, obj: modal.object.Object): ...
327
329
  def __getattr__(self, tag: str): ...
@@ -363,17 +365,18 @@ class App:
363
365
  def _get_default_image(self): ...
364
366
  def _get_watch_mounts(self): ...
365
367
  def _add_function(self, function: modal.functions.Function, is_web_endpoint: bool): ...
368
+ def _add_class(self, tag: str, cls: modal.cls.Cls): ...
366
369
  def _init_container(self, client: modal.client.Client, running_app: modal.running_app.RunningApp): ...
367
370
  @property
368
- def registered_functions(self) -> typing.Dict[str, modal.functions.Function]: ...
371
+ def registered_functions(self) -> dict[str, modal.functions.Function]: ...
369
372
  @property
370
- def registered_classes(self) -> typing.Dict[str, modal.functions.Function]: ...
373
+ def registered_classes(self) -> dict[str, modal.functions.Function]: ...
371
374
  @property
372
- def registered_entrypoints(self) -> typing.Dict[str, LocalEntrypoint]: ...
375
+ def registered_entrypoints(self) -> dict[str, LocalEntrypoint]: ...
373
376
  @property
374
- def indexed_objects(self) -> typing.Dict[str, modal.object.Object]: ...
377
+ def indexed_objects(self) -> dict[str, modal.object.Object]: ...
375
378
  @property
376
- def registered_web_endpoints(self) -> typing.List[str]: ...
379
+ def registered_web_endpoints(self) -> list[str]: ...
377
380
  def local_entrypoint(
378
381
  self, _warn_parentheses_missing: typing.Any = None, *, name: typing.Optional[str] = None
379
382
  ) -> typing.Callable[[typing.Callable[..., typing.Any]], LocalEntrypoint]: ...
@@ -383,22 +386,22 @@ class App:
383
386
  *,
384
387
  image: typing.Optional[modal.image.Image] = None,
385
388
  schedule: typing.Optional[modal.schedule.Schedule] = None,
386
- secrets: typing.Sequence[modal.secret.Secret] = (),
389
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
387
390
  gpu: typing.Union[
388
- None, bool, str, modal.gpu._GPUConfig, typing.List[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
391
+ None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
389
392
  ] = None,
390
393
  serialized: bool = False,
391
- mounts: typing.Sequence[modal.mount.Mount] = (),
392
- network_file_systems: typing.Dict[
394
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
395
+ network_file_systems: dict[
393
396
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system.NetworkFileSystem
394
397
  ] = {},
395
- volumes: typing.Dict[
398
+ volumes: dict[
396
399
  typing.Union[str, pathlib.PurePosixPath],
397
400
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
398
401
  ] = {},
399
402
  allow_cross_region_volumes: bool = False,
400
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
401
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
403
+ cpu: typing.Union[float, tuple[float, float], None] = None,
404
+ memory: typing.Union[int, tuple[int, int], None] = None,
402
405
  ephemeral_disk: typing.Optional[int] = None,
403
406
  proxy: typing.Optional[modal.proxy.Proxy] = None,
404
407
  retries: typing.Union[int, modal.retries.Retries, None] = None,
@@ -410,7 +413,7 @@ class App:
410
413
  name: typing.Optional[str] = None,
411
414
  is_generator: typing.Optional[bool] = None,
412
415
  cloud: typing.Optional[str] = None,
413
- region: typing.Union[str, typing.Sequence[str], None] = None,
416
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
414
417
  enable_memory_snapshot: bool = False,
415
418
  block_network: bool = False,
416
419
  max_inputs: typing.Optional[int] = None,
@@ -429,22 +432,22 @@ class App:
429
432
  _warn_parentheses_missing: typing.Optional[bool] = None,
430
433
  *,
431
434
  image: typing.Optional[modal.image.Image] = None,
432
- secrets: typing.Sequence[modal.secret.Secret] = (),
435
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
433
436
  gpu: typing.Union[
434
- None, bool, str, modal.gpu._GPUConfig, typing.List[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
437
+ None, bool, str, modal.gpu._GPUConfig, list[typing.Union[None, bool, str, modal.gpu._GPUConfig]]
435
438
  ] = None,
436
439
  serialized: bool = False,
437
- mounts: typing.Sequence[modal.mount.Mount] = (),
438
- network_file_systems: typing.Dict[
440
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
441
+ network_file_systems: dict[
439
442
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system.NetworkFileSystem
440
443
  ] = {},
441
- volumes: typing.Dict[
444
+ volumes: dict[
442
445
  typing.Union[str, pathlib.PurePosixPath],
443
446
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
444
447
  ] = {},
445
448
  allow_cross_region_volumes: bool = False,
446
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
447
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
449
+ cpu: typing.Union[float, tuple[float, float], None] = None,
450
+ memory: typing.Union[int, tuple[int, int], None] = None,
448
451
  ephemeral_disk: typing.Optional[int] = None,
449
452
  proxy: typing.Optional[modal.proxy.Proxy] = None,
450
453
  retries: typing.Union[int, modal.retries.Retries, None] = None,
@@ -454,7 +457,7 @@ class App:
454
457
  timeout: typing.Optional[int] = None,
455
458
  keep_warm: typing.Optional[int] = None,
456
459
  cloud: typing.Optional[str] = None,
457
- region: typing.Union[str, typing.Sequence[str], None] = None,
460
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
458
461
  enable_memory_snapshot: bool = False,
459
462
  block_network: bool = False,
460
463
  max_inputs: typing.Optional[int] = None,
@@ -469,20 +472,20 @@ class App:
469
472
  self,
470
473
  *entrypoint_args: str,
471
474
  image: typing.Optional[modal.image.Image] = None,
472
- mounts: typing.Sequence[modal.mount.Mount] = (),
473
- secrets: typing.Sequence[modal.secret.Secret] = (),
474
- network_file_systems: typing.Dict[
475
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
476
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
477
+ network_file_systems: dict[
475
478
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system.NetworkFileSystem
476
479
  ] = {},
477
480
  timeout: typing.Optional[int] = None,
478
481
  workdir: typing.Optional[str] = None,
479
482
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
480
483
  cloud: typing.Optional[str] = None,
481
- region: typing.Union[str, typing.Sequence[str], None] = None,
482
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
483
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
484
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
485
+ cpu: typing.Union[float, tuple[float, float], None] = None,
486
+ memory: typing.Union[int, tuple[int, int], None] = None,
484
487
  block_network: bool = False,
485
- volumes: typing.Dict[
488
+ volumes: dict[
486
489
  typing.Union[str, pathlib.PurePosixPath],
487
490
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
488
491
  ] = {},
@@ -493,20 +496,20 @@ class App:
493
496
  self,
494
497
  *entrypoint_args: str,
495
498
  image: typing.Optional[modal.image.Image] = None,
496
- mounts: typing.Sequence[modal.mount.Mount] = (),
497
- secrets: typing.Sequence[modal.secret.Secret] = (),
498
- network_file_systems: typing.Dict[
499
+ mounts: collections.abc.Sequence[modal.mount.Mount] = (),
500
+ secrets: collections.abc.Sequence[modal.secret.Secret] = (),
501
+ network_file_systems: dict[
499
502
  typing.Union[str, pathlib.PurePosixPath], modal.network_file_system.NetworkFileSystem
500
503
  ] = {},
501
504
  timeout: typing.Optional[int] = None,
502
505
  workdir: typing.Optional[str] = None,
503
506
  gpu: typing.Union[None, bool, str, modal.gpu._GPUConfig] = None,
504
507
  cloud: typing.Optional[str] = None,
505
- region: typing.Union[str, typing.Sequence[str], None] = None,
506
- cpu: typing.Union[float, typing.Tuple[float, float], None] = None,
507
- memory: typing.Union[int, typing.Tuple[int, int], None] = None,
508
+ region: typing.Union[str, collections.abc.Sequence[str], None] = None,
509
+ cpu: typing.Union[float, tuple[float, float], None] = None,
510
+ memory: typing.Union[int, tuple[int, int], None] = None,
508
511
  block_network: bool = False,
509
- volumes: typing.Dict[
512
+ volumes: dict[
510
513
  typing.Union[str, pathlib.PurePosixPath],
511
514
  typing.Union[modal.volume.Volume, modal.cloud_bucket_mount.CloudBucketMount],
512
515
  ] = {},
@@ -522,7 +525,9 @@ class App:
522
525
  def __call__(
523
526
  self, client: typing.Optional[modal.client.Client] = None
524
527
  ) -> typing.Generator[str, None, None]: ...
525
- def aio(self, client: typing.Optional[modal.client.Client] = None) -> typing.AsyncGenerator[str, None]: ...
528
+ def aio(
529
+ self, client: typing.Optional[modal.client.Client] = None
530
+ ) -> collections.abc.AsyncGenerator[str, None]: ...
526
531
 
527
532
  _logs: ___logs_spec
528
533
 
@@ -536,9 +541,9 @@ class _Stub(_App):
536
541
  name: typing.Optional[str] = None,
537
542
  *,
538
543
  image: typing.Optional[modal.image._Image] = None,
539
- mounts: typing.Sequence[modal.mount._Mount] = [],
540
- secrets: typing.Sequence[modal.secret._Secret] = [],
541
- volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
544
+ mounts: collections.abc.Sequence[modal.mount._Mount] = [],
545
+ secrets: collections.abc.Sequence[modal.secret._Secret] = [],
546
+ volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume._Volume] = {},
542
547
  ): ...
543
548
 
544
549
  class Stub(App):
@@ -547,9 +552,9 @@ class Stub(App):
547
552
  name: typing.Optional[str] = None,
548
553
  *,
549
554
  image: typing.Optional[modal.image.Image] = None,
550
- mounts: typing.Sequence[modal.mount.Mount] = [],
551
- secrets: typing.Sequence[modal.secret.Secret] = [],
552
- volumes: typing.Dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
555
+ mounts: collections.abc.Sequence[modal.mount.Mount] = [],
556
+ secrets: collections.abc.Sequence[modal.secret.Secret] = [],
557
+ volumes: dict[typing.Union[str, pathlib.PurePosixPath], modal.volume.Volume] = {},
553
558
  ) -> None: ...
554
559
 
555
560
  _default_image: modal.image._Image
modal/call_graph.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # Copyright Modal Labs 2022
2
2
  from dataclasses import dataclass
3
3
  from enum import IntEnum
4
- from typing import Dict, List, Optional
4
+ from typing import Optional
5
5
 
6
6
  from modal_proto import api_pb2
7
7
 
@@ -31,12 +31,12 @@ class InputInfo:
31
31
  status: InputStatus
32
32
  function_name: str
33
33
  module_name: str
34
- children: List["InputInfo"]
34
+ children: list["InputInfo"]
35
35
 
36
36
 
37
- def _reconstruct_call_graph(ser_graph: api_pb2.FunctionGetCallGraphResponse) -> List[InputInfo]:
38
- function_calls_by_id: Dict[str, api_pb2.FunctionCallCallGraphInfo] = {}
39
- inputs_by_id: Dict[str, api_pb2.InputCallGraphInfo] = {}
37
+ def _reconstruct_call_graph(ser_graph: api_pb2.FunctionGetCallGraphResponse) -> list[InputInfo]:
38
+ function_calls_by_id: dict[str, api_pb2.FunctionCallCallGraphInfo] = {}
39
+ inputs_by_id: dict[str, api_pb2.InputCallGraphInfo] = {}
40
40
 
41
41
  for function_call in ser_graph.function_calls:
42
42
  function_calls_by_id[function_call.function_call_id] = function_call
@@ -44,7 +44,7 @@ def _reconstruct_call_graph(ser_graph: api_pb2.FunctionGetCallGraphResponse) ->
44
44
  for input in ser_graph.inputs:
45
45
  inputs_by_id[input.input_id] = input
46
46
 
47
- input_info_by_id: Dict[str, InputInfo] = {}
47
+ input_info_by_id: dict[str, InputInfo] = {}
48
48
  result = []
49
49
 
50
50
  def _reconstruct(input_id: str) -> Optional[InputInfo]:
modal/cli/_download.py CHANGED
@@ -3,8 +3,9 @@ import asyncio
3
3
  import os
4
4
  import shutil
5
5
  import sys
6
+ from collections.abc import AsyncIterator
6
7
  from pathlib import Path, PurePosixPath
7
- from typing import AsyncIterator, Callable, Optional, Tuple, Union
8
+ from typing import Callable, Optional, Union
8
9
 
9
10
  from click import UsageError
10
11
 
@@ -25,7 +26,7 @@ async def _volume_download(
25
26
  ):
26
27
  is_pipe = local_destination == PIPE_PATH
27
28
 
28
- q: asyncio.Queue[Tuple[Optional[Path], Optional[FileEntry]]] = asyncio.Queue()
29
+ q: asyncio.Queue[tuple[Optional[Path], Optional[FileEntry]]] = asyncio.Queue()
29
30
  num_consumers = 1 if is_pipe else 10 # concurrency limit for downloading files
30
31
 
31
32
  async def producer():
modal/cli/_traceback.py CHANGED
@@ -2,7 +2,7 @@
2
2
  """Helper functions related to displaying tracebacks in the CLI."""
3
3
  import functools
4
4
  import warnings
5
- from typing import Dict, Optional
5
+ from typing import Optional
6
6
 
7
7
  from rich.console import Console, RenderResult, group
8
8
  from rich.panel import Panel
@@ -20,14 +20,14 @@ def _render_stack(self, stack: Stack) -> RenderResult:
20
20
 
21
21
  path_highlighter = PathHighlighter()
22
22
  theme = self.theme
23
- code_cache: Dict[str, str] = {}
23
+ code_cache: dict[str, str] = {}
24
24
  line_cache = getattr(stack, "line_cache", {})
25
25
  task_id = None
26
26
 
27
27
  def read_code(filename: str) -> str:
28
28
  code = code_cache.get(filename)
29
29
  if code is None:
30
- with open(filename, "rt", encoding="utf-8", errors="replace") as code_file:
30
+ with open(filename, encoding="utf-8", errors="replace") as code_file:
31
31
  code = code_file.read()
32
32
  code_cache[filename] = code
33
33
  return code
@@ -169,7 +169,7 @@ def highlight_modal_deprecation_warnings() -> None:
169
169
  date = content[:10]
170
170
  message = content[11:].strip()
171
171
  try:
172
- with open(filename, "rt", encoding="utf-8", errors="replace") as code_file:
172
+ with open(filename, encoding="utf-8", errors="replace") as code_file:
173
173
  source = code_file.readlines()[lineno - 1].strip()
174
174
  message = f"{message}\n\nSource: {filename}:{lineno}\n {source}"
175
175
  except OSError:
modal/cli/app.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Copyright Modal Labs 2022
2
2
  import re
3
- from typing import List, Optional, Union
3
+ from typing import Optional, Union
4
4
 
5
5
  import rich
6
6
  import typer
@@ -56,7 +56,7 @@ def warn_on_name_option(command: str, app_identifier: str, name: str) -> str:
56
56
 
57
57
  @app_cli.command("list")
58
58
  @synchronizer.create_blocking
59
- async def list(env: Optional[str] = ENV_OPTION, json: bool = False):
59
+ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
60
60
  """List Modal apps that are currently deployed/running or recently stopped."""
61
61
  env = ensure_env(env)
62
62
  client = await _Client.from_env()
@@ -65,7 +65,7 @@ async def list(env: Optional[str] = ENV_OPTION, json: bool = False):
65
65
  api_pb2.AppListRequest(environment_name=_get_environment_name(env))
66
66
  )
67
67
 
68
- columns: List[Union[Column, str]] = [
68
+ columns: list[Union[Column, str]] = [
69
69
  Column("App ID", min_width=25), # Ensure that App ID is not truncated in slim terminals
70
70
  "Description",
71
71
  "State",
@@ -73,7 +73,7 @@ async def list(env: Optional[str] = ENV_OPTION, json: bool = False):
73
73
  "Created at",
74
74
  "Stopped at",
75
75
  ]
76
- rows: List[List[Union[Text, str]]] = []
76
+ rows: list[list[Union[Text, str]]] = []
77
77
  for app_stats in resp.apps:
78
78
  state = APP_STATE_TO_MESSAGE.get(app_stats.state, Text("unknown", style="gray"))
79
79
  rows.append(
modal/cli/container.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # Copyright Modal Labs 2022
2
2
 
3
- from typing import List, Optional, Union
3
+ from typing import Optional, Union
4
4
 
5
5
  import typer
6
6
  from rich.text import Text
@@ -21,7 +21,7 @@ container_cli = typer.Typer(name="container", help="Manage and connect to runnin
21
21
 
22
22
  @container_cli.command("list")
23
23
  @synchronizer.create_blocking
24
- async def list(env: Optional[str] = ENV_OPTION, json: bool = False):
24
+ async def list_(env: Optional[str] = ENV_OPTION, json: bool = False):
25
25
  """List all containers that are currently running."""
26
26
  env = ensure_env(env)
27
27
  client = await _Client.from_env()
@@ -31,7 +31,7 @@ async def list(env: Optional[str] = ENV_OPTION, json: bool = False):
31
31
  )
32
32
 
33
33
  column_names = ["Container ID", "App ID", "App Name", "Start Time"]
34
- rows: List[List[Union[Text, str]]] = []
34
+ rows: list[list[Union[Text, str]]] = []
35
35
  res.tasks.sort(key=lambda task: task.started_at, reverse=True)
36
36
  for task_stats in res.tasks:
37
37
  rows.append(
@@ -56,7 +56,7 @@ def logs(container_id: str = typer.Argument(help="Container ID")):
56
56
  @synchronizer.create_blocking
57
57
  async def exec(
58
58
  container_id: str = typer.Argument(help="Container ID"),
59
- command: List[str] = typer.Argument(help="A command to run inside the container."),
59
+ command: list[str] = typer.Argument(help="A command to run inside the container."),
60
60
  pty: bool = typer.Option(default=True, help="Run the command using a PTY."),
61
61
  ):
62
62
  """Execute a command in a container."""
modal/cli/dict.py CHANGED
@@ -36,7 +36,7 @@ async def create(name: str, *, env: Optional[str] = ENV_OPTION):
36
36
 
37
37
  @dict_cli.command(name="list", rich_help_panel="Management")
38
38
  @synchronizer.create_blocking
39
- async def list(*, json: bool = False, env: Optional[str] = ENV_OPTION):
39
+ async def list_(*, json: bool = False, env: Optional[str] = ENV_OPTION):
40
40
  """List all named Dicts."""
41
41
  env = ensure_env(env)
42
42
  client = await _Client.from_env()
modal/cli/environment.py CHANGED
@@ -1,11 +1,10 @@
1
1
  # Copyright Modal Labs 2023
2
- from typing import Optional, Union
2
+ from typing import Annotated, Optional, Union
3
3
 
4
4
  import typer
5
5
  from click import UsageError
6
6
  from grpclib import GRPCError, Status
7
7
  from rich.text import Text
8
- from typing_extensions import Annotated
9
8
 
10
9
  from modal import environments
11
10
  from modal._utils.name_utils import check_environment_name
@@ -37,7 +36,7 @@ class RenderableBool(Text):
37
36
 
38
37
 
39
38
  @environment_cli.command(name="list", help="List all environments in the current workspace")
40
- def list(json: Optional[bool] = False):
39
+ def list_(json: Optional[bool] = False):
41
40
  envs = environments.list_environments()
42
41
 
43
42
  # determine which environment is currently active, prioritizing the local default
modal/cli/import_refs.py CHANGED
@@ -54,7 +54,7 @@ def import_file_or_module(file_or_module: str):
54
54
  # when using a script path, that scripts directory should also be on the path as it is
55
55
  # with `python some/script.py`
56
56
  full_path = Path(file_or_module).resolve()
57
- if "." in full_path.name[:-3]: # use removesuffix once we drop 3.8 support
57
+ if "." in full_path.name.removesuffix(".py"):
58
58
  raise InvalidError(
59
59
  f"Invalid Modal source filename: {full_path.name!r}."
60
60
  "\n\nSource filename cannot contain additional period characters."