Coverage for Lib/asyncio/streams.py: 93%

411 statements  

« prev     ^ index     » next       coverage.py v7.16.1, created at 2026-09-25 03:29 +0000

1__all__ = ( 

2 'StreamReader', 'StreamWriter', 'StreamReaderProtocol', 

3 'open_connection', 'start_server') 

4 

5import collections 

6import socket 

7import sys 

8import warnings 

9import weakref 

10 

11if hasattr(socket, 'AF_UNIX'): 11 ↛ 14line 11 didn't jump to line 14 because the condition on line 11 was always true

12 __all__ += ('open_unix_connection', 'start_unix_server') 

13 

14from . import coroutines 

15from . import events 

16from . import exceptions 

17from . import format_helpers 

18from . import protocols 

19from .log import logger 

20from .tasks import sleep 

21 

22 

23_DEFAULT_LIMIT = 2 ** 16 # 64 KiB 

24 

25 

26async def open_connection(host=None, port=None, *, 

27 limit=_DEFAULT_LIMIT, **kwds): 

28 """A wrapper for create_connection() returning a (reader, writer) pair. 

29 

30 The reader returned is a StreamReader instance; the writer is a 

31 StreamWriter instance. 

32 

33 The arguments are all the usual arguments to create_connection() 

34 except protocol_factory; most common are positional host and port, 

35 with various optional keyword arguments following. 

36 

37 Additional optional keyword arguments are loop (to set the event loop 

38 instance to use) and limit (to set the buffer limit passed to the 

39 StreamReader). 

40 

41 (If you want to customize the StreamReader and/or 

42 StreamReaderProtocol classes, just copy the code -- there's 

43 really nothing special here except some convenience.) 

44 """ 

45 loop = events.get_running_loop() 

46 reader = StreamReader(limit=limit, loop=loop) 

47 protocol = StreamReaderProtocol(reader, loop=loop) 

48 transport, _ = await loop.create_connection( 

49 lambda: protocol, host, port, **kwds) 

50 writer = StreamWriter(transport, protocol, reader, loop) 

51 return reader, writer 

52 

53 

54async def start_server(client_connected_cb, host=None, port=None, *, 

55 limit=_DEFAULT_LIMIT, **kwds): 

56 """Start a socket server, call back for each client connected. 

57 

58 The first parameter, `client_connected_cb`, takes two parameters: 

59 client_reader, client_writer. client_reader is a StreamReader 

60 object, while client_writer is a StreamWriter object. This 

61 parameter can either be a plain callback function or a coroutine; 

62 if it is a coroutine, it will be automatically converted into a 

63 Task. 

64 

65 The rest of the arguments are all the usual arguments to 

66 loop.create_server() except protocol_factory; most common are 

67 positional host and port, with various optional keyword arguments 

68 following. The return value is the same as loop.create_server(). 

69 

70 Additional optional keyword argument is limit (to set the buffer 

71 limit passed to the StreamReader). 

72 

73 The return value is the same as loop.create_server(), i.e. a 

74 Server object which can be used to stop the service. 

75 """ 

76 loop = events.get_running_loop() 

77 

78 def factory(): 

79 reader = StreamReader(limit=limit, loop=loop) 

80 protocol = StreamReaderProtocol(reader, client_connected_cb, 

81 loop=loop) 

82 return protocol 

83 

84 return await loop.create_server(factory, host, port, **kwds) 

85 

86 

87if hasattr(socket, 'AF_UNIX'): 87 ↛ 116line 87 didn't jump to line 116 because the condition on line 87 was always true

88 # UNIX Domain Sockets are supported on this platform 

89 

90 async def open_unix_connection(path=None, *, 

91 limit=_DEFAULT_LIMIT, **kwds): 

92 """Similar to `open_connection` but works with UNIX Domain Sockets.""" 

93 loop = events.get_running_loop() 

94 

95 reader = StreamReader(limit=limit, loop=loop) 

96 protocol = StreamReaderProtocol(reader, loop=loop) 

97 transport, _ = await loop.create_unix_connection( 

98 lambda: protocol, path, **kwds) 

99 writer = StreamWriter(transport, protocol, reader, loop) 

