modal 1.0.5.dev1__py3-none-any.whl → 1.0.5.dev3__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/io_streams.pyi CHANGED
@@ -14,6 +14,27 @@ def _container_process_logs_iterator(
14
14
  T = typing.TypeVar("T")
15
15
 
16
16
  class _StreamReader(typing.Generic[T]):
17
+ """Retrieve logs from a stream (`stdout` or `stderr`).
18
+
19
+ As an asynchronous iterable, the object supports the `for` and `async for`
20
+ statements. Just loop over the object to read in chunks.
21
+
22
+ **Usage**
23
+
24
+ ```python fixture:running_app
25
+ from modal import Sandbox
26
+
27
+ sandbox = Sandbox.create(
28
+ "bash",
29
+ "-c",
30
+ "for i in $(seq 1 10); do echo foo; sleep 0.1; done",
31
+ app=running_app,
32
+ )
33
+ for message in sandbox.stdout:
34
+ print(f"Message: {message}")
35
+ ```
36
+ """
37
+
17
38
  _stream: typing.Optional[collections.abc.AsyncGenerator[typing.Optional[bytes], None]]
18
39
 
19
40
  def __init__(
@@ -25,34 +46,159 @@ class _StreamReader(typing.Generic[T]):
25
46
  stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
26
47
  text: bool = True,
27
48
  by_line: bool = False,
28
- ) -> None: ...
49
+ ) -> None:
50
+ """mdmd:hidden"""
51
+ ...
52
+
29
53
  @property
30
- def file_descriptor(self) -> int: ...
31
- async def read(self) -> T: ...
32
- async def _consume_container_process_stream(self): ...
33
- def _stream_container_process(self) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
54
+ def file_descriptor(self) -> int:
55
+ """Possible values are `1` for stdout and `2` for stderr."""
56
+ ...
57
+
58
+ async def read(self) -> T:
59
+ """Fetch the entire contents of the stream until EOF.
60
+
61
+ **Usage**
62
+
63
+ ```python fixture:running_app
64
+ from modal import Sandbox
65
+
66
+ sandbox = Sandbox.create("echo", "hello", app=running_app)
67
+ sandbox.wait()
68
+
69
+ print(sandbox.stdout.read())
70
+ ```
71
+ """
72
+ ...
73
+
74
+ async def _consume_container_process_stream(self):
75
+ """Consume the container process stream and store messages in the buffer."""
76
+ ...
77
+
78
+ def _stream_container_process(self) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]:
79
+ """Streams the container process buffer to the reader."""
80
+ ...
81
+
34
82
  def _get_logs(
35
83
  self, skip_empty_messages: bool = True
36
- ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
37
- def _get_logs_by_line(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
38
- def __aiter__(self) -> collections.abc.AsyncIterator[T]: ...
39
- async def __anext__(self) -> T: ...
40
- async def aclose(self): ...
84
+ ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]:
85
+ """Streams sandbox or process logs from the server to the reader.
86
+
87
+ Logs returned by this method may contain partial or multiple lines at a time.
88
+
89
+ When the stream receives an EOF, it yields None. Once an EOF is received,
90
+ subsequent invocations will not yield logs.
91
+ """
92
+ ...
93
+
94
+ def _get_logs_by_line(self) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]:
95
+ """Process logs from the server and yield complete lines only."""
96
+ ...
97
+
98
+ def __aiter__(self) -> collections.abc.AsyncIterator[T]:
99
+ """mdmd:hidden"""
100
+ ...
101
+
102
+ async def __anext__(self) -> T:
103
+ """mdmd:hidden"""
104
+ ...
105
+
106
+ async def aclose(self):
107
+ """mdmd:hidden"""
108
+ ...
41
109
 
42
110
  class _StreamWriter:
111
+ """Provides an interface to buffer and write logs to a sandbox or container process stream (`stdin`)."""
43
112
  def __init__(
44
113
  self, object_id: str, object_type: typing.Literal["sandbox", "container_process"], client: modal.client._Client
45
- ) -> None: ...
114
+ ) -> None:
115
+ """mdmd:hidden"""
116
+ ...
117
+
46
118
  def _get_next_index(self) -> int: ...
