modal 0.67.13__py3-none-any.whl → 0.67.15__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
@@ -26,7 +26,7 @@ class _Client:
26
26
  _stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
27
27
 
28
28
  def __init__(
29
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.13"
29
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.15"
30
30
  ): ...
31
31
  def is_closed(self) -> bool: ...
32
32
  @property
@@ -81,7 +81,7 @@ class Client:
81
81
  _stub: typing.Optional[modal_proto.api_grpc.ModalClientStub]
82
82
 
83
83
  def __init__(
84
- self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.13"
84
+ self, server_url: str, client_type: int, credentials: typing.Optional[tuple[str, str]], version: str = "0.67.15"
85
85
  ): ...
86
86
  def is_closed(self) -> bool: ...
87
87
  @property
@@ -128,12 +128,16 @@ class _ContainerProcess(Generic[T]):
128
128
  on_connect = asyncio.Event()
129
129
 
130
130
  async def _write_to_fd_loop(stream: _StreamReader):
131
- async for line in stream:
131
+ # Don't skip empty messages so we can detect when the process has booted.
132
+ async for chunk in stream._get_logs(skip_empty_messages=False):
133
+ if chunk is None:
134
+ break
135
+
132
136
  if not on_connect.is_set():
133
137
  connecting_status.stop()
134
138
  on_connect.set()
135
139
 
136
- await write_to_fd(stream.file_descriptor, line.encode("utf-8"))
140
+ await write_to_fd(stream.file_descriptor, chunk)
137
141
 
138
142
  async def _handle_input(data: bytes, message_index: int):
139
143
  self.stdin.write(data)
modal/io_streams.py CHANGED
@@ -224,7 +224,7 @@ class _StreamReader(Generic[T]):
224
224
 
225
225
  entry_id += 1
226
226
 