100 return reader, writer 

101 

102 async def start_unix_server(client_connected_cb, path=None, *, 

103 limit=_DEFAULT_LIMIT, **kwds): 

104 """Similar to `start_server` but works with UNIX Domain Sockets.""" 

105 loop = events.get_running_loop() 

106 

107 def factory(): 

108 reader = StreamReader(limit=limit, loop=loop) 

109 protocol = StreamReaderProtocol(reader, client_connected_cb, 

110 loop=loop) 

111 return protocol 

112 

113 return await loop.create_unix_server(factory, path, **kwds) 

114 

115 

116class FlowControlMixin(protocols.Protocol): 

117 """Reusable flow control logic for StreamWriter.drain(). 

118 

119 This implements the protocol methods pause_writing(), 

120 resume_writing() and connection_lost(). If the subclass overrides 

121 these it must call the super methods. 

122 

123 StreamWriter.drain() must wait for _drain_helper() coroutine. 

124 """ 

125 

126 def __init__(self, loop=None): 

127 if loop is None: 

128 self._loop = events.get_event_loop() 

129 else: 

130 self._loop = loop 

131 self._paused = False 

132 self._drain_waiters = collections.deque() 

133 self._connection_lost = False 

134 

135 def pause_writing(self): 

136 assert not self._paused 

137 self._paused = True 

138 if self._loop.get_debug(): 

139 logger.debug("%r pauses writing", self) 

140 

141 def resume_writing(self): 

142 assert self._paused 

143 self._paused = False 

144 if self._loop.get_debug(): 144 ↛ 145line 144 didn't jump to line 145 because the condition on line 144 was never true

145 logger.debug("%r resumes writing", self) 

146 

147 for waiter in self._drain_waiters: 

148 if not waiter.done(): 148 ↛ 147line 148 didn't jump to line 147 because the condition on line 148 was always true

149 waiter.set_result(None) 

150 

151 def connection_lost(self, exc): 

152 self._connection_lost = True 

153 # Wake up the writer(s) if currently paused. 

154 if not self._paused: 

155 return 

156 

157 for waiter in self._drain_waiters: 

158 if not waiter.done(): 

159 if exc is None: 159 ↛ 160line 159 didn't jump to line 160 because the condition on line 159 was never true

160 waiter.set_result(None) 

161 else: 

162 waiter.set_exception(exc) 

163 

164 async def _drain_helper(self): 

165 if self._connection_lost: 

166 raise ConnectionResetError('Connection lost') 

167 if not self._paused: 

168 return 

169 waiter = self._loop.create_future() 

170 self._drain_waiters.append(waiter) 

171 try: 

172 await waiter 

173 finally: 

174 self._drain_waiters.remove(waiter) 

175 

176 def _get_close_waiter(self, stream): 

177 raise NotImplementedError 

178 

179 

180class StreamReaderProtocol(FlowControlMixin, protocols.Protocol): 

181 """Helper class to adapt between Protocol and StreamReader. 

182 

183 (This is a helper class instead of making StreamReader itself a 

184 Protocol subclass, because the StreamReader has other potential 

185 uses, and to prevent the user of the StreamReader to accidentally 

186 call inappropriate methods of the protocol.) 

187 """ 

188 

189 _source_traceback = None 

190 

191 def __init__(self, stream_reader, client_connected_cb=None, loop=None): 

192 super().__init__(loop=loop) 

193 if stream_reader is not None: 193 ↛ 197line 193 didn't jump to line 197 because the condition on line 193 was always true

194 self._stream_reader_wr = weakref.ref(stream_reader) 

195 self._source_traceback = stream_reader._source_traceback 

196 else: 

197 self._stream_reader_wr = None 

198 if client_connected_cb is not None: 

199 # This is a stream created by the `create_server()` function. 

200 # Keep a strong reference to the reader until a connection 

201 # is established. 

202 self._strong_reader = stream_reader 

203 self._reject_connection = False 

204 self._task = None 

205 self._transport = None 

206 self._client_connected_cb = client_connected_cb 

207 self._over_ssl = False 

208 self._closed = self._loop.create_future() 

209 

210 @property 

211 def _stream_reader(self): 