47
- def write(self, data: typing.Union[bytes, bytearray, memoryview, str]) -> None: ...
48
- def write_eof(self) -> None: ...
49
- async def drain(self) -> None: ...
119
+ def write(self, data: typing.Union[bytes, bytearray, memoryview, str]) -> None:
120
+ """Write data to the stream but does not send it immediately.
121
+
122
+ This is non-blocking and queues the data to an internal buffer. Must be
123
+ used along with the `drain()` method, which flushes the buffer.
124
+
125
+ **Usage**
126
+
127
+ ```python fixture:running_app
128
+ from modal import Sandbox
129
+
130
+ sandbox = Sandbox.create(
131
+ "bash",
132
+ "-c",
133
+ "while read line; do echo $line; done",
134
+ app=running_app,
135
+ )
136
+ sandbox.stdin.write(b"foo\n")
137
+ sandbox.stdin.write(b"bar\n")
138
+ sandbox.stdin.write_eof()
139
+
140
+ sandbox.stdin.drain()
141
+ sandbox.wait()
142
+ ```
143
+ """
144
+ ...
145
+
146
+ def write_eof(self) -> None:
147
+ """Close the write end of the stream after the buffered data is drained.
148
+
149
+ If the process was blocked on input, it will become unblocked after
150
+ `write_eof()`. This method needs to be used along with the `drain()`
151
+ method, which flushes the EOF to the process.
152
+ """
153
+ ...
154
+
155
+ async def drain(self) -> None:
156
+ """Flush the write buffer and send data to the running process.
157
+
158
+ This is a flow control method that blocks until data is sent. It returns
159
+ when it is appropriate to continue writing data to the stream.
160
+
161
+ **Usage**
162
+
163
+ ```python notest
164
+ writer.write(data)
165
+ writer.drain()
166
+ ```
167
+
168
+ Async usage:
169
+ ```python notest
170
+ writer.write(data) # not a blocking operation
171
+ await writer.drain.aio()
172
+ ```
173
+ """
174
+ ...
50
175
 
51
176
  T_INNER = typing.TypeVar("T_INNER", covariant=True)
52
177
 
53
178
  SUPERSELF = typing.TypeVar("SUPERSELF", covariant=True)
54
179
 
55
180
  class StreamReader(typing.Generic[T]):
181
+ """Retrieve logs from a stream (`stdout` or `stderr`).
182
+
183
+ As an asynchronous iterable, the object supports the `for` and `async for`
184
+ statements. Just loop over the object to read in chunks.
185
+
186
+ **Usage**
187
+
188
+ ```python fixture:running_app
189
+ from modal import Sandbox
190
+
191
+ sandbox = Sandbox.create(
192
+ "bash",
193
+ "-c",
194
+ "for i in $(seq 1 10); do echo foo; sleep 0.1; done",
195
+ app=running_app,
196
+ )
197
+ for message in sandbox.stdout:
198
+ print(f"Message: {message}")
199
+ ```
200
+ """
201
+
56
202
  _stream: typing.Optional[collections.abc.AsyncGenerator[typing.Optional[bytes], None]]
57
203
 
58
204
  def __init__(
@@ -64,61 +210,218 @@ class StreamReader(typing.Generic[T]):
64
210
  stream_type: modal.stream_type.StreamType = modal.stream_type.StreamType.PIPE,
65
211
  text: bool = True,
66
212
  by_line: bool = False,
67
- ) -> None: ...
213
+ ) -> None:
214
+ """mdmd:hidden"""
215
+ ...
216
+
68
217
  @property
69
- def file_descriptor(self) -> int: ...
218
+ def file_descriptor(self) -> int:
219
+ """Possible values are `1` for stdout and `2` for stderr."""
220
+ ...
70
221
 
71
222
  class __read_spec(typing_extensions.Protocol[T_INNER, SUPERSELF]):
