modal 1.0.5.dev9__py3-none-any.whl → 1.0.5.dev10__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.
modal/client.pyi CHANGED
@@ -31,7 +31,7 @@ class _Client:
31
31
  server_url: str,
32
32
  client_type: int,
33
33
  credentials: typing.Optional[tuple[str, str]],
34
- version: str = "1.0.5.dev9",
34
+ version: str = "1.0.5.dev10",
35
35
  ):
36
36
  """mdmd:hidden
37
37
  The Modal client object is not intended to be instantiated directly by users.
@@ -160,7 +160,7 @@ class Client:
160
160
  server_url: str,
161
161
  client_type: int,
162
162
  credentials: typing.Optional[tuple[str, str]],
163
- version: str = "1.0.5.dev9",
163
+ version: str = "1.0.5.dev10",
164
164
  ):
165
165
  """mdmd:hidden
166
166
  The Modal client object is not intended to be instantiated directly by users.
@@ -1,5 +1,7 @@
1
1
  # Copyright Modal Labs 2025
2
+ import asyncio
2
3
  import os
4
+ import sys
3
5
  from dataclasses import dataclass
4
6
  from pathlib import Path
5
7
  from typing import Literal, Optional, Union
@@ -11,11 +13,13 @@ from .._functions import _Function
11
13
  from .._object import _get_environment_name
12
14
  from .._partial_function import _clustered
13
15
  from .._runtime.container_io_manager import _ContainerIOManager
16
+ from .._tunnel import _forward as _forward_tunnel
14
17
  from .._utils.async_utils import synchronize_api, synchronizer
15
18
  from .._utils.deprecation import deprecation_warning
16
19
  from .._utils.grpc_utils import retry_transient_errors
17
20
  from ..client import _Client
18
21
  from ..cls import _Obj
22
+ from ..config import logger
19
23
  from ..exception import InvalidError
20
24
  from ..image import DockerfileSpec, ImageBuilderVersion, _Image, _ImageRegistryConfig
21
25
  from ..secret import _Secret