212 if self._stream_reader_wr is None: 

213 return None 

214 return self._stream_reader_wr() 

215 

216 def _replace_transport(self, transport): 

217 self._transport = transport 

218 self._over_ssl = transport.get_extra_info('sslcontext') is not None 

219 reader = self._stream_reader 

220 if reader is not None: 220 ↛ exitline 220 didn't return from function '_replace_transport' because the condition on line 220 was always true

221 reader._replace_transport(transport) 

222 

223 def connection_made(self, transport): 

224 if self._reject_connection: 224 ↛ 225line 224 didn't jump to line 225 because the condition on line 224 was never true

225 context = { 

226 'message': ('An open stream was garbage collected prior to ' 

227 'establishing network connection; ' 

228 'call "stream.close()" explicitly.') 

229 } 

230 if self._source_traceback: 

231 context['source_traceback'] = self._source_traceback 

232 self._loop.call_exception_handler(context) 

233 transport.abort() 

234 return 

235 self._transport = transport 

236 reader = self._stream_reader 

237 if reader is not None: 237 ↛ 239line 237 didn't jump to line 239 because the condition on line 237 was always true

238 reader.set_transport(transport) 

239 self._over_ssl = transport.get_extra_info('sslcontext') is not None 

240 if self._client_connected_cb is not None: 

241 writer = StreamWriter(transport, self, reader, self._loop) 

242 try: 

243 res = self._client_connected_cb(reader, writer) 

244 except Exception as exc: 

245 self._loop.call_exception_handler({ 

246 'message': 'Unhandled exception in client_connected_cb', 

247 'exception': exc, 

248 'transport': transport, 

249 }) 

250 transport.close() 

251 self._strong_reader = None 

252 return 

253 if coroutines.iscoroutine(res): 

254 def callback(task): 

255 if task.cancelled(): 

256 transport.close() 

257 return 

258 exc = task.exception() 

259 if exc is not None: 

260 self._loop.call_exception_handler({ 

261 'message': 'Unhandled exception in client_connected_cb', 

262 'exception': exc, 

263 'transport': transport, 

264 }) 

265 transport.close() 

266 

267 self._task = self._loop.create_task(res) 

268 self._task.add_done_callback(callback) 

269 

270 self._strong_reader = None 

271 

272 def connection_lost(self, exc): 

273 reader = self._stream_reader 

274 if reader is not None: 

275 if exc is None: 

276 reader.feed_eof() 

277 else: 

278 reader.set_exception(exc) 

279 if not self._closed.done(): 

280 if exc is None: 

281 self._closed.set_result(None) 

282 else: 

283 self._closed.set_exception(exc) 

284 super().connection_lost(exc) 

285 self._stream_reader_wr = None 

286 self._task = None 

287 self._transport = None 

288 

289 def data_received(self, data): 

290 reader = self._stream_reader 

291 if reader is not None: 291 ↛ exitline 291 didn't return from function 'data_received' because the condition on line 291 was always true

292 reader.feed_data(data) 

293 

294 def eof_received(self): 

295 reader = self._stream_reader 

296 if reader is not None: 

297 reader.feed_eof() 

298 if self._over_ssl: 

299 # Prevent a warning in SSLProtocol.eof_received: 

300 # "returning true from eof_received() 

301 # has no effect when using ssl" 

302 return False 

303 return True 

304 

305 def _get_close_waiter(self, stream): 

306 return self._closed 

307 

308 def __del__(self): 

309 # Prevent reports about unhandled exceptions. 

310 # Better than self._closed._log_traceback = False hack 

311 try: 

312 closed = self._closed 

313 except AttributeError: 

314 pass # failed constructor 

315 else: 

316 if closed.done() and not closed.cancelled(): 

317 closed.exception() 

318 

319 

320class StreamWriter: 

321 """Wraps a Transport. 

322 

323 This exposes write(), writelines(), [can_]write_eof(), 

324 get_extra_info() and close(). It adds drain() which returns an 

325 optional Future on which you can wait for flow control. It also 

326 adds a transport property which references the Transport 

327 directly. 

328 """ 

329 

330 def __init__(self, transport, protocol, reader, loop): 