72
- def __call__(self, /) -> T_INNER: ...
73
- async def aio(self, /) -> T_INNER: ...
223
+ def __call__(self, /) -> T_INNER:
224
+ """Fetch the entire contents of the stream until EOF.
225
+
226
+ **Usage**
227
+
228
+ ```python fixture:running_app
229
+ from modal import Sandbox
230
+
231
+ sandbox = Sandbox.create("echo", "hello", app=running_app)
232
+ sandbox.wait()
233
+
234
+ print(sandbox.stdout.read())
235
+ ```
236
+ """
237
+ ...
238
+
239
+ async def aio(self, /) -> T_INNER:
240
+ """Fetch the entire contents of the stream until EOF.
241
+
242
+ **Usage**
243
+
244
+ ```python fixture:running_app
245
+ from modal import Sandbox
246
+
247
+ sandbox = Sandbox.create("echo", "hello", app=running_app)
248
+ sandbox.wait()
249
+
250
+ print(sandbox.stdout.read())
251
+ ```
252
+ """
253
+ ...
74
254
 
75
255
  read: __read_spec[T, typing_extensions.Self]
76
256
 
77
257
  class ___consume_container_process_stream_spec(typing_extensions.Protocol[SUPERSELF]):
78
- def __call__(self, /): ...
79
- async def aio(self, /): ...
258
+ def __call__(self, /):
259
+ """Consume the container process stream and store messages in the buffer."""
260
+ ...
261
+
262
+ async def aio(self, /):
263
+ """Consume the container process stream and store messages in the buffer."""
264
+ ...
80
265
 
81
266
  _consume_container_process_stream: ___consume_container_process_stream_spec[typing_extensions.Self]
82
267
 
83
268
  class ___stream_container_process_spec(typing_extensions.Protocol[SUPERSELF]):
84
- def __call__(self, /) -> typing.Generator[tuple[typing.Optional[bytes], str], None, None]: ...
85
- def aio(self, /) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]: ...
269
+ def __call__(self, /) -> typing.Generator[tuple[typing.Optional[bytes], str], None, None]:
270
+ """Streams the container process buffer to the reader."""
271
+ ...
272
+
273
+ def aio(self, /) -> collections.abc.AsyncGenerator[tuple[typing.Optional[bytes], str], None]:
274
+ """Streams the container process buffer to the reader."""
275
+ ...
86
276
 
87
277
  _stream_container_process: ___stream_container_process_spec[typing_extensions.Self]
88
278
 
89
279
  class ___get_logs_spec(typing_extensions.Protocol[SUPERSELF]):
90
- def __call__(
91
- self, /, skip_empty_messages: bool = True
92
- ) -> typing.Generator[typing.Optional[bytes], None, None]: ...
280
+ def __call__(self, /, skip_empty_messages: bool = True) -> typing.Generator[typing.Optional[bytes], None, None]:
281
+ """Streams sandbox or process logs from the server to the reader.
282
+
283
+ Logs returned by this method may contain partial or multiple lines at a time.
284
+
285
+ When the stream receives an EOF, it yields None. Once an EOF is received,
286
+ subsequent invocations will not yield logs.
287
+ """
288
+ ...
289
+
93
290
  def aio(
94
291
  self, /, skip_empty_messages: bool = True
95
- ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
292
+ ) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]:
293
+ """Streams sandbox or process logs from the server to the reader.
294
+
295
+ Logs returned by this method may contain partial or multiple lines at a time.
296
+
297
+ When the stream receives an EOF, it yields None. Once an EOF is received,
298
+ subsequent invocations will not yield logs.
299
+ """
300
+ ...
96
301
 
97
302
  _get_logs: ___get_logs_spec[typing_extensions.Self]
98
303
 
99
304
  class ___get_logs_by_line_spec(typing_extensions.Protocol[SUPERSELF]):
100
- def __call__(self, /) -> typing.Generator[typing.Optional[bytes], None, None]: ...
101
- def aio(self, /) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]: ...
305
+ def __call__(self, /) -> typing.Generator[typing.Optional[bytes], None, None]:
306
+ """Process logs from the server and yield complete lines only."""
307
+ ...
308
+
309
+ def aio(self, /) -> collections.abc.AsyncGenerator[typing.Optional[bytes], None]:
310
+ """Process logs from the server and yield complete lines only."""
311
+ ...
102
312
 
103
313
  _get_logs_by_line: ___get_logs_by_line_spec[typing_extensions.Self]
104
314
 
