modal 0.62.16__py3-none-any.whl → 0.72.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 (220) hide show
  1. modal/__init__.py +17 -13
  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 +420 -937
  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 -59
  11. modal/_resources.py +51 -0
  12. modal/_runtime/__init__.py +1 -0
  13. modal/_runtime/asgi.py +519 -0
  14. modal/_runtime/container_io_manager.py +1036 -0
  15. modal/_runtime/execution_context.py +89 -0
  16. modal/_runtime/telemetry.py +169 -0
  17. modal/_runtime/user_code_imports.py +356 -0
  18. modal/_serialization.py +134 -9
  19. modal/_traceback.py +47 -187
  20. modal/_tunnel.py +52 -16
  21. modal/_tunnel.pyi +19 -36
  22. modal/_utils/app_utils.py +3 -17
  23. modal/_utils/async_utils.py +479 -100
  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 +460 -171
  29. modal/_utils/grpc_testing.py +47 -31
  30. modal/_utils/grpc_utils.py +62 -109
  31. modal/_utils/hash_utils.py +61 -19
  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 +5 -7
  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 +14 -12
  43. modal/app.py +1003 -314
  44. modal/app.pyi +540 -264
  45. modal/call_graph.py +7 -6
  46. modal/cli/_download.py +63 -53
  47. modal/cli/_traceback.py +200 -0
  48. modal/cli/app.py +205 -45
  49. modal/cli/config.py +12 -5
  50. modal/cli/container.py +62 -14
  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 +64 -58
  55. modal/cli/launch.py +32 -18
  56. modal/cli/network_file_system.py +64 -83
  57. modal/cli/profile.py +1 -1
  58. modal/cli/programs/run_jupyter.py +35 -10
  59. modal/cli/programs/vscode.py +60 -10
  60. modal/cli/queues.py +131 -0
  61. modal/cli/run.py +234 -131
  62. modal/cli/secret.py +8 -7
  63. modal/cli/token.py +7 -2
  64. modal/cli/utils.py +79 -10
  65. modal/cli/volume.py +110 -109
  66. modal/client.py +250 -144
  67. modal/client.pyi +157 -118
  68. modal/cloud_bucket_mount.py +108 -34
  69. modal/cloud_bucket_mount.pyi +32 -38
  70. modal/cls.py +535 -148
  71. modal/cls.pyi +190 -146
  72. modal/config.py +41 -19
  73. modal/container_process.py +177 -0
  74. modal/container_process.pyi +82 -0
  75. modal/dict.py +111 -65
  76. modal/dict.pyi +136 -131
  77. modal/environments.py +106 -5
  78. modal/environments.pyi +77 -25
  79. modal/exception.py +34 -43
  80. modal/experimental.py +61 -2
  81. modal/extensions/ipython.py +5 -5
  82. modal/file_io.py +537 -0
  83. modal/file_io.pyi +235 -0
  84. modal/file_pattern_matcher.py +197 -0
  85. modal/functions.py +906 -911
  86. modal/functions.pyi +466 -430
  87. modal/gpu.py +57 -44
  88. modal/image.py +1089 -479
  89. modal/image.pyi +584 -228
  90. modal/io_streams.py +434 -0
  91. modal/io_streams.pyi +122 -0
  92. modal/mount.py +314 -101
  93. modal/mount.pyi +241 -235
  94. modal/network_file_system.py +92 -92
  95. modal/network_file_system.pyi +152 -110
  96. modal/object.py +67 -36
  97. modal/object.pyi +166 -143
  98. modal/output.py +63 -0
  99. modal/parallel_map.py +434 -0
  100. modal/parallel_map.pyi +75 -0
  101. modal/partial_function.py +282 -117
  102. modal/partial_function.pyi +222 -129
  103. modal/proxy.py +15 -12
  104. modal/proxy.pyi +3 -8
  105. modal/queue.py +182 -65
  106. modal/queue.pyi +218 -118
  107. modal/requirements/2024.04.txt +29 -0
  108. modal/requirements/2024.10.txt +16 -0
  109. modal/requirements/README.md +21 -0
  110. modal/requirements/base-images.json +22 -0
  111. modal/retries.py +48 -7
  112. modal/runner.py +459 -156
  113. modal/runner.pyi +135 -71
  114. modal/running_app.py +38 -0
  115. modal/sandbox.py +514 -236
  116. modal/sandbox.pyi +397 -169
  117. modal/schedule.py +4 -4
  118. modal/scheduler_placement.py +20 -3
  119. modal/secret.py +56 -31
  120. modal/secret.pyi +62 -42
  121. modal/serving.py +51 -56
  122. modal/serving.pyi +44 -36
  123. modal/stream_type.py +15 -0
  124. modal/token_flow.py +5 -3
  125. modal/token_flow.pyi +37 -32
  126. modal/volume.py +285 -157
  127. modal/volume.pyi +249 -184
  128. {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/METADATA +7 -7
  129. modal-0.72.11.dist-info/RECORD +174 -0
  130. {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/top_level.txt +0 -1
  131. modal_docs/gen_reference_docs.py +3 -1
  132. modal_docs/mdmd/mdmd.py +0 -1
  133. modal_docs/mdmd/signatures.py +5 -2
  134. modal_global_objects/images/base_images.py +28 -0
  135. modal_global_objects/mounts/python_standalone.py +2 -2
  136. modal_proto/__init__.py +1 -1
  137. modal_proto/api.proto +1288 -533
  138. modal_proto/api_grpc.py +856 -456
  139. modal_proto/api_pb2.py +2165 -1157
  140. modal_proto/api_pb2.pyi +8859 -0
  141. modal_proto/api_pb2_grpc.py +1674 -855
  142. modal_proto/api_pb2_grpc.pyi +1416 -0
  143. modal_proto/modal_api_grpc.py +149 -0
  144. modal_proto/modal_options_grpc.py +3 -0
  145. modal_proto/options_pb2.pyi +20 -0
  146. modal_proto/options_pb2_grpc.pyi +7 -0
  147. modal_proto/py.typed +0 -0
  148. modal_version/__init__.py +1 -1
  149. modal_version/_version_generated.py +2 -2
  150. modal/_asgi.py +0 -370
  151. modal/_container_entrypoint.pyi +0 -378
  152. modal/_container_exec.py +0 -128
  153. modal/_sandbox_shell.py +0 -49
  154. modal/shared_volume.py +0 -23
  155. modal/shared_volume.pyi +0 -24
  156. modal/stub.py +0 -783
  157. modal/stub.pyi +0 -332
  158. modal-0.62.16.dist-info/RECORD +0 -198
  159. modal_global_objects/images/conda.py +0 -15
  160. modal_global_objects/images/debian_slim.py +0 -15
  161. modal_global_objects/images/micromamba.py +0 -15
  162. test/__init__.py +0 -1
  163. test/aio_test.py +0 -12
  164. test/async_utils_test.py +0 -262
  165. test/blob_test.py +0 -67
  166. test/cli_imports_test.py +0 -149
  167. test/cli_test.py +0 -659
  168. test/client_test.py +0 -194
  169. test/cls_test.py +0 -630
  170. test/config_test.py +0 -137
  171. test/conftest.py +0 -1420
  172. test/container_app_test.py +0 -32
  173. test/container_test.py +0 -1389
  174. test/cpu_test.py +0 -23
  175. test/decorator_test.py +0 -85
  176. test/deprecation_test.py +0 -34
  177. test/dict_test.py +0 -33
  178. test/e2e_test.py +0 -68
  179. test/error_test.py +0 -7
  180. test/function_serialization_test.py +0 -32
  181. test/function_test.py +0 -653
  182. test/function_utils_test.py +0 -101
  183. test/gpu_test.py +0 -159
  184. test/grpc_utils_test.py +0 -141
  185. test/helpers.py +0 -42
  186. test/image_test.py +0 -669
  187. test/live_reload_test.py +0 -80
  188. test/lookup_test.py +0 -70
  189. test/mdmd_test.py +0 -329
  190. test/mount_test.py +0 -162
  191. test/mounted_files_test.py +0 -329
  192. test/network_file_system_test.py +0 -181
  193. test/notebook_test.py +0 -66
  194. test/object_test.py +0 -41
  195. test/package_utils_test.py +0 -25
  196. test/queue_test.py +0 -97
  197. test/resolver_test.py +0 -58
  198. test/retries_test.py +0 -67
  199. test/runner_test.py +0 -85
  200. test/sandbox_test.py +0 -191
  201. test/schedule_test.py +0 -15
  202. test/scheduler_placement_test.py +0 -29
  203. test/secret_test.py +0 -78
  204. test/serialization_test.py +0 -42
  205. test/stub_composition_test.py +0 -10
  206. test/stub_test.py +0 -360
  207. test/test_asgi_wrapper.py +0 -234
  208. test/token_flow_test.py +0 -18
  209. test/traceback_test.py +0 -135
  210. test/tunnel_test.py +0 -29
  211. test/utils_test.py +0 -88
  212. test/version_test.py +0 -14
  213. test/volume_test.py +0 -341
  214. test/watcher_test.py +0 -30
  215. test/webhook_test.py +0 -146
  216. /modal/{requirements.312.txt → requirements/2023.12.312.txt} +0 -0
  217. /modal/{requirements.txt → requirements/2023.12.txt} +0 -0
  218. {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/LICENSE +0 -0
  219. {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/WHEEL +0 -0
  220. {modal-0.62.16.dist-info → modal-0.72.11.dist-info}/entry_points.txt +0 -0
@@ -1,141 +1,234 @@
1
+ import collections.abc
1
2
  import enum
2
3
  import modal.functions
3
4
  import modal_proto.api_pb2
4
5
  import typing
6
+ import typing_extensions
5
7
 
6
8
  class _PartialFunctionFlags(enum.IntFlag):
7
- FUNCTION: int
8
- BUILD: int
9
- ENTER_PRE_CHECKPOINT: int
10
- ENTER_POST_CHECKPOINT: int
11
- EXIT: int
9
+ FUNCTION: int = 1
10
+ BUILD: int = 2
11
+ ENTER_PRE_SNAPSHOT: int = 4
12
+ ENTER_POST_SNAPSHOT: int = 8
13
+ EXIT: int = 16
14
+ BATCHED: int = 32
15
+ CLUSTERED: int = 64 # Experimental: Clustered functions
12
16
 
13
- def _generate_next_value_(name, start, count, last_values):
14
- ...
17
+ @staticmethod
18
+ def all() -> int:
19
+ return ~_PartialFunctionFlags(0)
15
20
 
16
- def __new__(cls, value):
17
- ...
21
+ P = typing_extensions.ParamSpec("P")
18
22
 
23
+ ReturnType = typing.TypeVar("ReturnType", covariant=True)
19
24
 
20
- class _PartialFunction:
21
- raw_f: typing.Callable[..., typing.Any]
22
- flags: _PartialFunctionFlags
23
- webhook_config: typing.Union[modal_proto.api_pb2.WebhookConfig, None]
24
- is_generator: typing.Union[bool, None]
25
- keep_warm: typing.Union[int, None]
26
-
27
- def __init__(self, raw_f: typing.Callable[..., typing.Any], flags: _PartialFunctionFlags, webhook_config: typing.Union[modal_proto.api_pb2.WebhookConfig, None] = None, is_generator: typing.Union[bool, None] = None, keep_warm: typing.Union[int, None] = None):
28
- ...
29
-
30
- def __get__(self, obj, objtype=None) -> modal.functions._Function:
31
- ...
32
-
33
- def __del__(self):
34
- ...
25
+ OriginalReturnType = typing.TypeVar("OriginalReturnType", covariant=True)
35
26
 
36
- def add_flags(self, flags) -> _PartialFunction:
37
- ...
38
-
39
-
40
- class PartialFunction:
41
- raw_f: typing.Callable[..., typing.Any]
27
+ class _PartialFunction(typing.Generic[P, ReturnType, OriginalReturnType]):
28
+ raw_f: typing.Callable[P, ReturnType]
42
29
  flags: _PartialFunctionFlags
43
- webhook_config: typing.Union[modal_proto.api_pb2.WebhookConfig, None]
44
- is_generator: typing.Union[bool, None]
45
- keep_warm: typing.Union[int, None]
46
-
47
- def __init__(self, raw_f: typing.Callable[..., typing.Any], flags: _PartialFunctionFlags, webhook_config: typing.Union[modal_proto.api_pb2.WebhookConfig, None] = None, is_generator: typing.Union[bool, None] = None, keep_warm: typing.Union[int, None] = None):
48
- ...
49
-
50
- def __get__(self, obj, objtype=None) -> modal.functions.Function:
51
- ...
52
-
53
- def __del__(self):
54
- ...
55
-
56
- def add_flags(self, flags) -> PartialFunction:
57
- ...
58
-
59
-
60
- def _find_partial_methods_for_cls(user_cls: typing.Type, flags: _PartialFunctionFlags) -> typing.Dict[str, _PartialFunction]:
61
- ...
62
-
63
-
64
- def _find_callables_for_cls(user_cls: typing.Type, flags: _PartialFunctionFlags) -> typing.Dict[str, typing.Callable]:
65
- ...
66
-
67
-
68
- def _find_callables_for_obj(user_obj: typing.Any, flags: _PartialFunctionFlags) -> typing.Dict[str, typing.Callable]:
69
- ...
70
-
71
-
72
- def _method(_warn_parentheses_missing=None, *, is_generator: typing.Union[bool, None] = None, keep_warm: typing.Union[int, None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]:
73
- ...
74
-
75
-
76
- def _parse_custom_domains(custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.List[modal_proto.api_pb2.CustomDomainConfig]:
77
- ...
78
-
79
-
80
- def _web_endpoint(_warn_parentheses_missing=None, *, method: str = 'GET', label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]:
81
- ...
82
-
83
-
84
- def _asgi_app(_warn_parentheses_missing=None, *, label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]:
85
- ...
86
-
87
-
88
- def _wsgi_app(_warn_parentheses_missing=None, *, label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]:
89
- ...
90
-
91
-
92
- def _web_server(port: int, *, startup_timeout: float = 5.0, label: typing.Union[str, None] = None, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]:
93
- ...
94
-
95
-
96
- def _disallow_wrapping_method(f: _PartialFunction, wrapper: str) -> None:
97
- ...
98
-
99
-
100
- def _build(_warn_parentheses_missing=None) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], _PartialFunction]], _PartialFunction]:
101
- ...
102
-
103
-
104
- def _enter(_warn_parentheses_missing=None, *, snap: bool = False) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], _PartialFunction]], _PartialFunction]:
105
- ...
106
-
107
-
108
- def _exit(_warn_parentheses_missing=None) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any, typing.Union[typing.Type[BaseException], None], typing.Union[BaseException, None], typing.Any], None], typing.Callable[[typing.Any], None]]], _PartialFunction]:
109
- ...
110
-
111
-
112
- def method(_warn_parentheses_missing=None, *, is_generator: typing.Union[bool, None] = None, keep_warm: typing.Union[int, None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]:
113
- ...
114
-
115
-
116
- def web_endpoint(_warn_parentheses_missing=None, *, method: str = 'GET', label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]:
117
- ...
118
-
119
-
120
- def asgi_app(_warn_parentheses_missing=None, *, label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]:
121
- ...
122
-
123
-
124
- def wsgi_app(_warn_parentheses_missing=None, *, label: typing.Union[str, None] = None, wait_for_response: bool = True, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]:
125
- ...
126
-
127
-
128
- def web_server(port: int, *, startup_timeout: float = 5.0, label: typing.Union[str, None] = None, custom_domains: typing.Union[typing.Iterable[str], None] = None) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]:
129
- ...
130
-
131
-
132
- def build(_warn_parentheses_missing=None) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction]:
133
- ...
134
-
135
-
136
- def enter(_warn_parentheses_missing=None, *, snap: bool = False) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction]:
137
- ...
138
-
139
-
140
- def exit(_warn_parentheses_missing=None) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any, typing.Union[typing.Type[BaseException], None], typing.Union[BaseException, None], typing.Any], None], typing.Callable[[typing.Any], None]]], PartialFunction]:
141
- ...
30
+ webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig]
31
+ is_generator: bool
32
+ keep_warm: typing.Optional[int]
33
+ batch_max_size: typing.Optional[int]
34
+ batch_wait_ms: typing.Optional[int]
35
+ force_build: bool
36
+ cluster_size: typing.Optional[int]
37
+ build_timeout: typing.Optional[int]
38
+
39
+ def __init__(
40
+ self,
41
+ raw_f: typing.Callable[P, ReturnType],
42
+ flags: _PartialFunctionFlags,
43
+ webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig] = None,
44
+ is_generator: typing.Optional[bool] = None,
45
+ keep_warm: typing.Optional[int] = None,
46
+ batch_max_size: typing.Optional[int] = None,
47
+ batch_wait_ms: typing.Optional[int] = None,
48
+ cluster_size: typing.Optional[int] = None,
49
+ force_build: bool = False,
50
+ build_timeout: typing.Optional[int] = None,
51
+ ): ...
52
+ def __get__(self, obj, objtype=None) -> modal.functions._Function[P, ReturnType, OriginalReturnType]: ...
53
+ def __del__(self): ...
54
+ def add_flags(self, flags) -> _PartialFunction: ...
55
+
56
+ class PartialFunction(typing.Generic[P, ReturnType, OriginalReturnType]):
57
+ raw_f: typing.Callable[P, ReturnType]
58
+ flags: _PartialFunctionFlags
59
+ webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig]
60
+ is_generator: bool
61
+ keep_warm: typing.Optional[int]
62
+ batch_max_size: typing.Optional[int]
63
+ batch_wait_ms: typing.Optional[int]
64
+ force_build: bool
65
+ cluster_size: typing.Optional[int]
66
+ build_timeout: typing.Optional[int]
67
+
68
+ def __init__(
69
+ self,
70
+ raw_f: typing.Callable[P, ReturnType],
71
+ flags: _PartialFunctionFlags,
72
+ webhook_config: typing.Optional[modal_proto.api_pb2.WebhookConfig] = None,
73
+ is_generator: typing.Optional[bool] = None,
74
+ keep_warm: typing.Optional[int] = None,
75
+ batch_max_size: typing.Optional[int] = None,
76
+ batch_wait_ms: typing.Optional[int] = None,
77
+ cluster_size: typing.Optional[int] = None,
78
+ force_build: bool = False,
79
+ build_timeout: typing.Optional[int] = None,
80
+ ): ...
81
+ def __get__(self, obj, objtype=None) -> modal.functions.Function[P, ReturnType, OriginalReturnType]: ...
82
+ def __del__(self): ...
83
+ def add_flags(self, flags) -> PartialFunction: ...
84
+
85
+ def _find_partial_methods_for_user_cls(user_cls: type[typing.Any], flags: int) -> dict[str, _PartialFunction]: ...
86
+ def _find_callables_for_obj(user_obj: typing.Any, flags: int) -> dict[str, typing.Callable[..., typing.Any]]: ...
87
+
88
+ class _MethodDecoratorType:
89
+ @typing.overload
90
+ def __call__(
91
+ self, func: PartialFunction[typing_extensions.Concatenate[typing.Any, P], ReturnType, OriginalReturnType]
92
+ ) -> PartialFunction[P, ReturnType, OriginalReturnType]: ...
93
+ @typing.overload
94
+ def __call__(
95
+ self,
96
+ func: typing.Callable[
97
+ typing_extensions.Concatenate[typing.Any, P], collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]
98
+ ],
99
+ ) -> PartialFunction[P, ReturnType, collections.abc.Coroutine[typing.Any, typing.Any, ReturnType]]: ...
100
+ @typing.overload
101
+ def __call__(
102
+ self, func: typing.Callable[typing_extensions.Concatenate[typing.Any, P], ReturnType]
103
+ ) -> PartialFunction[P, ReturnType, ReturnType]: ...
104
+
105
+ def _method(
106
+ _warn_parentheses_missing=None,
107
+ *,
108
+ is_generator: typing.Optional[bool] = None,
109
+ keep_warm: typing.Optional[int] = None,
110
+ ) -> _MethodDecoratorType: ...
111
+ def _parse_custom_domains(
112
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
113
+ ) -> list[modal_proto.api_pb2.CustomDomainConfig]: ...
114
+ def _web_endpoint(
115
+ _warn_parentheses_missing=None,
116
+ *,
117
+ method: str = "GET",
118
+ label: typing.Optional[str] = None,
119
+ docs: bool = False,
120
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
121
+ requires_proxy_auth: bool = False,
122
+ wait_for_response: bool = True,
123
+ ) -> typing.Callable[[typing.Callable[P, ReturnType]], _PartialFunction[P, ReturnType, ReturnType]]: ...
124
+ def _asgi_app(
125
+ _warn_parentheses_missing=None,
126
+ *,
127
+ label: typing.Optional[str] = None,
128
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
129
+ requires_proxy_auth: bool = False,
130
+ wait_for_response: bool = True,
131
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]: ...
132
+ def _wsgi_app(
133
+ _warn_parentheses_missing=None,
134
+ *,
135
+ label: typing.Optional[str] = None,
136
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
137
+ requires_proxy_auth: bool = False,
138
+ wait_for_response: bool = True,
139
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]: ...
140
+ def _web_server(
141
+ port: int,
142
+ *,
143
+ startup_timeout: float = 5.0,
144
+ label: typing.Optional[str] = None,
145
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
146
+ requires_proxy_auth: bool = False,
147
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]: ...
148
+ def _disallow_wrapping_method(f: _PartialFunction, wrapper: str) -> None: ...
149
+ def _build(
150
+ _warn_parentheses_missing=None, *, force: bool = False, timeout: int = 86400
151
+ ) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], _PartialFunction]], _PartialFunction]: ...
152
+ def _enter(
153
+ _warn_parentheses_missing=None, *, snap: bool = False
154
+ ) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], _PartialFunction]], _PartialFunction]: ...
155
+ def _exit(
156
+ _warn_parentheses_missing=None,
157
+ ) -> typing.Callable[
158
+ [
159
+ typing.Union[
160
+ typing.Callable[
161
+ [typing.Any, typing.Optional[type[BaseException]], typing.Optional[BaseException], typing.Any],
162
+ typing.Any,
163
+ ],
164
+ typing.Callable[[typing.Any], typing.Any],
165
+ ]
166
+ ],
167
+ _PartialFunction,
168
+ ]: ...
169
+ def _batched(
170
+ _warn_parentheses_missing=None, *, max_batch_size: int, wait_ms: int
171
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], _PartialFunction]: ...
172
+ def method(
173
+ _warn_parentheses_missing=None,
174
+ *,
175
+ is_generator: typing.Optional[bool] = None,
176
+ keep_warm: typing.Optional[int] = None,
177
+ ) -> _MethodDecoratorType: ...
178
+ def web_endpoint(
179
+ _warn_parentheses_missing=None,
180
+ *,
181
+ method: str = "GET",
182
+ label: typing.Optional[str] = None,
183
+ docs: bool = False,
184
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
185
+ requires_proxy_auth: bool = False,
186
+ wait_for_response: bool = True,
187
+ ) -> typing.Callable[[typing.Callable[P, ReturnType]], PartialFunction[P, ReturnType, ReturnType]]: ...
188
+ def asgi_app(
189
+ _warn_parentheses_missing=None,
190
+ *,
191
+ label: typing.Optional[str] = None,
192
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
193
+ requires_proxy_auth: bool = False,
194
+ wait_for_response: bool = True,
195
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]: ...
196
+ def wsgi_app(
197
+ _warn_parentheses_missing=None,
198
+ *,
199
+ label: typing.Optional[str] = None,
200
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
201
+ requires_proxy_auth: bool = False,
202
+ wait_for_response: bool = True,
203
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]: ...
204
+ def web_server(
205
+ port: int,
206
+ *,
207
+ startup_timeout: float = 5.0,
208
+ label: typing.Optional[str] = None,
209
+ custom_domains: typing.Optional[collections.abc.Iterable[str]] = None,
210
+ requires_proxy_auth: bool = False,
211
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]: ...
212
+ def build(
213
+ _warn_parentheses_missing=None, *, force: bool = False, timeout: int = 86400
214
+ ) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction]: ...
215
+ def enter(
216
+ _warn_parentheses_missing=None, *, snap: bool = False
217
+ ) -> typing.Callable[[typing.Union[typing.Callable[[typing.Any], typing.Any], PartialFunction]], PartialFunction]: ...
218
+ def exit(
219
+ _warn_parentheses_missing=None,
220
+ ) -> typing.Callable[
221
+ [
222
+ typing.Union[
223
+ typing.Callable[
224
+ [typing.Any, typing.Optional[type[BaseException]], typing.Optional[BaseException], typing.Any],
225
+ typing.Any,
226
+ ],
227
+ typing.Callable[[typing.Any], typing.Any],
228
+ ]
229
+ ],
230
+ PartialFunction,
231
+ ]: ...
232
+ def batched(
233
+ _warn_parentheses_missing=None, *, max_batch_size: int, wait_ms: int
234
+ ) -> typing.Callable[[typing.Callable[..., typing.Any]], PartialFunction]: ...
modal/proxy.py CHANGED
@@ -9,28 +9,31 @@ from .object import _get_environment_name, _Object
9
9
 