331 self._transport = transport 

332 self._protocol = protocol 

333 # drain() expects that the reader has an exception() method 

334 assert reader is None or isinstance(reader, StreamReader) 

335 self._reader = reader 

336 self._loop = loop 

337 

338 def __repr__(self): 

339 info = [self.__class__.__name__, f'transport={self._transport!r}'] 

340 if self._reader is not None: 340 ↛ 342line 340 didn't jump to line 342 because the condition on line 340 was always true

341 info.append(f'reader={self._reader!r}') 

342 return '<{}>'.format(' '.join(info)) 

343 

344 @property 

345 def transport(self): 

346 return self._transport 

347 

348 def write(self, data): 

349 self._transport.write(data) 

350 

351 def writelines(self, data): 

352 self._transport.writelines(data) 

353 

354 def write_eof(self): 

355 return self._transport.write_eof() 

356 

357 def can_write_eof(self): 

358 return self._transport.can_write_eof() 

359 

360 def close(self): 

361 return self._transport.close() 

362 

363 def is_closing(self): 

364 return self._transport.is_closing() 

365 

366 async def wait_closed(self): 

367 await self._protocol._get_close_waiter(self) 

368 

369 def get_extra_info(self, name, default=None): 

370 return self._transport.get_extra_info(name, default) 

371 

372 async def drain(self): 

373 """Flush the write buffer. 

374 

375 The intended use is to write 

376 

377 w.write(data) 

378 await w.drain() 

379 """ 

380 if self._reader is not None: 

381 exc = self._reader.exception() 

382 if exc is not None: 382 ↛ 383line 382 didn't jump to line 383 because the condition on line 382 was never true

383 raise exc 

384 if self._transport.is_closing(): 

385 # Wait for protocol.connection_lost() call 

386 # Raise connection closing error if any, 

387 # ConnectionResetError otherwise 

388 # Yield to the event loop so connection_lost() may be 

389 # called. Without this, _drain_helper() would return 

390 # immediately, and code that calls 

391 # write(...); await drain() 

392 # in a loop would never call connection_lost(), so it 

393 # would not see an error when the socket is closed. 

394 await sleep(0) 

395 await self._protocol._drain_helper() 

396 

397 async def start_tls(self, sslcontext, *, 

398 server_hostname=None, 

399 ssl_handshake_timeout=None, 

400 ssl_shutdown_timeout=None): 

401 """Upgrade an existing stream-based connection to TLS.""" 

402 server_side = self._protocol._client_connected_cb is not None 

403 protocol = self._protocol 

404 await self.drain() 

405 new_transport = await self._loop.start_tls( # type: ignore 

406 self._transport, protocol, sslcontext, 

407 server_side=server_side, server_hostname=server_hostname, 

408 ssl_handshake_timeout=ssl_handshake_timeout, 

409 ssl_shutdown_timeout=ssl_shutdown_timeout) 

410 self._transport = new_transport 

411 protocol._replace_transport(new_transport) 

412 

413 def __del__(self, warnings=warnings): 

414 if not self._transport.is_closing(): 

415 if self._loop.is_closed(): 415 ↛ 416line 415 didn't jump to line 416 because the condition on line 415 was never true

416 warnings.warn("loop is closed", ResourceWarning) 

417 else: 

418 self.close() 

419 warnings.warn(f"unclosed {self!r}", ResourceWarning) 

420 

421class StreamReader: 

422 

423 _source_traceback = None 

424 

425 def __init__(self, limit=_DEFAULT_LIMIT, loop=None): 

426 # The line length limit is a security feature; 

427 # it also doubles as half the buffer limit. 

428 

429 if limit <= 0: 

430 raise ValueError('Limit cannot be <= 0') 

431 

432 self._limit = limit 

433 if loop is None: 

434 self._loop = events.get_event_loop() 

435 else: 

436 self._loop = loop 

437 self._buffer = bytearray() 

438 self._eof = False # Whether we're done. 

439 self._waiter = None # A future used by _wait_for_data() 

440 self._exception = None 

441 self._transport = None 

442 self._paused = False 

443 if self._loop.get_debug(): 