227
- async def _get_logs(self) -> AsyncGenerator[Optional[bytes], None]:
227
+ async def _get_logs(self, skip_empty_messages: bool = True) -> AsyncGenerator[Optional[bytes], None]:
228
228
  """Streams sandbox or process logs from the server to the reader.
229
229
 
230
230
  Logs returned by this method may contain partial or multiple lines at a time.
@@ -253,6 +253,11 @@ class _StreamReader(Generic[T]):
253
253
 
254
254
  async for message, entry_id in iterator:
255
255
  self._last_entry_id = entry_id
256
+ # Empty messages are sent when the process boots up. Don't yield them unless
257
+ # we're using the empty message to signal process liveness.
258
+ if skip_empty_messages and message == b"":
259
+ continue
260
+
256
261
  yield message
257
262
  if message is None:
258
263
  completed = True
modal/io_streams.pyi CHANGED
@@ -31,7 +31,9 @@ class _StreamReader(typing.Generic[T]):
31
31
  async def read(self) -> T: ...
32
32
  async def _consume_container_process_stream(self): ...
33
33
  def _stream_container_process(self) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
34
- def _get_logs(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
34
+ def _get_logs(
35
+ self, skip_empty_messages: bool = True
36
+ ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
35
37
  def _get_logs_by_line(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
36
38
  def __aiter__(self) -> collections.abc.AsyncIterator[T]: ...
37
39
  async def __anext__(self) -> T: ...
@@ -82,8 +84,12 @@ class StreamReader(typing.Generic[T]):
82
84
  _stream_container_process: ___stream_container_process_spec
83
85
 
84
86
  class ___get_logs_spec(typing_extensions.Protocol):
85
- def __call__(self) -> typing.Generator[typing.Optional[bytes], None, None]: ...
86
- def aio(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
87
+ def __call__(
88
+ self, skip_empty_messages: bool = True
89
+ ) -> typing.Generator[typing.Optional[bytes], None, None]: ...
90
+ def aio(
91
+ self, skip_empty_messages: bool = True
92
+ ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
87
93
 
88
94
  _get_logs: ___get_logs_spec
89
95
 
modal/sandbox.py CHANGED
@@ -28,6 +28,7 @@ from .io_streams import StreamReader, StreamWriter, _StreamReader, _StreamWriter
28
28
  from .mount import _Mount
29
29
  from .network_file_system import _NetworkFileSystem, network_file_system_mount_protos
30
30
  from .object import _get_environment_name, _Object
31
+ from .proxy import _Proxy
31
32
  from .scheduler_placement import SchedulerPlacement
32
33
  from .secret import _Secret
33
34
  from .stream_type import StreamType
@@ -73,6 +74,7 @@ class _Sandbox(_Object, type_prefix="sb"):
73
74
  pty_info: Optional[api_pb2.PTYInfo] = None,
74
75
  encrypted_ports: Sequence[int] = [],
75
76
  unencrypted_ports: Sequence[int] = [],
77
+ proxy: Optional[_Proxy] = None,
76
78
  _experimental_scheduler_placement: Optional[SchedulerPlacement] = None,
77
79
  ) -> "_Sandbox":
78
80
  """mdmd:hidden"""
@@ -166,6 +168,7 @@ class _Sandbox(_Object, type_prefix="sb"):
166
168
  worker_id=config.get("worker_id"),
167
169
  open_ports=api_pb2.PortSpecs(ports=open_ports),
168
170
  network_access=network_access,
171
+ proxy_id=(proxy.object_id if proxy else None),
169
172
  )
170
173
 
171
174
  # Note - `resolver.app_id` will be `None` for app-less sandboxes
modal/sandbox.pyi CHANGED
@@ -11,6 +11,7 @@ import modal.io_streams
11
11
  import modal.mount
12
12
  import modal.network_file_system
13
13
  import modal.object
14
+ import modal.proxy
14
15
  import modal.scheduler_placement
15
16
  import modal.secret
16
17
  import modal.stream_type
@@ -51,6 +52,7 @@ class _Sandbox(modal.object._Object):
51
52
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
52
53
  encrypted_ports: collections.abc.Sequence[int] = [],
53
54
  unencrypted_ports: collections.abc.Sequence[int] = [],
55
+ proxy: typing.Optional[modal.proxy._Proxy] = None,
54
56
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
55
57
  ) -> _Sandbox: ...
56
58
  @staticmethod
@@ -165,6 +167,7 @@ class Sandbox(modal.object.Object):
165
167
  pty_info: typing.Optional[modal_proto.api_pb2.PTYInfo] = None,
166
168
  encrypted_ports: collections.abc.Sequence[int] = [],
167
169
  unencrypted_ports: collections.abc.Sequence[int] = [],
170
+ proxy: typing.Optional[modal.proxy.Proxy] = None,
168
171
  _experimental_scheduler_placement: typing.Optional[modal.scheduler_placement.SchedulerPlacement] = None,
169
172
  ) -> Sandbox: ...
170
173
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: modal
3
- Version: 0.67.13
3
+ Version: 0.67.15
4
4
  Summary: Python client library for Modal
5
5
  Author: Modal Labs
6
6
  Author-email: support@modal.com
@@ -19,13 +19,13 @@ modal/app.py,sha256=EJ7FUN6rWnSwLJoYJh8nmKg_t-8hdN8_rt0OrkP7JvQ,46084
19
19
  modal/app.pyi,sha256=BE5SlR5tRECuc6-e2lUuOknDdov3zxgZ4N0AsLb5ZVQ,25270
20
20
  modal/call_graph.py,sha256=1g2DGcMIJvRy-xKicuf63IVE98gJSnQsr8R_NVMptNc,2581
21
21
  modal/client.py,sha256=VMg_aIuo_LOEe2ttxBHEND3PLhTp5lo-onH4wELhIyY,16375
22
- modal/client.pyi,sha256=eg7nuSgtNxJkB8fQLRu6VDD6b8w8fSBcW9-5wO2Phzo,7354
22
+ modal/client.pyi,sha256=omuAq-oRdFMqcdb731dEYbDNBp3cThARcleAXFIPVZs,7354
23
23
  modal/cloud_bucket_mount.py,sha256=G7T7jWLD0QkmrfKR75mSTwdUZ2xNfj7pkVqb4ipmxmI,5735
24
24
  modal/cloud_bucket_mount.pyi,sha256=CEi7vrH3kDUF4LAy4qP6tfImy2UJuFRcRbsgRNM1wo8,1403
25
25
  modal/cls.py,sha256=F2jk5zFCAA8h-GfM0dbdBG3Mu5wiG9k9Z9JLYRYuT2Q,24758
26
26
  modal/cls.pyi,sha256=2_nbvSlkh2d0tfibTIxsThPiL0Xcrcosc5f_ET-i0sk,8147
27
27
  modal/config.py,sha256=1KhNJkjYsJkX1V8RPPdRYPlM2HE-ZZs0JVSxbiXjmrw,11010
28
- modal/container_process.py,sha256=c_jBPtyPeSxbIcbLfs_FzTrt-1eErtRSnsfxkDozFoY,5589
28
+ modal/container_process.py,sha256=YRCKjn56oqTtGjtLxpl_KSkOhYrcRitgF3LOI6o14Q4,5759
29
29
  modal/container_process.pyi,sha256=k2kClwaSzz11eci1pzFZgCm-ptXapHAyHTOENorlazA,2594
30
30
  modal/dict.py,sha256=RmJlEwFJOdSfAYcVa50hbbFccV8e7BvC5tc5g1HXF-c,12622
31
31
  modal/dict.pyi,sha256=2cYgOqBxYZih4BYgMV0c3rNPuxYR6-cB1GBXzFkHA5c,7265
@@ -38,8 +38,8 @@ modal/functions.pyi,sha256=fifvDS5GDEYmXjko1UGZrKqmhfnQn6GRwCblM9hrRWo,25107
38
38
  modal/gpu.py,sha256=r4rL6uH3UJIQthzYvfWauXNyh01WqCPtKZCmmSX1fd4,6881
39
39
  modal/image.py,sha256=ZIC8tgjJnqWamN4sZ0Gch3x2VmcM671MWfRLR5SMmoc,79423
40
40
  modal/image.pyi,sha256=JjicLNuaBsfuPZ_xo_eN0zKZkDrEm2alYg-szENhJjM,24591
41
- modal/io_streams.py,sha256=gZPXD7unxRrxC4aroejKM1-pd4STg09JqLd0NRegAMs,14635
42
- modal/io_streams.pyi,sha256=QNvbZpm1qW6LkqCIcJ4Zprn_IW-ZVqt62KrpDP--_Co,4555
41
+ modal/io_streams.py,sha256=4pF2HumRK1pVnrx6S9UwGqJn69rQqyQqpe5X_nifny0,14943
42
+ modal/io_streams.pyi,sha256=An766S3JKP78b2A4RphjdVNR73yblDc5uG_xp5--6k4,4715
43
43
  modal/mount.py,sha256=_N_fd5NX_eWwmb_xh_X_28nNHW9upEDXDyXixZWnUiQ,27730
44
44
  modal/mount.pyi,sha256=3e4nkXUeeVmUmOyK8Tiyk_EQlHeWruN3yGJVnmDUVrI,9761
45
45
  modal/network_file_system.py,sha256=mwtYp25XtFaiGpSG7U0KSkiTzJWrxgGTcoxfPZ9yGR0,14141
@@ -60,8 +60,8 @@ modal/retries.py,sha256=HKR2Q9aNPWkMjQ5nwobqYTuZaSuw0a8lI2zrtY5IW98,5230
60
60
  modal/runner.py,sha256=7obU-Gq1ocpBGCuR6pvn1T-D6ggg1T48qFo2TNUGWkU,24089
61
61
  modal/runner.pyi,sha256=RAtCvx_lXWjyFjIaZ3t9-X1c7rqpgAQlhl4Hww53OY8,5038
62
62
  modal/running_app.py,sha256=CshNvGDJtagOdKW54uYjY8HY73j2TpnsL9jkPFZAsfA,560
63
- modal/sandbox.py,sha256=5oDrV9XL8JkGl_gcbu5D20vbaxFRpWv_bCdw-Fo-qNE,24886
64
- modal/sandbox.pyi,sha256=FKdkLGmJrdRT0pHlhV_brxo1pvxr6uWZeL-zomLHSas,17366
63
+ modal/sandbox.py,sha256=8cZ7eArLvUeR7bmvb9-XuE08ij-wSd5rbLhspdkAA9Y,25015
64
+ modal/sandbox.pyi,sha256=4sxZGsRpmXME9wGWWQOLukN0tCezdMSp3pVJWu6fe5g,17502
65
65
  modal/schedule.py,sha256=0ZFpKs1bOxeo5n3HZjoL7OE2ktsb-_oGtq-WJEPO4tY,2615
66
66
  modal/scheduler_placement.py,sha256=BAREdOY5HzHpzSBqt6jDVR6YC_jYfHMVqOzkyqQfngU,1235
67
67
  modal/secret.py,sha256=Y1WgybQIkfkxdzH9CQ1h-Wd1DJJpzipigMhyyvSxTww,10007
@@ -159,10 +159,10 @@ modal_proto/options_pb2_grpc.pyi,sha256=CImmhxHsYnF09iENPoe8S4J-n93jtgUYD2JPAc0y
159
159
  modal_proto/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
160
160
  modal_version/__init__.py,sha256=3IY-AWLH55r35_mQXIaut0jrJvoPuf1NZJBQQfSbPuo,470
161
161
  modal_version/__main__.py,sha256=2FO0yYQQwDTh6udt1h-cBnGd1c4ZyHnHSI4BksxzVac,105
162
- modal_version/_version_generated.py,sha256=n6vTPP069df_S0Gqp_hCTlgHvSYzFTpcSw2VEbRd6Mo,149
163
- modal-0.67.13.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
- modal-0.67.13.dist-info/METADATA,sha256=9cCPrWPQbv5ADr9zsoeQ0TW32a2uNY12MQdaINSIuyY,2329
165
- modal-0.67.13.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
166
- modal-0.67.13.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
167
- modal-0.67.13.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
168
- modal-0.67.13.dist-info/RECORD,,
162
+ modal_version/_version_generated.py,sha256=yW74Sph3leSunGQQCrZcsTL-NaIvPoOH06ZVkpapDHU,149
163
+ modal-0.67.15.dist-info/LICENSE,sha256=psuoW8kuDP96RQsdhzwOqi6fyWv0ct8CR6Jr7He_P_k,10173
164
+ modal-0.67.15.dist-info/METADATA,sha256=w0WCe3LaidFdAW4u8XBv2gJhK23l0q-q4JPZoFLzGvQ,2329
165
+ modal-0.67.15.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
166
+ modal-0.67.15.dist-info/entry_points.txt,sha256=An-wYgeEUnm6xzrAP9_NTSTSciYvvEWsMZILtYrvpAI,46
167
+ modal-0.67.15.dist-info/top_level.txt,sha256=1nvYbOSIKcmU50fNrpnQnrrOpj269ei3LzgB6j9xGqg,64
168
+ modal-0.67.15.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  # Copyright Modal Labs 2024
2
2
 
3
3
  # Note: Reset this value to -1 whenever you make a minor `0.X` release of the client.
4
- build_number = 13 # git: b71220f
4
+ build_number = 15 # git: fb6eb81