10
10
 
11
11
  class _Proxy(_Object, type_prefix="pr"):
12
- """
13
- Proxy objects are used to setup secure tunnel connections to a private remote address, for example
14
- a database.
12
+ """Proxy objects give your Modal containers a static outbound IP address.
15
13
 
16
- Currently `modal.Proxy` objects must be setup with the assistance of Modal staff. If you require a proxy
17
- please contact us.
14
+ This can be used for connecting to a remote address with network whitelist, for example
15
+ a database. See [the guide](/docs/guide/proxy-ips) for more information.
18
16
  """
19
17
 
20
18
  @staticmethod
21
19
  def from_name(
22
- label: str,
23
- namespace=api_pb2.DEPLOYMENT_NAMESPACE_WORKSPACE,
20
+ name: str,
24
21
  environment_name: Optional[str] = None,
25
22
  ) -> "_Proxy":
23
+ """Reference a Proxy by its name.
24
+
25
+ In contrast to most other Modal objects, new Proxy objects must be
26
+ provisioned via the Dashboard and cannot be created on the fly from code.
27
+
28
+ """
29
+
26
30
  async def _load(self: _Proxy, resolver: Resolver, existing_object_id: Optional[str]):
27
- req = api_pb2.ProxyGetOrCreateRequest(
28
- deployment_name=label,
29
- namespace=namespace,
31
+ req = api_pb2.ProxyGetRequest(
32
+ name=name,
30
33
  environment_name=_get_environment_name(environment_name, resolver),
31
34
  )
32
- response = await resolver.client.stub.ProxyGetOrCreate(req)
33
- self._hydrate(response.proxy_id, resolver.client, None)
35
+ response: api_pb2.ProxyGetResponse = await resolver.client.stub.ProxyGet(req)
36
+ self._hydrate(response.proxy.proxy_id, resolver.client, None)
34
37
 
35
38
  return _Proxy._from_loader(_load, "Proxy()", is_another_app=True)
36
39
 
modal/proxy.pyi CHANGED
@@ -3,14 +3,9 @@ import typing
3
3
 
4
4
  class _Proxy(modal.object._Object):
5
5
  @staticmethod
6
- def from_name(label: str, namespace=1, environment_name: typing.Union[str, None] = None) -> _Proxy:
7
- ...
8
-
6
+ def from_name(name: str, environment_name: typing.Optional[str] = None) -> _Proxy: ...
9
7
 
10
8
  class Proxy(modal.object.Object):
11
- def __init__(self, *args, **kwargs):
12
- ...
13
-
9
+ def __init__(self, *args, **kwargs): ...
14
10
  @staticmethod
15
- def from_name(label: str, namespace=1, environment_name: typing.Union[str, None] = None) -> Proxy:
16
- ...
11
+ def from_name(name: str, environment_name: typing.Optional[str] = None) -> Proxy: ...