444 self._source_traceback = format_helpers.extract_stack( 

445 sys._getframe(1)) 

446 

447 def __repr__(self): 

448 info = ['StreamReader'] 

449 if self._buffer: 

450 info.append(f'{len(self._buffer)} bytes') 

451 if self._eof: 

452 info.append('eof') 

453 if self._limit != _DEFAULT_LIMIT: 

454 info.append(f'limit={self._limit}') 

455 if self._waiter: 

456 info.append(f'waiter={self._waiter!r}') 

457 if self._exception: 

458 info.append(f'exception={self._exception!r}') 

459 if self._transport: 

460 info.append(f'transport={self._transport!r}') 

461 if self._paused: 461 ↛ 462line 461 didn't jump to line 462 because the condition on line 461 was never true

462 info.append('paused') 

463 return '<{}>'.format(' '.join(info)) 

464 

465 def exception(self): 

466 return self._exception 

467 

468 def set_exception(self, exc): 

469 self._exception = exc 

470 

471 waiter = self._waiter 

472 if waiter is not None: 

473 self._waiter = None 

474 if not waiter.cancelled(): 474 ↛ exitline 474 didn't return from function 'set_exception' because the condition on line 474 was always true

475 waiter.set_exception(exc) 

476 

477 def _wakeup_waiter(self): 

478 """Wakeup read*() functions waiting for data or EOF.""" 

479 waiter = self._waiter 

480 if waiter is not None: 

481 self._waiter = None 

482 if not waiter.cancelled(): 482 ↛ exitline 482 didn't return from function '_wakeup_waiter' because the condition on line 482 was always true

483 waiter.set_result(None) 

484 

485 def set_transport(self, transport): 

486 assert self._transport is None, 'Transport already set' 

487 self._transport = transport 

488 

489 def _replace_transport(self, transport): 

490 assert self._transport is not None, 'Transport not set' 

491 self._transport = transport 

492 

493 def _maybe_resume_transport(self): 

494 if self._paused and len(self._buffer) <= self._limit: 

495 self._paused = False 

496 self._transport.resume_reading() 

497 

498 def feed_eof(self): 

499 self._eof = True 

500 self._wakeup_waiter() 

501 

502 def at_eof(self): 

503 """Return True if the buffer is empty and 'feed_eof' was called.""" 

504 return self._eof and not self._buffer 

505 

506 def feed_data(self, data): 

507 assert not self._eof, 'feed_data after feed_eof' 

508 

509 if not data: 

510 return 

511 

512 self._buffer.extend(data) 

513 self._wakeup_waiter() 

514 

515 if (self._transport is not None and 

516 not self._paused and 

517 len(self._buffer) > 2 * self._limit): 

518 try: 

519 self._transport.pause_reading() 

520 except NotImplementedError: 

521 # The transport can't be paused. 

522 # We'll just have to buffer all data. 

523 # Forget the transport so we don't keep trying. 

524 self._transport = None 

525 else: 

526 self._paused = True 

527 

528 async def _wait_for_data(self, func_name): 

529 """Wait until feed_data() or feed_eof() is called. 

530 

531 If stream was paused, automatically resume it. 

532 """ 

533 # StreamReader uses a future to link the protocol feed_data() method 

534 # to a read coroutine. Running two read coroutines at the same time 

535 # would have an unexpected behaviour. It would not possible to know 

536 # which coroutine would get the next data. 

537 if self._waiter is not None: 537 ↛ 538line 537 didn't jump to line 538 because the condition on line 537 was never true

538 raise RuntimeError( 

539 f'{func_name}() called while another coroutine is ' 

540 f'already waiting for incoming data') 

541 

542 assert not self._eof, '_wait_for_data after EOF' 

543 

544 # Waiting for data while paused will make deadlock, so prevent it. 

545 # This is essential for readexactly(n) for case when n > self._limit. 

546 if self._paused: 546 ↛ 547line 546 didn't jump to line 547 because the condition on line 546 was never true

547 self._paused = False 

548 self._transport.resume_reading() 

549 

550 self._waiter = self._loop.create_future() 

551 try: 

552 await self._waiter 

553 finally: 

554 self._waiter = None 

555 