105
- def __iter__(self) -> typing.Iterator[T]: ...
106
- def __aiter__(self) -> collections.abc.AsyncIterator[T]: ...
107
- def __next__(self) -> T: ...
108
- async def __anext__(self) -> T: ...
109
- def close(self): ...
110
- async def aclose(self): ...
315
+ def __iter__(self) -> typing.Iterator[T]:
316
+ """mdmd:hidden"""
317
+ ...
318
+
319
+ def __aiter__(self) -> collections.abc.AsyncIterator[T]:
320
+ """mdmd:hidden"""
321
+ ...
322
+
323
+ def __next__(self) -> T:
324
+ """mdmd:hidden"""
325
+ ...
326
+
327
+ async def __anext__(self) -> T:
328
+ """mdmd:hidden"""
329
+ ...
330
+
331
+ def close(self):
332
+ """mdmd:hidden"""
333
+ ...
334
+
335
+ async def aclose(self):
336
+ """mdmd:hidden"""
337
+ ...
111
338
 
112
339
  class StreamWriter:
340
+ """Provides an interface to buffer and write logs to a sandbox or container process stream (`stdin`)."""
113
341
  def __init__(
114
342
  self, object_id: str, object_type: typing.Literal["sandbox", "container_process"], client: modal.client.Client
115
- ) -> None: ...
343
+ ) -> None:
344
+ """mdmd:hidden"""
345
+ ...
346
+
116
347
  def _get_next_index(self) -> int: ...
117
- def write(self, data: typing.Union[bytes, bytearray, memoryview, str]) -> None: ...
118
- def write_eof(self) -> None: ...
348
+ def write(self, data: typing.Union[bytes, bytearray, memoryview, str]) -> None:
349
+ """Write data to the stream but does not send it immediately.
350
+
351
+ This is non-blocking and queues the data to an internal buffer. Must be
352
+ used along with the `drain()` method, which flushes the buffer.
353
+
354
+ **Usage**
355
+
356
+ ```python fixture:running_app
357
+ from modal import Sandbox
358
+
359
+ sandbox = Sandbox.create(
360
+ "bash",
361
+ "-c",
362
+ "while read line; do echo $line; done",
363
+ app=running_app,
364
+ )
365
+ sandbox.stdin.write(b"foo\n")
366
+ sandbox.stdin.write(b"bar\n")
367
+ sandbox.stdin.write_eof()
368
+
369
+ sandbox.stdin.drain()
370
+ sandbox.wait()
371
+ ```
372
+ """
373
+ ...
374
+
375
+ def write_eof(self) -> None:
376
+ """Close the write end of the stream after the buffered data is drained.
377
+
378
+ If the process was blocked on input, it will become unblocked after
379
+ `write_eof()`. This method needs to be used along with the `drain()`
380
+ method, which flushes the EOF to the process.
381
+ """
382
+ ...
119
383
 
120
384
  class __drain_spec(typing_extensions.Protocol[SUPERSELF]):
121
- def __call__(self, /) -> None: ...
122
- async def aio(self, /) -> None: ...
385
+ def __call__(self, /) -> None:
386
+ """Flush the write buffer and send data to the running process.
387
+
388
+ This is a flow control method that blocks until data is sent. It returns
389
+ when it is appropriate to continue writing data to the stream.
390
+
391
+ **Usage**
392
+
393
+ ```python notest
394
+ writer.write(data)
395
+ writer.drain()
396
+ ```
397
+
398
+ Async usage:
399
+ ```python notest
400
+ writer.write(data) # not a blocking operation
401
+ await writer.drain.aio()
402
+ ```
403
+ """
404
+ ...
405
+
406
+ async def aio(self, /) -> None:
407
+ """Flush the write buffer and send data to the running process.
408
+
409
+ This is a flow control method that blocks until data is sent. It returns
410
+ when it is appropriate to continue writing data to the stream.
411
+
412
+ **Usage**
413
+
414
+ ```python notest
415
+ writer.write(data)
416
+ writer.drain()
417
+ ```
418
+
419
+ Async usage:
420
+ ```python notest
421
+ writer.write(data) # not a blocking operation
422
+ await writer.drain.aio()
423
+ ```
424
+ """
425
+ ...
123
426
 
124
427
  drain: __drain_spec[typing_extensions.Self]