@@ -209,3 +213,70 @@ async def update_autoscaler(
209
213
 
210
214
  request = api_pb2.FunctionUpdateSchedulingParamsRequest(function_id=f.object_id, settings=settings)
211
215
  await retry_transient_errors(client.stub.FunctionUpdateSchedulingParams, request)
216
+
217
+
218
+ class _FlashManager:
219
+ def __init__(self, client: _Client, port: int):
220
+ self.client = client
221
+ self.port = port
222
+ self.tunnel_manager = _forward_tunnel(port, client=client)
223
+
224
+ async def _start(self):
225
+ tunnel = await self.tunnel_manager.__aenter__()
226
+
227
+ host, port = tunnel.url.split("://")[1].split(":")
228
+ self.heartbeat_task = asyncio.create_task(self._run_heartbeat(host, int(port)))
229
+
230
+ async def _run_heartbeat(self, host: str, port: int):
231
+ first_registration = True
232
+ while True:
233
+ try:
234
+ resp = await self.client.stub.FlashContainerRegister(
235
+ api_pb2.FlashContainerRegisterRequest(
236
+ priority=10,
237
+ weight=5,
238
+ host=host,
239
+ port=port,
240
+ ),
241
+ timeout=1,
242
+ )
243
+ if first_registration:
244
+ logger.warning(f"[Modal Flash] Listening at {resp.url}")
245
+ first_registration = False
246
+ except asyncio.CancelledError:
247
+ logger.warning("[Modal Flash] Shutting down...")
248
+ break
249
+ except Exception as e:
250
+ logger.error(f"[Modal Flash] Heartbeat failed: {e}")
251
+
252
+ try:
253
+ await asyncio.sleep(1)
254
+ except asyncio.CancelledError:
255
+ logger.warning("[Modal Flash] Shutting down...")
256
+ break
257
+
258
+ async def stop(self):
259
+ self.heartbeat_task.cancel()
260
+ await retry_transient_errors(
261
+ self.client.stub.FlashContainerDeregister,
262
+ api_pb2.FlashContainerDeregisterRequest(),
263
+ )
264
+ await self.tunnel_manager.__aexit__(*sys.exc_info())
265
+
266
+
267
+ FlashManager = synchronize_api(_FlashManager)
268
+
269
+
270
+ @synchronizer.create_blocking
271
+ async def flash_forward(port: int) -> _FlashManager:
272
+ """
273
+ Forward a port to the Modal Flash service, exposing that port as a stable web endpoint.
274
+
275
+ This is a highly experimental method that can break or be removed at any time without warning.
276
+ Do not use this method unless explicitly instructed to do so by Modal support.
277
+ """
278
+ client = await _Client.from_env()
279
+
280
+ manager = _FlashManager(client, port)
281
+ await manager._start()
282
+ return manager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: modal
3
- Version: 1.0.5.dev9
3
+ Version: 1.0.5.dev10
4
4
  Summary: Python client library for Modal
5
5
  Author-email: Modal Labs <support@modal.com>
6
6
  License: Apache-2.0
@@ -22,7 +22,7 @@ modal/app.py,sha256=pj-4mpvBR6phFG38rQZ8GM1FIgcaM8cje5d_Vo2_gJU,46602
22
22
  modal/app.pyi,sha256=Z6wi_dkXywiaM2rvAvguj2Wgu9ZgPjMSLl1nH1a7EYI,42243
23
23
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
24
24
  modal/client.py,sha256=OwISJvkgMb-rHm9Gc4i-7YcDgGiZgwJ7F_PzwZH7a6Q,16847
25
- modal/client.pyi,sha256=rHKE8PgbWzInGkoBb4XPPjFkE7mc-oP1lEJKVIYkumY,15079
25
+ modal/client.pyi,sha256=T1F26WrBQ3ZFILDxqq4t9b0GAyFe_p8dB5HzgllZAnY,15081
26
26
  modal/cloud_bucket_mount.py,sha256=YOe9nnvSr4ZbeCn587d7_VhE9IioZYRvF9VYQTQux08,5914
27
27
  modal/cloud_bucket_mount.pyi,sha256=-qSfYAQvIoO_l2wsCCGTG5ZUwQieNKXdAO00yP1-LYU,7394
28
28
  modal/cls.py,sha256=6GMJFnqVm5BqfLbEGWcI7M_QBAuUzn-apB9P1sllI9s,39843
@@ -138,7 +138,7 @@ modal/cli/volume.py,sha256=KJ4WKQYjRGsTERkwHE1HcRia9rWzLIDDnlc89QmTLvE,10960
138
138
  modal/cli/programs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
139
139
  modal/cli/programs/run_jupyter.py,sha256=44Lpvqk2l3hH-uOkmAOzw60NEsfB5uaRDWDKVshvQhs,2682
140
140
  modal/cli/programs/vscode.py,sha256=KbTAaIXyQBVCDXxXjmBHmKpgXkUw0q4R4KkJvUjCYgk,3380
141
- modal/experimental/__init__.py,sha256=qO5CqJNSIqSRD5WaoN8l1D-qZ7HRSrGzg85BH6hroiI,8410
141
+ modal/experimental/__init__.py,sha256=lmhu5bFoIUSbq5TVTc0S6ZBb5Q-xZKy_PCVngIGd26I,10833
142
142
  modal/experimental/ipython.py,sha256=TrCfmol9LGsRZMeDoeMPx3Hv3BFqQhYnmD_iH0pqdhk,2904
143
143
  modal/requirements/2023.12.312.txt,sha256=zWWUVgVQ92GXBKNYYr2-5vn9rlnXcmkqlwlX5u1eTYw,400
144
144
  modal/requirements/2023.12.txt,sha256=OjsbXFkCSdkzzryZP82Q73osr5wxQ6EUzmGcK7twfkA,502
@@ -147,7 +147,7 @@ modal/requirements/2024.10.txt,sha256=qD-5cVIVM9wXesJ6JC89Ew-3m2KjEElUz3jaw_MddR
147
147
  modal/requirements/PREVIEW.txt,sha256=KxDaVTOwatHvboDo4lorlgJ7-n-MfAwbPwxJ0zcJqrs,312
148
148
  modal/requirements/README.md,sha256=9tK76KP0Uph7O0M5oUgsSwEZDj5y-dcUPsnpR0Sc-Ik,854
149
149
  modal/requirements/base-images.json,sha256=f1bwyp2UkM844eoO9Qk30gQw_xrMqKpMSeJ6MErXnEk,995
150
- modal-1.0.5.dev9.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
150
+ modal-1.0.5.dev10.dist-info/licenses/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
151
151
  modal_docs/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,28
152
152
  modal_docs/gen_cli_docs.py,sha256=c1yfBS_x--gL5bs0N4ihMwqwX8l3IBWSkBAKNNIi6bQ,3801
153
153
  modal_docs/gen_reference_docs.py,sha256=d_CQUGQ0rfw28u75I2mov9AlS773z9rG40-yq5o7g2U,6359
@@ -155,13 +155,13 @@ modal_docs/mdmd/__init__.py,sha256=svYKtV8HDwDCN86zbdWqyq5T8sMdGDj0PVlzc2tIxDM,2
155
155
  modal_docs/mdmd/mdmd.py,sha256=Irx49MCCTlBOP4FBdLR--JrpA3-WhsVeriq0LGgsRic,6232
156
156
  modal_docs/mdmd/signatures.py,sha256=XJaZrK7Mdepk5fdX51A8uENiLFNil85Ud0d4MH8H5f0,3218
157
157
  modal_proto/__init__.py,sha256=MIEP8jhXUeGq_eCjYFcqN5b1bxBM4fdk0VESpjWR0fc,28
158
- modal_proto/api.proto,sha256=z0hs56mo8kBS82aJTCZOO4vsfI2jIB_aPlrVVNQmWVY,96775
159
- modal_proto/api_grpc.py,sha256=iY5o_Tm4VDP-Wa1JgA_NpQa_Y-4FYB_RN9wdSUExjwI,117469
160
- modal_proto/api_pb2.py,sha256=0cPu8GmJi_iV8ui-y_F2HsL4we8WVIZ3BkIOpMIdIiw,340022
161
- modal_proto/api_pb2.pyi,sha256=drZMxTFOY2Jcc9d5S1RuIH-0awGnvND_fs_MnEn3whQ,466425
162
- modal_proto/api_pb2_grpc.py,sha256=NL5prOS_hh_pA1hVvQP_ZRE1w49N-PR8iNPRZ65i6nA,254089
163
- modal_proto/api_pb2_grpc.pyi,sha256=Xxgdcnv1mBnu5_AQxJ6fo0yz7GnqVU0HVObNfZWHVfM,59440
164
- modal_proto/modal_api_grpc.py,sha256=0ir2lnwT3-IgPcAWw98yWMAiqZPkjvNro9UBk4u8hnk,17763
158
+ modal_proto/api.proto,sha256=i-ETZCN-HofvuOxK-0TQ9V0lYpCOyREEUg3VxuUfjJY,97293
159
+ modal_proto/api_grpc.py,sha256=KR3X2FZiKjJuistRWzsBsDi8DKeIlKJJ2iPPbzltDJg,119140
160
+ modal_proto/api_pb2.py,sha256=QruoJk16KzDhNut2aoANMPpnj2KCt_EBvQU5gsAIq88,342410
161
+ modal_proto/api_pb2.pyi,sha256=zTjXqsw79xO2EkzVWaspD-skxW8JrK0PJUM5BlAmXZA,468320
162
+ modal_proto/api_pb2_grpc.py,sha256=xRO6E7F9wSeE75T2NW_EVSN0JHUkCz-qQDgPMTG1x0o,257566
163
+ modal_proto/api_pb2_grpc.pyi,sha256=pCgIpIcJnEoWnh1Bu1LT62-oesNHN-XyQJaZzxRNeB4,60334
164
+ modal_proto/modal_api_grpc.py,sha256=Vc2BoHcB6hV2GlkwvpB5yBfeJT72dxQ6-VMUhbPD-0U,18019
165
165
  modal_proto/modal_options_grpc.py,sha256=qJ1cuwA54oRqrdTyPTbvfhFZYd9HhJKK5UCwt523r3Y,120
166
166
  modal_proto/options.proto,sha256=zp9h5r61ivsp0XwEWwNBsVqNTbRA1VSY_UtN7sEcHtE,549
167
167
  modal_proto/options_grpc.py,sha256=M18X3d-8F_cNYSVM3I25dUTO5rZ0rd-vCCfynfh13Nc,125
@@ -170,10 +170,10 @@ modal_proto/options_pb2.pyi,sha256=l7DBrbLO7q3Ir-XDkWsajm0d0TQqqrfuX54i4BMpdQg,1
170
170
  modal_proto/options_pb2_grpc.py,sha256=1oboBPFxaTEXt9Aw7EAj8gXHDCNMhZD2VXqocC9l_gk,159
171
171
  modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0yJSI,247
172
172
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
- modal_version/__init__.py,sha256=NP0of-jUg-JDdAgiQcpLCvWtDc6Q-IhoGaqrUxNxU2o,120
173
+ modal_version/__init__.py,sha256=JSMwaNXk5-V1fjFndXUHI51gfY_IwuoLQ-kFSo_71J0,121
174
174
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
175
- modal-1.0.5.dev9.dist-info/METADATA,sha256=3B4-3yvxYkdxXTZqj1vftu6igx9PU-W-Bgz5kMNUO3A,2454
176
- modal-1.0.5.dev9.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
- modal-1.0.5.dev9.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
- modal-1.0.5.dev9.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
- modal-1.0.5.dev9.dist-info/RECORD,,
175
+ modal-1.0.5.dev10.dist-info/METADATA,sha256=viMvvnbKrrT3p_5zNJPSn1AeerXaz5hu_XsI8aKRFwY,2455
176
+ modal-1.0.5.dev10.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
177
+ modal-1.0.5.dev10.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
178
+ modal-1.0.5.dev10.dist-info/top_level.txt,sha256=4BWzoKYREKUZ5iyPzZpjqx4G8uB5TWxXPDwibLcVa7k,43
179
+ modal-1.0.5.dev10.dist-info/RECORD,,
modal_proto/api.proto CHANGED
@@ -1242,6 +1242,22 @@ message FilesystemRuntimeOutputBatch {
1242
1242
  bool eof = 4;
1243
1243
  }
1244
1244
 
1245
+ message FlashContainerDeregisterRequest {
1246
+ string service_name = 1;
1247
+ }
1248
+
1249
+ message FlashContainerRegisterRequest {
1250
+ string service_name = 1;
1251
+ uint32 priority = 2;
1252
+ uint32 weight = 3;
1253
+ string host = 4;
1254
+ uint32 port = 5;
1255
+ }
1256
+
1257
+ message FlashContainerRegisterResponse {
1258
+ string url = 1;
1259
+ }
1260
+
1245
1261
  message Function {
1246
1262
  string module_name = 1;
1247
1263
  string function_name = 2;
@@ -3268,6 +3284,10 @@ service ModalClient {
3268
3284
  rpc EnvironmentList(google.protobuf.Empty) returns (EnvironmentListResponse);
3269
3285
  rpc EnvironmentUpdate(EnvironmentUpdateRequest) returns (EnvironmentListItem);
3270
3286
 
3287
+ // Modal Flash (experimental)
3288
+ rpc FlashContainerDeregister(FlashContainerDeregisterRequest) returns (google.protobuf.Empty);
3289
+ rpc FlashContainerRegister(FlashContainerRegisterRequest) returns (FlashContainerRegisterResponse);
3290
+
3271
3291
  // Functions
3272
3292
  rpc FunctionAsyncInvoke(FunctionAsyncInvokeRequest) returns (FunctionAsyncInvokeResponse);
3273
3293
  rpc FunctionBindParams(FunctionBindParamsRequest) returns (FunctionBindParamsResponse);
modal_proto/api_grpc.py CHANGED
@@ -242,6 +242,14 @@ class ModalClientBase(abc.ABC):
242
242
  async def EnvironmentUpdate(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.EnvironmentUpdateRequest, modal_proto.api_pb2.EnvironmentListItem]') -> None:
243
243
  pass
244
244
 
245
+ @abc.abstractmethod
246
+ async def FlashContainerDeregister(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FlashContainerDeregisterRequest, google.protobuf.empty_pb2.Empty]') -> None:
247
+ pass
248
+
249
+ @abc.abstractmethod
250
+ async def FlashContainerRegister(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FlashContainerRegisterRequest, modal_proto.api_pb2.FlashContainerRegisterResponse]') -> None:
251
+ pass
252
+
245
253
  @abc.abstractmethod
246
254
  async def FunctionAsyncInvoke(self, stream: 'grpclib.server.Stream[modal_proto.api_pb2.FunctionAsyncInvokeRequest, modal_proto.api_pb2.FunctionAsyncInvokeResponse]') -> None:
247
255
  pass
@@ -968,6 +976,18 @@ class ModalClientBase(abc.ABC):
968
976
  modal_proto.api_pb2.EnvironmentUpdateRequest,
969
977
  modal_proto.api_pb2.EnvironmentListItem,
970
978
  ),
979
+ '/modal.client.ModalClient/FlashContainerDeregister': grpclib.const.Handler(
980
+ self.FlashContainerDeregister,
981
+ grpclib.const.Cardinality.UNARY_UNARY,
982
+ modal_proto.api_pb2.FlashContainerDeregisterRequest,
983
+ google.protobuf.empty_pb2.Empty,
984
+ ),
985
+ '/modal.client.ModalClient/FlashContainerRegister': grpclib.const.Handler(
986
+ self.FlashContainerRegister,
987
+ grpclib.const.Cardinality.UNARY_UNARY,
988
+ modal_proto.api_pb2.FlashContainerRegisterRequest,
989
+ modal_proto.api_pb2.FlashContainerRegisterResponse,
990
+ ),
971
991
  '/modal.client.ModalClient/FunctionAsyncInvoke': grpclib.const.Handler(
972
992
  self.FunctionAsyncInvoke,
973
993
  grpclib.const.Cardinality.UNARY_UNARY,
@@ -1892,6 +1912,18 @@ class ModalClientStub:
1892
1912
  modal_proto.api_pb2.EnvironmentUpdateRequest,
1893
1913
  modal_proto.api_pb2.EnvironmentListItem,
1894
1914
  )
1915
+ self.FlashContainerDeregister = grpclib.client.UnaryUnaryMethod(
1916
+ channel,
1917
+ '/modal.client.ModalClient/FlashContainerDeregister',
1918
+ modal_proto.api_pb2.FlashContainerDeregisterRequest,
1919
+ google.protobuf.empty_pb2.Empty,
1920
+ )
1921
+ self.FlashContainerRegister = grpclib.client.UnaryUnaryMethod(
1922
+ channel,
1923
+ '/modal.client.ModalClient/FlashContainerRegister',
1924
+ modal_proto.api_pb2.FlashContainerRegisterRequest,
1925
+ modal_proto.api_pb2.FlashContainerRegisterResponse,
1926
+ )
1895
1927
  self.FunctionAsyncInvoke = grpclib.client.UnaryUnaryMethod(
1896
1928
  channel,
1897
1929
  '/modal.client.ModalClient/FunctionAsyncInvoke',