556 async def readline(self): 

557 r"""Read chunk of data from the stream until newline (b'\n') is found. 

558 

559 On success, return chunk that ends with newline. If only partial 

560 line can be read due to EOF, return incomplete line without 

561 terminating newline. When EOF was reached while no bytes read, 

562 empty bytes object is returned. 

563 

564 If limit is reached, ValueError will be raised. In that case, if 

565 newline was found, complete line including newline will be removed 

566 from internal buffer. Else, internal buffer will be cleared. 

567 Limit is compared against part of the line without newline. 

568 

569 If stream was paused, this function will automatically resume it if 

570 needed. 

571 """ 

572 sep = b'\n' 

573 seplen = len(sep) 

574 try: 

575 line = await self.readuntil(sep) 

576 except exceptions.IncompleteReadError as e: 

577 return e.partial 

578 except exceptions.LimitOverrunError as e: 

579 if self._buffer.startswith(sep, e.consumed): 

580 del self._buffer[:e.consumed + seplen] 

581 else: 

582 self._buffer.clear() 

583 self._maybe_resume_transport() 

584 raise ValueError(e.args[0]) 

585 return line 

586 

587 async def readuntil(self, separator=b'\n'): 

588 """Read data from the stream until ``separator`` is found. 

589 

590 On success, the data and separator will be removed from the 

591 internal buffer (consumed). Returned data will include the 

592 separator at the end. 

593 

594 Configured stream limit is used to check result. Limit sets the 

595 maximal length of data that can be returned, not counting the 

596 separator. 

597 

598 If an EOF occurs and the complete separator is still not found, 

599 an IncompleteReadError exception will be raised, and the internal 

600 buffer will be reset. The IncompleteReadError.partial attribute 

601 may contain the separator partially. 

602 

603 If the data cannot be read because of over limit, a 

604 LimitOverrunError exception will be raised, and the data 

605 will be left in the internal buffer, so it can be read again. 

606 

607 The ``separator`` may also be a tuple of separators. In this 

608 case the return value will be the shortest possible that has any 

609 separator as the suffix. For the purposes of LimitOverrunError, 

610 the shortest possible separator is considered to be the one that 

611 matched. 

612 """ 

613 if isinstance(separator, tuple): 

614 # Makes sure shortest matches wins 

615 separator = sorted(separator, key=len) 

616 else: 

617 separator = [separator] 

618 if not separator: 

619 raise ValueError('Separator should contain at least one element') 

620 min_seplen = len(separator[0]) 

621 max_seplen = len(separator[-1]) 

622 if min_seplen == 0: 

623 raise ValueError('Separator should be at least one-byte string') 

624 

625 if self._exception is not None: 

626 raise self._exception 

627 

628 # Consume whole buffer except last bytes, which length is 

629 # one less than max_seplen. Let's check corner cases with 

630 # separator[-1]='SEPARATOR': 

631 # * we have received almost complete separator (without last 

632 # byte). i.e buffer='some textSEPARATO'. In this case we 

633 # can safely consume max_seplen - 1 bytes. 

634 # * last byte of buffer is first byte of separator, i.e. 

635 # buffer='abcdefghijklmnopqrS'. We may safely consume 

636 # everything except that last byte, but this require to 

637 # analyze bytes of buffer that match partial separator. 

638 # This is slow and/or require FSM. For this case our 

639 # implementation is not optimal, since require rescanning 

640 # of data that is known to not belong to separator. In 

641 # real world, separator will not be so long to notice 

642 # performance problems. Even when reading MIME-encoded 

643 # messages :) 

644 

645 # `offset` is the number of bytes from the beginning of the buffer 

646 # where there is no occurrence of any `separator`. 

647 offset = 0 

648 

649 # Loop until we find a `separator` in the buffer, exceed the buffer size, 

650 # or an EOF has happened. 

651 while True: 

652 buflen = len(self._buffer) 

653 

654 # Check if we now have enough data in the buffer for shortest 

655 # separator to fit. 

656 if buflen - offset >= min_seplen: 

657 match_start = None 

658 match_end = None 

659 for sep in separator: 

660 isep = self._buffer.find(sep, offset) 

661 

662 if isep != -1: 

663 # `separator` is in the buffer. `match_start` and 

664 # `match_end` will be used later to retrieve the 

665 # data. 

666 end = isep + len(sep) 

667 if match_end is None or end < match_end: 

668 match_end = end 

669 match_start = isep 

670 if match_end is not None: 

671 break 

672 

673 # see upper comment for explanation. 

674 offset = max(0, buflen + 1 - max_seplen) 

675 if offset > self._limit: 

676 raise exceptions.LimitOverrunError( 

677 'Separator is not found, and chunk exceed the limit', 

678 offset) 

679 

680 # Complete message (with full separator) may be present in buffer 

681 # even when EOF flag is set. This may happen when the last chunk 

682 # adds data which makes separator be found. That's why we check for 

683 # EOF *after* inspecting the buffer. 

684 if self._eof: 

685 chunk = self._buffer.take_bytes() 

686 raise exceptions.IncompleteReadError(chunk, None) 

687 

688 # _wait_for_data() will resume reading if stream was paused. 

689 await self._wait_for_data('readuntil') 

690 

691 if match_start > self._limit: 

692 raise exceptions.LimitOverrunError( 

693 'Separator is found, but chunk is longer than limit', match_start) 

694 

695 chunk = self._buffer.take_bytes(match_end) 

696 self._maybe_resume_transport() 

697 return chunk 

698 

699 async def read(self, n=-1): 

700 """Read up to `n` bytes from the stream. 

701 

702 If `n` is not provided or set to -1, 

703 read until EOF, then return all read bytes. 

704 If EOF was received and the internal buffer is empty, 

705 return an empty bytes object. 

706 

707 If `n` is 0, return an empty bytes object immediately. 

708 

709 If `n` is positive, return at most `n` available bytes 

710 as soon as at least 1 byte is available in the internal buffer. 

711 If EOF is received before any byte is read, return an empty 

712 bytes object. 

713 

714 Returned value is not limited with limit, configured at stream 

715 creation. 

716 

717 If stream was paused, this function will automatically resume it if 

718 needed. 

719 """ 

720 

721 if self._exception is not None: 

722 raise self._exception 

723 

724 if n == 0: 

725 return b'' 

726 

727 if n < 0: 

728 # This used to just loop creating a new waiter hoping to 

729 # collect everything in self._buffer, but that would 

730 # deadlock if the subprocess sends more than self.limit 

731 # bytes. So just call self.read(self._limit) until EOF. 

732 joined = bytearray() 

733 while block := await self.read(self._limit): 

734 joined += block 

735 return joined.take_bytes() 

736 

737 if not self._buffer and not self._eof: 

738 await self._wait_for_data('read') 

739 

740 # This will work right even if buffer is less than n bytes 

741 data = self._buffer.take_bytes(min(len(self._buffer), n)) 

742 

743 self._maybe_resume_transport() 

744 return data 

745 

746 async def readexactly(self, n): 

747 """Read exactly `n` bytes. 

748 

749 Raise an IncompleteReadError if EOF is reached before `n` bytes can be 

750 read. The IncompleteReadError.partial attribute of the exception will 

751 contain the partial read bytes. 

752 

753 if n is zero, return empty bytes object. 

754 

755 Returned value is not limited with limit, configured at stream 

756 creation. 

757 

758 If stream was paused, this function will automatically resume it if 

759 needed. 

760 """ 

761 if n < 0: 

762 raise ValueError('readexactly size can not be less than zero') 

763 

764 if self._exception is not None: 

765 raise self._exception 

766 

767 if n == 0: 

768 return b'' 

769 

770 while len(self._buffer) < n: 

771 if self._eof: 

772 incomplete = self._buffer.take_bytes() 

773 raise exceptions.IncompleteReadError(incomplete, n) 

774 

775 await self._wait_for_data('readexactly') 

776 

777 data = self._buffer.take_bytes(n) 

778 self._maybe_resume_transport() 

779 return data 

780 

781 def __aiter__(self): 

782 return self 

783 

784 async def __anext__(self): 

785 val = await self.readline() 

786 if val == b'': 

787 raise StopAsyncIteration 

788 return val