Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/aiohttp/client.py: 55%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

611 statements  

1"""HTTP Client for asyncio.""" 

2 

3import asyncio 

4import base64 

5import hashlib 

6import json 

7import os 

8import sys 

9import traceback 

10import warnings 

11from contextlib import suppress 

12from types import TracebackType 

13from typing import ( 

14 TYPE_CHECKING, 

15 Any, 

16 Awaitable, 

17 Callable, 

18 Coroutine, 

19 Final, 

20 FrozenSet, 

21 Generator, 

22 Generic, 

23 Iterable, 

24 List, 

25 Mapping, 

26 Optional, 

27 Sequence, 

28 Set, 

29 Tuple, 

30 Type, 

31 TypedDict, 

32 TypeVar, 

33 Union, 

34) 

35 

36import attr 

37from multidict import CIMultiDict, MultiDict, MultiDictProxy, istr 

38from yarl import URL 

39 

40from . import hdrs, http, payload 

41from ._websocket.reader import WebSocketDataQueue 

42from .abc import AbstractCookieJar 

43from .client_exceptions import ( 

44 ClientConnectionError, 

45 ClientConnectionResetError, 

46 ClientConnectorCertificateError, 

47 ClientConnectorDNSError, 

48 ClientConnectorError, 

49 ClientConnectorSSLError, 

50 ClientError, 

51 ClientHttpProxyError, 

52 ClientOSError, 

53 ClientPayloadError, 

54 ClientProxyConnectionError, 

55 ClientResponseError, 

56 ClientSSLError, 

57 ConnectionTimeoutError, 

58 ContentTypeError, 

59 InvalidURL, 

60 InvalidUrlClientError, 

61 InvalidUrlRedirectClientError, 

62 NonHttpUrlClientError, 

63 NonHttpUrlRedirectClientError, 

64 RedirectClientError, 

65 ServerConnectionError, 

66 ServerDisconnectedError, 

67 ServerFingerprintMismatch, 

68 ServerTimeoutError, 

69 SocketTimeoutError, 

70 TooManyRedirects, 

71 WSMessageTypeError, 

72 WSServerHandshakeError, 

73) 

74from .client_middlewares import ClientMiddlewareType, build_client_middlewares 

75from .client_reqrep import ( 

76 ClientRequest as ClientRequest, 

77 ClientResponse as ClientResponse, 

78 Fingerprint as Fingerprint, 

79 RequestInfo as RequestInfo, 

80 _merge_ssl_params, 

81) 

82from .client_ws import ( 

83 DEFAULT_WS_CLIENT_TIMEOUT, 

84 ClientWebSocketResponse as ClientWebSocketResponse, 

85 ClientWSTimeout as ClientWSTimeout, 

86) 

87from .connector import ( 

88 HTTP_AND_EMPTY_SCHEMA_SET, 

89 BaseConnector as BaseConnector, 

90 NamedPipeConnector as NamedPipeConnector, 

91 TCPConnector as TCPConnector, 

92 UnixConnector as UnixConnector, 

93) 

94from .cookiejar import CookieJar 

95from .helpers import ( 

96 _SENTINEL, 

97 DEBUG, 

98 EMPTY_BODY_METHODS, 

99 BasicAuth, 

100 TimeoutHandle, 

101 basicauth_from_netrc, 

102 get_env_proxy_for_url, 

103 netrc_from_env, 

104 sentinel, 

105 strip_auth_from_url, 

106) 

107from .http import WS_KEY, HttpVersion, WebSocketReader, WebSocketWriter 

108from .http_websocket import WSHandshakeError, ws_ext_gen, ws_ext_parse 

109from .tracing import Trace, TraceConfig 

110from .typedefs import JSONEncoder, LooseCookies, LooseHeaders, Query, StrOrURL 

111 

112__all__ = ( 

113 # client_exceptions 

114 "ClientConnectionError", 

115 "ClientConnectionResetError", 

116 "ClientConnectorCertificateError", 

117 "ClientConnectorDNSError", 

118 "ClientConnectorError", 

119 "ClientConnectorSSLError", 

120 "ClientError", 

121 "ClientHttpProxyError", 

122 "ClientOSError", 

123 "ClientPayloadError", 

124 "ClientProxyConnectionError", 

125 "ClientResponseError", 

126 "ClientSSLError", 

127 "ConnectionTimeoutError", 

128 "ContentTypeError", 

129 "InvalidURL", 

130 "InvalidUrlClientError", 

131 "RedirectClientError", 

132 "NonHttpUrlClientError", 

133 "InvalidUrlRedirectClientError", 

134 "NonHttpUrlRedirectClientError", 

135 "ServerConnectionError", 

136 "ServerDisconnectedError", 

137 "ServerFingerprintMismatch", 

138 "ServerTimeoutError", 

139 "SocketTimeoutError", 

140 "TooManyRedirects", 

141 "WSServerHandshakeError", 

142 # client_reqrep 

143 "ClientRequest", 

144 "ClientResponse", 

145 "Fingerprint", 

146 "RequestInfo", 

147 # connector 

148 "BaseConnector", 

149 "TCPConnector", 

150 "UnixConnector", 

151 "NamedPipeConnector", 

152 # client_ws 

153 "ClientWebSocketResponse", 

154 # client 

155 "ClientSession", 

156 "ClientTimeout", 

157 "ClientWSTimeout", 

158 "request", 

159 "WSMessageTypeError", 

160) 

161 

162 

163if TYPE_CHECKING: 

164 from ssl import SSLContext 

165else: 

166 SSLContext = None 

167 

168if sys.version_info >= (3, 11) and TYPE_CHECKING: 

169 from typing import Unpack 

170 

171 

172class _RequestOptions(TypedDict, total=False): 

173 params: Query 

174 data: Any 

175 json: Any 

176 cookies: Union[LooseCookies, None] 

177 headers: Union[LooseHeaders, None] 

178 skip_auto_headers: Union[Iterable[str], None] 

179 auth: Union[BasicAuth, None] 

180 allow_redirects: bool 

181 max_redirects: int 

182 compress: Union[str, bool, None] 

183 chunked: Union[bool, None] 

184 expect100: bool 

185 raise_for_status: Union[None, bool, Callable[[ClientResponse], Awaitable[None]]] 

186 read_until_eof: bool 

187 proxy: Union[StrOrURL, None] 

188 proxy_auth: Union[BasicAuth, None] 

189 timeout: "Union[ClientTimeout, _SENTINEL, None]" 

190 ssl: Union[SSLContext, bool, Fingerprint] 

191 server_hostname: Union[str, None] 

192 proxy_headers: Union[LooseHeaders, None] 

193 trace_request_ctx: Union[Mapping[str, Any], None] 

194 read_bufsize: Union[int, None] 

195 auto_decompress: Union[bool, None] 

196 max_line_size: Union[int, None] 

197 max_field_size: Union[int, None] 

198 middlewares: Optional[Sequence[ClientMiddlewareType]] 

199 

200 

201@attr.s(auto_attribs=True, frozen=True, slots=True) 

202class ClientTimeout: 

203 total: Optional[float] = None 

204 connect: Optional[float] = None 

205 sock_read: Optional[float] = None 

206 sock_connect: Optional[float] = None 

207 ceil_threshold: float = 5 

208 

209 # pool_queue_timeout: Optional[float] = None 

210 # dns_resolution_timeout: Optional[float] = None 

211 # socket_connect_timeout: Optional[float] = None 

212 # connection_acquiring_timeout: Optional[float] = None 

213 # new_connection_timeout: Optional[float] = None 

214 # http_header_timeout: Optional[float] = None 

215 # response_body_timeout: Optional[float] = None 

216 

217 # to create a timeout specific for a single request, either 

218 # - create a completely new one to overwrite the default 

219 # - or use http://www.attrs.org/en/stable/api.html#attr.evolve 

220 # to overwrite the defaults 

221 

222 

223# 5 Minute default read timeout 

224DEFAULT_TIMEOUT: Final[ClientTimeout] = ClientTimeout(total=5 * 60, sock_connect=30) 

225 

226# https://www.rfc-editor.org/rfc/rfc9110#section-9.2.2 

227IDEMPOTENT_METHODS = frozenset({"GET", "HEAD", "OPTIONS", "TRACE", "PUT", "DELETE"}) 

228 

229_RetType = TypeVar("_RetType", ClientResponse, ClientWebSocketResponse) 

230_CharsetResolver = Callable[[ClientResponse, bytes], str] 

231 

232 

233class ClientSession: 

234 """First-class interface for making HTTP requests.""" 

235 

236 ATTRS = frozenset( 

237 [ 

238 "_base_url", 

239 "_base_url_origin", 

240 "_source_traceback", 

241 "_connector", 

242 "_loop", 

243 "_cookie_jar", 

244 "_connector_owner", 

245 "_default_auth", 

246 "_version", 

247 "_json_serialize", 

248 "_requote_redirect_url", 

249 "_timeout", 

250 "_raise_for_status", 

251 "_auto_decompress", 

252 "_trust_env", 

253 "_default_headers", 

254 "_skip_auto_headers", 

255 "_request_class", 

256 "_response_class", 

257 "_ws_response_class", 

258 "_trace_configs", 

259 "_read_bufsize", 

260 "_max_line_size", 

261 "_max_field_size", 

262 "_resolve_charset", 

263 "_default_proxy", 

264 "_default_proxy_auth", 

265 "_retry_connection", 

266 "_middlewares", 

267 "requote_redirect_url", 

268 ] 

269 ) 

270 

271 _source_traceback: Optional[traceback.StackSummary] = None 

272 _connector: Optional[BaseConnector] = None 

273 

274 def __init__( 

275 self, 

276 base_url: Optional[StrOrURL] = None, 

277 *, 

278 connector: Optional[BaseConnector] = None, 

279 loop: Optional[asyncio.AbstractEventLoop] = None, 

280 cookies: Optional[LooseCookies] = None, 

281 headers: Optional[LooseHeaders] = None, 

282 proxy: Optional[StrOrURL] = None, 

283 proxy_auth: Optional[BasicAuth] = None, 

284 skip_auto_headers: Optional[Iterable[str]] = None, 

285 auth: Optional[BasicAuth] = None, 

286 json_serialize: JSONEncoder = json.dumps, 

287 request_class: Type[ClientRequest] = ClientRequest, 

288 response_class: Type[ClientResponse] = ClientResponse, 

289 ws_response_class: Type[ClientWebSocketResponse] = ClientWebSocketResponse, 

290 version: HttpVersion = http.HttpVersion11, 

291 cookie_jar: Optional[AbstractCookieJar] = None, 

292 connector_owner: bool = True, 

293 raise_for_status: Union[ 

294 bool, Callable[[ClientResponse], Awaitable[None]] 

295 ] = False, 

296 read_timeout: Union[float, _SENTINEL] = sentinel, 

297 conn_timeout: Optional[float] = None, 

298 timeout: Union[object, ClientTimeout] = sentinel, 

299 auto_decompress: bool = True, 

300 trust_env: bool = False, 

301 requote_redirect_url: bool = True, 

302 trace_configs: Optional[List[TraceConfig]] = None, 

303 read_bufsize: int = 2**16, 

304 max_line_size: int = 8190, 

305 max_field_size: int = 8190, 

306 fallback_charset_resolver: _CharsetResolver = lambda r, b: "utf-8", 

307 middlewares: Sequence[ClientMiddlewareType] = (), 

308 ssl_shutdown_timeout: Union[_SENTINEL, None, float] = sentinel, 

309 ) -> None: 

310 # We initialise _connector to None immediately, as it's referenced in __del__() 

311 # and could cause issues if an exception occurs during initialisation. 

312 self._connector: Optional[BaseConnector] = None 

313 

314 if loop is None: 

315 if connector is not None: 

316 loop = connector._loop 

317 

318 loop = loop or asyncio.get_running_loop() 

319 

320 if base_url is None or isinstance(base_url, URL): 

321 self._base_url: Optional[URL] = base_url 

322 self._base_url_origin = None if base_url is None else base_url.origin() 

323 else: 

324 self._base_url = URL(base_url) 

325 self._base_url_origin = self._base_url.origin() 

326 assert self._base_url.absolute, "Only absolute URLs are supported" 

327 if self._base_url is not None and not self._base_url.path.endswith("/"): 

328 raise ValueError("base_url must have a trailing '/'") 

329 

330 if timeout is sentinel or timeout is None: 

331 self._timeout = DEFAULT_TIMEOUT 

332 if read_timeout is not sentinel: 

333 warnings.warn( 

334 "read_timeout is deprecated, use timeout argument instead", 

335 DeprecationWarning, 

336 stacklevel=2, 

337 ) 

338 self._timeout = attr.evolve(self._timeout, total=read_timeout) 

339 if conn_timeout is not None: 

340 self._timeout = attr.evolve(self._timeout, connect=conn_timeout) 

341 warnings.warn( 

342 "conn_timeout is deprecated, use timeout argument instead", 

343 DeprecationWarning, 

344 stacklevel=2, 

345 ) 

346 else: 

347 if not isinstance(timeout, ClientTimeout): 

348 raise ValueError( 

349 f"timeout parameter cannot be of {type(timeout)} type, " 

350 "please use 'timeout=ClientTimeout(...)'", 

351 ) 

352 self._timeout = timeout 

353 if read_timeout is not sentinel: 

354 raise ValueError( 

355 "read_timeout and timeout parameters " 

356 "conflict, please setup " 

357 "timeout.read" 

358 ) 

359 if conn_timeout is not None: 

360 raise ValueError( 

361 "conn_timeout and timeout parameters " 

362 "conflict, please setup " 

363 "timeout.connect" 

364 ) 

365 

366 if ssl_shutdown_timeout is not sentinel: 

367 warnings.warn( 

368 "The ssl_shutdown_timeout parameter is deprecated and will be removed in aiohttp 4.0", 

369 DeprecationWarning, 

370 stacklevel=2, 

371 ) 

372 

373 if connector is None: 

374 connector = TCPConnector( 

375 loop=loop, ssl_shutdown_timeout=ssl_shutdown_timeout 

376 ) 

377 

378 if connector._loop is not loop: 

379 raise RuntimeError("Session and connector has to use same event loop") 

380 

381 self._loop = loop 

382 

383 if loop.get_debug(): 

384 self._source_traceback = traceback.extract_stack(sys._getframe(1)) 

385 

386 if cookie_jar is None: 

387 cookie_jar = CookieJar(loop=loop) 

388 self._cookie_jar = cookie_jar 

389 

390 if cookies: 

391 self._cookie_jar.update_cookies(cookies) 

392 

393 self._connector = connector 

394 self._connector_owner = connector_owner 

395 self._default_auth = auth 

396 self._version = version 

397 self._json_serialize = json_serialize 

398 self._raise_for_status = raise_for_status 

399 self._auto_decompress = auto_decompress 

400 self._trust_env = trust_env 

401 self._requote_redirect_url = requote_redirect_url 

402 self._read_bufsize = read_bufsize 

403 self._max_line_size = max_line_size 

404 self._max_field_size = max_field_size 

405 

406 # Convert to list of tuples 

407 if headers: 

408 real_headers: CIMultiDict[str] = CIMultiDict(headers) 

409 else: 

410 real_headers = CIMultiDict() 

411 self._default_headers: CIMultiDict[str] = real_headers 

412 if skip_auto_headers is not None: 

413 self._skip_auto_headers = frozenset(istr(i) for i in skip_auto_headers) 

414 else: 

415 self._skip_auto_headers = frozenset() 

416 

417 self._request_class = request_class 

418 self._response_class = response_class 

419 self._ws_response_class = ws_response_class 

420 

421 self._trace_configs = trace_configs or [] 

422 for trace_config in self._trace_configs: 

423 trace_config.freeze() 

424 

425 self._resolve_charset = fallback_charset_resolver 

426 

427 self._default_proxy = proxy 

428 self._default_proxy_auth = proxy_auth 

429 self._retry_connection: bool = True 

430 self._middlewares = middlewares 

431 

432 def __init_subclass__(cls: Type["ClientSession"]) -> None: 

433 warnings.warn( 

434 "Inheritance class {} from ClientSession " 

435 "is discouraged".format(cls.__name__), 

436 DeprecationWarning, 

437 stacklevel=2, 

438 ) 

439 

440 if DEBUG: 

441 

442 def __setattr__(self, name: str, val: Any) -> None: 

443 if name not in self.ATTRS: 

444 warnings.warn( 

445 "Setting custom ClientSession.{} attribute " 

446 "is discouraged".format(name), 

447 DeprecationWarning, 

448 stacklevel=2, 

449 ) 

450 super().__setattr__(name, val) 

451 

452 def __del__(self, _warnings: Any = warnings) -> None: 

453 if not self.closed: 

454 kwargs = {"source": self} 

455 _warnings.warn( 

456 f"Unclosed client session {self!r}", ResourceWarning, **kwargs 

457 ) 

458 context = {"client_session": self, "message": "Unclosed client session"} 

459 if self._source_traceback is not None: 

460 context["source_traceback"] = self._source_traceback 

461 self._loop.call_exception_handler(context) 

462 

463 if sys.version_info >= (3, 11) and TYPE_CHECKING: 

464 

465 def request( 

466 self, 

467 method: str, 

468 url: StrOrURL, 

469 **kwargs: Unpack[_RequestOptions], 

470 ) -> "_RequestContextManager": ... 

471 

472 else: 

473 

474 def request( 

475 self, method: str, url: StrOrURL, **kwargs: Any 

476 ) -> "_RequestContextManager": 

477 """Perform HTTP request.""" 

478 return _RequestContextManager(self._request(method, url, **kwargs)) 

479 

480 def _build_url(self, str_or_url: StrOrURL) -> URL: 

481 url = URL(str_or_url) 

482 if self._base_url and not url.absolute: 

483 return self._base_url.join(url) 

484 return url 

485 

486 async def _request( 

487 self, 

488 method: str, 

489 str_or_url: StrOrURL, 

490 *, 

491 params: Query = None, 

492 data: Any = None, 

493 json: Any = None, 

494 cookies: Optional[LooseCookies] = None, 

495 headers: Optional[LooseHeaders] = None, 

496 skip_auto_headers: Optional[Iterable[str]] = None, 

497 auth: Optional[BasicAuth] = None, 

498 allow_redirects: bool = True, 

499 max_redirects: int = 10, 

500 compress: Union[str, bool, None] = None, 

501 chunked: Optional[bool] = None, 

502 expect100: bool = False, 

503 raise_for_status: Union[ 

504 None, bool, Callable[[ClientResponse], Awaitable[None]] 

505 ] = None, 

506 read_until_eof: bool = True, 

507 proxy: Optional[StrOrURL] = None, 

508 proxy_auth: Optional[BasicAuth] = None, 

509 timeout: Union[ClientTimeout, _SENTINEL] = sentinel, 

510 verify_ssl: Optional[bool] = None, 

511 fingerprint: Optional[bytes] = None, 

512 ssl_context: Optional[SSLContext] = None, 

513 ssl: Union[SSLContext, bool, Fingerprint] = True, 

514 server_hostname: Optional[str] = None, 

515 proxy_headers: Optional[LooseHeaders] = None, 

516 trace_request_ctx: Optional[Mapping[str, Any]] = None, 

517 read_bufsize: Optional[int] = None, 

518 auto_decompress: Optional[bool] = None, 

519 max_line_size: Optional[int] = None, 

520 max_field_size: Optional[int] = None, 

521 middlewares: Optional[Sequence[ClientMiddlewareType]] = None, 

522 ) -> ClientResponse: 

523 

524 # NOTE: timeout clamps existing connect and read timeouts. We cannot 

525 # set the default to None because we need to detect if the user wants 

526 # to use the existing timeouts by setting timeout to None. 

527 

528 if self.closed: 

529 raise RuntimeError("Session is closed") 

530 

531 ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) 

532 

533 if data is not None and json is not None: 

534 raise ValueError( 

535 "data and json parameters can not be used at the same time" 

536 ) 

537 elif json is not None: 

538 data = payload.JsonPayload(json, dumps=self._json_serialize) 

539 

540 if not isinstance(chunked, bool) and chunked is not None: 

541 warnings.warn("Chunk size is deprecated #1615", DeprecationWarning) 

542 

543 redirects = 0 

544 history: List[ClientResponse] = [] 

545 version = self._version 

546 params = params or {} 

547 

548 # Merge with default headers and transform to CIMultiDict 

549 headers = self._prepare_headers(headers) 

550 

551 try: 

552 url = self._build_url(str_or_url) 

553 except ValueError as e: 

554 raise InvalidUrlClientError(str_or_url) from e 

555 

556 assert self._connector is not None 

557 if url.scheme not in self._connector.allowed_protocol_schema_set: 

558 raise NonHttpUrlClientError(url) 

559 

560 skip_headers: Optional[Iterable[istr]] 

561 if skip_auto_headers is not None: 

562 skip_headers = { 

563 istr(i) for i in skip_auto_headers 

564 } | self._skip_auto_headers 

565 elif self._skip_auto_headers: 

566 skip_headers = self._skip_auto_headers 

567 else: 

568 skip_headers = None 

569 

570 if proxy is None: 

571 proxy = self._default_proxy 

572 if proxy_auth is None: 

573 proxy_auth = self._default_proxy_auth 

574 

575 if proxy is None: 

576 proxy_headers = None 

577 else: 

578 proxy_headers = self._prepare_headers(proxy_headers) 

579 try: 

580 proxy = URL(proxy) 

581 except ValueError as e: 

582 raise InvalidURL(proxy) from e 

583 

584 if timeout is sentinel: 

585 real_timeout: ClientTimeout = self._timeout 

586 else: 

587 if not isinstance(timeout, ClientTimeout): 

588 real_timeout = ClientTimeout(total=timeout) 

589 else: 

590 real_timeout = timeout 

591 # timeout is cumulative for all request operations 

592 # (request, redirects, responses, data consuming) 

593 tm = TimeoutHandle( 

594 self._loop, real_timeout.total, ceil_threshold=real_timeout.ceil_threshold 

595 ) 

596 handle = tm.start() 

597 

598 if read_bufsize is None: 

599 read_bufsize = self._read_bufsize 

600 

601 if auto_decompress is None: 

602 auto_decompress = self._auto_decompress 

603 

604 if max_line_size is None: 

605 max_line_size = self._max_line_size 

606 

607 if max_field_size is None: 

608 max_field_size = self._max_field_size 

609 

610 traces = [ 

611 Trace( 

612 self, 

613 trace_config, 

614 trace_config.trace_config_ctx(trace_request_ctx=trace_request_ctx), 

615 ) 

616 for trace_config in self._trace_configs 

617 ] 

618 

619 for trace in traces: 

620 await trace.send_request_start(method, url.update_query(params), headers) 

621 

622 timer = tm.timer() 

623 try: 

624 with timer: 

625 # https://www.rfc-editor.org/rfc/rfc9112.html#name-retrying-requests 

626 retry_persistent_connection = ( 

627 self._retry_connection and method in IDEMPOTENT_METHODS 

628 ) 

629 while True: 

630 url, auth_from_url = strip_auth_from_url(url) 

631 if not url.raw_host: 

632 # NOTE: Bail early, otherwise, causes `InvalidURL` through 

633 # NOTE: `self._request_class()` below. 

634 err_exc_cls = ( 

635 InvalidUrlRedirectClientError 

636 if redirects 

637 else InvalidUrlClientError 

638 ) 

639 raise err_exc_cls(url) 

640 # If `auth` was passed for an already authenticated URL, 

641 # disallow only if this is the initial URL; this is to avoid issues 

642 # with sketchy redirects that are not the caller's responsibility 

643 if not history and (auth and auth_from_url): 

644 raise ValueError( 

645 "Cannot combine AUTH argument with " 

646 "credentials encoded in URL" 

647 ) 

648 

649 # Override the auth with the one from the URL only if we 

650 # have no auth, or if we got an auth from a redirect URL 

651 if auth is None or (history and auth_from_url is not None): 

652 auth = auth_from_url 

653 

654 if ( 

655 auth is None 

656 and self._default_auth 

657 and ( 

658 not self._base_url or self._base_url_origin == url.origin() 

659 ) 

660 ): 

661 auth = self._default_auth 

662 

663 # Try netrc if auth is still None and trust_env is enabled. 

664 if auth is None and self._trust_env and url.host is not None: 

665 auth = await self._loop.run_in_executor( 

666 None, self._get_netrc_auth, url.host 

667 ) 

668 

669 # It would be confusing if we support explicit 

670 # Authorization header with auth argument 

671 if ( 

672 headers is not None 

673 and auth is not None 

674 and hdrs.AUTHORIZATION in headers 

675 ): 

676 raise ValueError( 

677 "Cannot combine AUTHORIZATION header " 

678 "with AUTH argument or credentials " 

679 "encoded in URL" 

680 ) 

681 

682 all_cookies = self._cookie_jar.filter_cookies(url) 

683 

684 if cookies is not None: 

685 tmp_cookie_jar = CookieJar( 

686 quote_cookie=self._cookie_jar.quote_cookie 

687 ) 

688 tmp_cookie_jar.update_cookies(cookies) 

689 req_cookies = tmp_cookie_jar.filter_cookies(url) 

690 if req_cookies: 

691 all_cookies.load(req_cookies) 

692 

693 proxy_: Optional[URL] = None 

694 if proxy is not None: 

695 proxy_ = URL(proxy) 

696 elif self._trust_env: 

697 with suppress(LookupError): 

698 proxy_, proxy_auth = await asyncio.to_thread( 

699 get_env_proxy_for_url, url 

700 ) 

701 

702 req = self._request_class( 

703 method, 

704 url, 

705 params=params, 

706 headers=headers, 

707 skip_auto_headers=skip_headers, 

708 data=data, 

709 cookies=all_cookies, 

710 auth=auth, 

711 version=version, 

712 compress=compress, 

713 chunked=chunked, 

714 expect100=expect100, 

715 loop=self._loop, 

716 response_class=self._response_class, 

717 proxy=proxy_, 

718 proxy_auth=proxy_auth, 

719 timer=timer, 

720 session=self, 

721 ssl=ssl if ssl is not None else True, 

722 server_hostname=server_hostname, 

723 proxy_headers=proxy_headers, 

724 traces=traces, 

725 trust_env=self.trust_env, 

726 ) 

727 

728 async def _connect_and_send_request( 

729 req: ClientRequest, 

730 ) -> ClientResponse: 

731 # connection timeout 

732 assert self._connector is not None 

733 try: 

734 conn = await self._connector.connect( 

735 req, traces=traces, timeout=real_timeout 

736 ) 

737 except asyncio.TimeoutError as exc: 

738 raise ConnectionTimeoutError( 

739 f"Connection timeout to host {req.url}" 

740 ) from exc 

741 

742 assert conn.protocol is not None 

743 conn.protocol.set_response_params( 

744 timer=timer, 

745 skip_payload=req.method in EMPTY_BODY_METHODS, 

746 read_until_eof=read_until_eof, 

747 auto_decompress=auto_decompress, 

748 read_timeout=real_timeout.sock_read, 

749 read_bufsize=read_bufsize, 

750 timeout_ceil_threshold=self._connector._timeout_ceil_threshold, 

751 max_line_size=max_line_size, 

752 max_field_size=max_field_size, 

753 ) 

754 try: 

755 resp = await req.send(conn) 

756 try: 

757 await resp.start(conn) 

758 except BaseException: 

759 resp.close() 

760 raise 

761 except BaseException: 

762 conn.close() 

763 raise 

764 return resp 

765 

766 # Apply middleware (if any) - per-request middleware overrides session middleware 

767 effective_middlewares = ( 

768 self._middlewares if middlewares is None else middlewares 

769 ) 

770 

771 if effective_middlewares: 

772 handler = build_client_middlewares( 

773 _connect_and_send_request, effective_middlewares 

774 ) 

775 else: 

776 handler = _connect_and_send_request 

777 

778 try: 

779 resp = await handler(req) 

780 # Client connector errors should not be retried 

781 except ( 

782 ConnectionTimeoutError, 

783 ClientConnectorError, 

784 ClientConnectorCertificateError, 

785 ClientConnectorSSLError, 

786 ): 

787 raise 

788 except (ClientOSError, ServerDisconnectedError): 

789 if retry_persistent_connection: 

790 retry_persistent_connection = False 

791 continue 

792 raise 

793 except ClientError: 

794 raise 

795 except OSError as exc: 

796 if exc.errno is None and isinstance(exc, asyncio.TimeoutError): 

797 raise 

798 raise ClientOSError(*exc.args) from exc 

799 

800 # Update cookies from raw headers to preserve duplicates 

801 if resp._raw_cookie_headers: 

802 self._cookie_jar.update_cookies_from_headers( 

803 resp._raw_cookie_headers, resp.url 

804 ) 

805 

806 # redirects 

807 if resp.status in (301, 302, 303, 307, 308) and allow_redirects: 

808 

809 for trace in traces: 

810 await trace.send_request_redirect( 

811 method, url.update_query(params), headers, resp 

812 ) 

813 

814 redirects += 1 

815 history.append(resp) 

816 if max_redirects and redirects >= max_redirects: 

817 if req._body is not None: 

818 await req._body.close() 

819 resp.close() 

820 raise TooManyRedirects( 

821 history[0].request_info, tuple(history) 

822 ) 

823 

824 # For 301 and 302, mimic IE, now changed in RFC 

825 # https://github.com/kennethreitz/requests/pull/269 

826 if (resp.status == 303 and resp.method != hdrs.METH_HEAD) or ( 

827 resp.status in (301, 302) and resp.method == hdrs.METH_POST 

828 ): 

829 method = hdrs.METH_GET 

830 data = None 

831 if headers.get(hdrs.CONTENT_LENGTH): 

832 headers.pop(hdrs.CONTENT_LENGTH) 

833 else: 

834 # For 307/308, always preserve the request body 

835 # For 301/302 with non-POST methods, preserve the request body 

836 # https://www.rfc-editor.org/rfc/rfc9110#section-15.4.3-3.1 

837 # Use the existing payload to avoid recreating it from a potentially consumed file 

838 data = req._body 

839 

840 r_url = resp.headers.get(hdrs.LOCATION) or resp.headers.get( 

841 hdrs.URI 

842 ) 

843 if r_url is None: 

844 # see github.com/aio-libs/aiohttp/issues/2022 

845 break 

846 else: 

847 # reading from correct redirection 

848 # response is forbidden 

849 resp.release() 

850 

851 try: 

852 parsed_redirect_url = URL( 

853 r_url, encoded=not self._requote_redirect_url 

854 ) 

855 except ValueError as e: 

856 if req._body is not None: 

857 await req._body.close() 

858 resp.close() 

859 raise InvalidUrlRedirectClientError( 

860 r_url, 

861 "Server attempted redirecting to a location that does not look like a URL", 

862 ) from e 

863 

864 scheme = parsed_redirect_url.scheme 

865 if scheme not in HTTP_AND_EMPTY_SCHEMA_SET: 

866 if req._body is not None: 

867 await req._body.close() 

868 resp.close() 

869 raise NonHttpUrlRedirectClientError(r_url) 

870 elif not scheme: 

871 parsed_redirect_url = url.join(parsed_redirect_url) 

872 

873 try: 

874 redirect_origin = parsed_redirect_url.origin() 

875 except ValueError as origin_val_err: 

876 if req._body is not None: 

877 await req._body.close() 

878 resp.close() 

879 raise InvalidUrlRedirectClientError( 

880 parsed_redirect_url, 

881 "Invalid redirect URL origin", 

882 ) from origin_val_err 

883 

884 if url.origin() != redirect_origin: 

885 auth = None 

886 headers.pop(hdrs.AUTHORIZATION, None) 

887 

888 url = parsed_redirect_url 

889 params = {} 

890 resp.release() 

891 continue 

892 

893 break 

894 

895 if req._body is not None: 

896 await req._body.close() 

897 # check response status 

898 if raise_for_status is None: 

899 raise_for_status = self._raise_for_status 

900 

901 if raise_for_status is None: 

902 pass 

903 elif callable(raise_for_status): 

904 await raise_for_status(resp) 

905 elif raise_for_status: 

906 resp.raise_for_status() 

907 

908 # register connection 

909 if handle is not None: 

910 if resp.connection is not None: 

911 resp.connection.add_callback(handle.cancel) 

912 else: 

913 handle.cancel() 

914 

915 resp._history = tuple(history) 

916 

917 for trace in traces: 

918 await trace.send_request_end( 

919 method, url.update_query(params), headers, resp 

920 ) 

921 return resp 

922 

923 except BaseException as e: 

924 # cleanup timer 

925 tm.close() 

926 if handle: 

927 handle.cancel() 

928 handle = None 

929 

930 for trace in traces: 

931 await trace.send_request_exception( 

932 method, url.update_query(params), headers, e 

933 ) 

934 raise 

935 

936 def ws_connect( 

937 self, 

938 url: StrOrURL, 

939 *, 

940 method: str = hdrs.METH_GET, 

941 protocols: Iterable[str] = (), 

942 timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, 

943 receive_timeout: Optional[float] = None, 

944 autoclose: bool = True, 

945 autoping: bool = True, 

946 heartbeat: Optional[float] = None, 

947 auth: Optional[BasicAuth] = None, 

948 origin: Optional[str] = None, 

949 params: Query = None, 

950 headers: Optional[LooseHeaders] = None, 

951 proxy: Optional[StrOrURL] = None, 

952 proxy_auth: Optional[BasicAuth] = None, 

953 ssl: Union[SSLContext, bool, Fingerprint] = True, 

954 verify_ssl: Optional[bool] = None, 

955 fingerprint: Optional[bytes] = None, 

956 ssl_context: Optional[SSLContext] = None, 

957 server_hostname: Optional[str] = None, 

958 proxy_headers: Optional[LooseHeaders] = None, 

959 compress: int = 0, 

960 max_msg_size: int = 4 * 1024 * 1024, 

961 ) -> "_WSRequestContextManager": 

962 """Initiate websocket connection.""" 

963 return _WSRequestContextManager( 

964 self._ws_connect( 

965 url, 

966 method=method, 

967 protocols=protocols, 

968 timeout=timeout, 

969 receive_timeout=receive_timeout, 

970 autoclose=autoclose, 

971 autoping=autoping, 

972 heartbeat=heartbeat, 

973 auth=auth, 

974 origin=origin, 

975 params=params, 

976 headers=headers, 

977 proxy=proxy, 

978 proxy_auth=proxy_auth, 

979 ssl=ssl, 

980 verify_ssl=verify_ssl, 

981 fingerprint=fingerprint, 

982 ssl_context=ssl_context, 

983 server_hostname=server_hostname, 

984 proxy_headers=proxy_headers, 

985 compress=compress, 

986 max_msg_size=max_msg_size, 

987 ) 

988 ) 

989 

990 async def _ws_connect( 

991 self, 

992 url: StrOrURL, 

993 *, 

994 method: str = hdrs.METH_GET, 

995 protocols: Iterable[str] = (), 

996 timeout: Union[ClientWSTimeout, _SENTINEL] = sentinel, 

997 receive_timeout: Optional[float] = None, 

998 autoclose: bool = True, 

999 autoping: bool = True, 

1000 heartbeat: Optional[float] = None, 

1001 auth: Optional[BasicAuth] = None, 

1002 origin: Optional[str] = None, 

1003 params: Query = None, 

1004 headers: Optional[LooseHeaders] = None, 

1005 proxy: Optional[StrOrURL] = None, 

1006 proxy_auth: Optional[BasicAuth] = None, 

1007 ssl: Union[SSLContext, bool, Fingerprint] = True, 

1008 verify_ssl: Optional[bool] = None, 

1009 fingerprint: Optional[bytes] = None, 

1010 ssl_context: Optional[SSLContext] = None, 

1011 server_hostname: Optional[str] = None, 

1012 proxy_headers: Optional[LooseHeaders] = None, 

1013 compress: int = 0, 

1014 max_msg_size: int = 4 * 1024 * 1024, 

1015 ) -> ClientWebSocketResponse: 

1016 if timeout is not sentinel: 

1017 if isinstance(timeout, ClientWSTimeout): 

1018 ws_timeout = timeout 

1019 else: 

1020 warnings.warn( 

1021 "parameter 'timeout' of type 'float' " 

1022 "is deprecated, please use " 

1023 "'timeout=ClientWSTimeout(ws_close=...)'", 

1024 DeprecationWarning, 

1025 stacklevel=2, 

1026 ) 

1027 ws_timeout = ClientWSTimeout(ws_close=timeout) 

1028 else: 

1029 ws_timeout = DEFAULT_WS_CLIENT_TIMEOUT 

1030 if receive_timeout is not None: 

1031 warnings.warn( 

1032 "float parameter 'receive_timeout' " 

1033 "is deprecated, please use parameter " 

1034 "'timeout=ClientWSTimeout(ws_receive=...)'", 

1035 DeprecationWarning, 

1036 stacklevel=2, 

1037 ) 

1038 ws_timeout = attr.evolve(ws_timeout, ws_receive=receive_timeout) 

1039 

1040 if headers is None: 

1041 real_headers: CIMultiDict[str] = CIMultiDict() 

1042 else: 

1043 real_headers = CIMultiDict(headers) 

1044 

1045 default_headers = { 

1046 hdrs.UPGRADE: "websocket", 

1047 hdrs.CONNECTION: "Upgrade", 

1048 hdrs.SEC_WEBSOCKET_VERSION: "13", 

1049 } 

1050 

1051 for key, value in default_headers.items(): 

1052 real_headers.setdefault(key, value) 

1053 

1054 sec_key = base64.b64encode(os.urandom(16)) 

1055 real_headers[hdrs.SEC_WEBSOCKET_KEY] = sec_key.decode() 

1056 

1057 if protocols: 

1058 real_headers[hdrs.SEC_WEBSOCKET_PROTOCOL] = ",".join(protocols) 

1059 if origin is not None: 

1060 real_headers[hdrs.ORIGIN] = origin 

1061 if compress: 

1062 extstr = ws_ext_gen(compress=compress) 

1063 real_headers[hdrs.SEC_WEBSOCKET_EXTENSIONS] = extstr 

1064 

1065 # For the sake of backward compatibility, if user passes in None, convert it to True 

1066 if ssl is None: 

1067 warnings.warn( 

1068 "ssl=None is deprecated, please use ssl=True", 

1069 DeprecationWarning, 

1070 stacklevel=2, 

1071 ) 

1072 ssl = True 

1073 ssl = _merge_ssl_params(ssl, verify_ssl, ssl_context, fingerprint) 

1074 

1075 # send request 

1076 resp = await self.request( 

1077 method, 

1078 url, 

1079 params=params, 

1080 headers=real_headers, 

1081 read_until_eof=False, 

1082 auth=auth, 

1083 proxy=proxy, 

1084 proxy_auth=proxy_auth, 

1085 ssl=ssl, 

1086 server_hostname=server_hostname, 

1087 proxy_headers=proxy_headers, 

1088 ) 

1089 

1090 try: 

1091 # check handshake 

1092 if resp.status != 101: 

1093 raise WSServerHandshakeError( 

1094 resp.request_info, 

1095 resp.history, 

1096 message="Invalid response status", 

1097 status=resp.status, 

1098 headers=resp.headers, 

1099 ) 

1100 

1101 if resp.headers.get(hdrs.UPGRADE, "").lower() != "websocket": 

1102 raise WSServerHandshakeError( 

1103 resp.request_info, 

1104 resp.history, 

1105 message="Invalid upgrade header", 

1106 status=resp.status, 

1107 headers=resp.headers, 

1108 ) 

1109 

1110 if resp.headers.get(hdrs.CONNECTION, "").lower() != "upgrade": 

1111 raise WSServerHandshakeError( 

1112 resp.request_info, 

1113 resp.history, 

1114 message="Invalid connection header", 

1115 status=resp.status, 

1116 headers=resp.headers, 

1117 ) 

1118 

1119 # key calculation 

1120 r_key = resp.headers.get(hdrs.SEC_WEBSOCKET_ACCEPT, "") 

1121 match = base64.b64encode(hashlib.sha1(sec_key + WS_KEY).digest()).decode() 

1122 if r_key != match: 

1123 raise WSServerHandshakeError( 

1124 resp.request_info, 

1125 resp.history, 

1126 message="Invalid challenge response", 

1127 status=resp.status, 

1128 headers=resp.headers, 

1129 ) 

1130 

1131 # websocket protocol 

1132 protocol = None 

1133 if protocols and hdrs.SEC_WEBSOCKET_PROTOCOL in resp.headers: 

1134 resp_protocols = [ 

1135 proto.strip() 

1136 for proto in resp.headers[hdrs.SEC_WEBSOCKET_PROTOCOL].split(",") 

1137 ] 

1138 

1139 for proto in resp_protocols: 

1140 if proto in protocols: 

1141 protocol = proto 

1142 break 

1143 

1144 # websocket compress 

1145 notakeover = False 

1146 if compress: 

1147 compress_hdrs = resp.headers.get(hdrs.SEC_WEBSOCKET_EXTENSIONS) 

1148 if compress_hdrs: 

1149 try: 

1150 compress, notakeover = ws_ext_parse(compress_hdrs) 

1151 except WSHandshakeError as exc: 

1152 raise WSServerHandshakeError( 

1153 resp.request_info, 

1154 resp.history, 

1155 message=exc.args[0], 

1156 status=resp.status, 

1157 headers=resp.headers, 

1158 ) from exc 

1159 else: 

1160 compress = 0 

1161 notakeover = False 

1162 

1163 conn = resp.connection 

1164 assert conn is not None 

1165 conn_proto = conn.protocol 

1166 assert conn_proto is not None 

1167 

1168 # For WS connection the read_timeout must be either receive_timeout or greater 

1169 # None == no timeout, i.e. infinite timeout, so None is the max timeout possible 

1170 if ws_timeout.ws_receive is None: 

1171 # Reset regardless 

1172 conn_proto.read_timeout = None 

1173 elif conn_proto.read_timeout is not None: 

1174 conn_proto.read_timeout = max( 

1175 ws_timeout.ws_receive, conn_proto.read_timeout 

1176 ) 

1177 

1178 transport = conn.transport 

1179 assert transport is not None 

1180 reader = WebSocketDataQueue(conn_proto, 2**16, loop=self._loop) 

1181 conn_proto.set_parser(WebSocketReader(reader, max_msg_size), reader) 

1182 writer = WebSocketWriter( 

1183 conn_proto, 

1184 transport, 

1185 use_mask=True, 

1186 compress=compress, 

1187 notakeover=notakeover, 

1188 ) 

1189 except BaseException: 

1190 resp.close() 

1191 raise 

1192 else: 

1193 return self._ws_response_class( 

1194 reader, 

1195 writer, 

1196 protocol, 

1197 resp, 

1198 ws_timeout, 

1199 autoclose, 

1200 autoping, 

1201 self._loop, 

1202 heartbeat=heartbeat, 

1203 compress=compress, 

1204 client_notakeover=notakeover, 

1205 ) 

1206 

1207 def _prepare_headers(self, headers: Optional[LooseHeaders]) -> "CIMultiDict[str]": 

1208 """Add default headers and transform it to CIMultiDict""" 

1209 # Convert headers to MultiDict 

1210 result = CIMultiDict(self._default_headers) 

1211 if headers: 

1212 if not isinstance(headers, (MultiDictProxy, MultiDict)): 

1213 headers = CIMultiDict(headers) 

1214 added_names: Set[str] = set() 

1215 for key, value in headers.items(): 

1216 if key in added_names: 

1217 result.add(key, value) 

1218 else: 

1219 result[key] = value 

1220 added_names.add(key) 

1221 return result 

1222 

1223 def _get_netrc_auth(self, host: str) -> Optional[BasicAuth]: 

1224 """ 

1225 Get auth from netrc for the given host. 

1226 

1227 This method is designed to be called in an executor to avoid 

1228 blocking I/O in the event loop. 

1229 """ 

1230 netrc_obj = netrc_from_env() 

1231 try: 

1232 return basicauth_from_netrc(netrc_obj, host) 

1233 except LookupError: 

1234 return None 

1235 

1236 if sys.version_info >= (3, 11) and TYPE_CHECKING: 

1237 

1238 def get( 

1239 self, 

1240 url: StrOrURL, 

1241 **kwargs: Unpack[_RequestOptions], 

1242 ) -> "_RequestContextManager": ... 

1243 

1244 def options( 

1245 self, 

1246 url: StrOrURL, 

1247 **kwargs: Unpack[_RequestOptions], 

1248 ) -> "_RequestContextManager": ... 

1249 

1250 def head( 

1251 self, 

1252 url: StrOrURL, 

1253 **kwargs: Unpack[_RequestOptions], 

1254 ) -> "_RequestContextManager": ... 

1255 

1256 def post( 

1257 self, 

1258 url: StrOrURL, 

1259 **kwargs: Unpack[_RequestOptions], 

1260 ) -> "_RequestContextManager": ... 

1261 

1262 def put( 

1263 self, 

1264 url: StrOrURL, 

1265 **kwargs: Unpack[_RequestOptions], 

1266 ) -> "_RequestContextManager": ... 

1267 

1268 def patch( 

1269 self, 

1270 url: StrOrURL, 

1271 **kwargs: Unpack[_RequestOptions], 

1272 ) -> "_RequestContextManager": ... 

1273 

1274 def delete( 

1275 self, 

1276 url: StrOrURL, 

1277 **kwargs: Unpack[_RequestOptions], 

1278 ) -> "_RequestContextManager": ... 

1279 

1280 else: 

1281 

1282 def get( 

1283 self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any 

1284 ) -> "_RequestContextManager": 

1285 """Perform HTTP GET request.""" 

1286 return _RequestContextManager( 

1287 self._request( 

1288 hdrs.METH_GET, url, allow_redirects=allow_redirects, **kwargs 

1289 ) 

1290 ) 

1291 

1292 def options( 

1293 self, url: StrOrURL, *, allow_redirects: bool = True, **kwargs: Any 

1294 ) -> "_RequestContextManager": 

1295 """Perform HTTP OPTIONS request.""" 

1296 return _RequestContextManager( 

1297 self._request( 

1298 hdrs.METH_OPTIONS, url, allow_redirects=allow_redirects, **kwargs 

1299 ) 

1300 ) 

1301 

1302 def head( 

1303 self, url: StrOrURL, *, allow_redirects: bool = False, **kwargs: Any 

1304 ) -> "_RequestContextManager": 

1305 """Perform HTTP HEAD request.""" 

1306 return _RequestContextManager( 

1307 self._request( 

1308 hdrs.METH_HEAD, url, allow_redirects=allow_redirects, **kwargs 

1309 ) 

1310 ) 

1311 

1312 def post( 

1313 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1314 ) -> "_RequestContextManager": 

1315 """Perform HTTP POST request.""" 

1316 return _RequestContextManager( 

1317 self._request(hdrs.METH_POST, url, data=data, **kwargs) 

1318 ) 

1319 

1320 def put( 

1321 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1322 ) -> "_RequestContextManager": 

1323 """Perform HTTP PUT request.""" 

1324 return _RequestContextManager( 

1325 self._request(hdrs.METH_PUT, url, data=data, **kwargs) 

1326 ) 

1327 

1328 def patch( 

1329 self, url: StrOrURL, *, data: Any = None, **kwargs: Any 

1330 ) -> "_RequestContextManager": 

1331 """Perform HTTP PATCH request.""" 

1332 return _RequestContextManager( 

1333 self._request(hdrs.METH_PATCH, url, data=data, **kwargs) 

1334 ) 

1335 

1336 def delete(self, url: StrOrURL, **kwargs: Any) -> "_RequestContextManager": 

1337 """Perform HTTP DELETE request.""" 

1338 return _RequestContextManager( 

1339 self._request(hdrs.METH_DELETE, url, **kwargs) 

1340 ) 

1341 

1342 async def close(self) -> None: 

1343 """Close underlying connector. 

1344 

1345 Release all acquired resources. 

1346 """ 

1347 if not self.closed: 

1348 if self._connector is not None and self._connector_owner: 

1349 await self._connector.close() 

1350 self._connector = None 

1351 

1352 @property 

1353 def closed(self) -> bool: 

1354 """Is client session closed. 

1355 

1356 A readonly property. 

1357 """ 

1358 return self._connector is None or self._connector.closed 

1359 

1360 @property 

1361 def connector(self) -> Optional[BaseConnector]: 

1362 """Connector instance used for the session.""" 

1363 return self._connector 

1364 

1365 @property 

1366 def cookie_jar(self) -> AbstractCookieJar: 

1367 """The session cookies.""" 

1368 return self._cookie_jar 

1369 

1370 @property 

1371 def version(self) -> Tuple[int, int]: 

1372 """The session HTTP protocol version.""" 

1373 return self._version 

1374 

1375 @property 

1376 def requote_redirect_url(self) -> bool: 

1377 """Do URL requoting on redirection handling.""" 

1378 return self._requote_redirect_url 

1379 

1380 @requote_redirect_url.setter 

1381 def requote_redirect_url(self, val: bool) -> None: 

1382 """Do URL requoting on redirection handling.""" 

1383 warnings.warn( 

1384 "session.requote_redirect_url modification is deprecated #2778", 

1385 DeprecationWarning, 

1386 stacklevel=2, 

1387 ) 

1388 self._requote_redirect_url = val 

1389 

1390 @property 

1391 def loop(self) -> asyncio.AbstractEventLoop: 

1392 """Session's loop.""" 

1393 warnings.warn( 

1394 "client.loop property is deprecated", DeprecationWarning, stacklevel=2 

1395 ) 

1396 return self._loop 

1397 

1398 @property 

1399 def timeout(self) -> ClientTimeout: 

1400 """Timeout for the session.""" 

1401 return self._timeout 

1402 

1403 @property 

1404 def headers(self) -> "CIMultiDict[str]": 

1405 """The default headers of the client session.""" 

1406 return self._default_headers 

1407 

1408 @property 

1409 def skip_auto_headers(self) -> FrozenSet[istr]: 

1410 """Headers for which autogeneration should be skipped""" 

1411 return self._skip_auto_headers 

1412 

1413 @property 

1414 def auth(self) -> Optional[BasicAuth]: 

1415 """An object that represents HTTP Basic Authorization""" 

1416 return self._default_auth 

1417 

1418 @property 

1419 def json_serialize(self) -> JSONEncoder: 

1420 """Json serializer callable""" 

1421 return self._json_serialize 

1422 

1423 @property 

1424 def connector_owner(self) -> bool: 

1425 """Should connector be closed on session closing""" 

1426 return self._connector_owner 

1427 

1428 @property 

1429 def raise_for_status( 

1430 self, 

1431 ) -> Union[bool, Callable[[ClientResponse], Awaitable[None]]]: 

1432 """Should `ClientResponse.raise_for_status()` be called for each response.""" 

1433 return self._raise_for_status 

1434 

1435 @property 

1436 def auto_decompress(self) -> bool: 

1437 """Should the body response be automatically decompressed.""" 

1438 return self._auto_decompress 

1439 

1440 @property 

1441 def trust_env(self) -> bool: 

1442 """ 

1443 Should proxies information from environment or netrc be trusted. 

1444 

1445 Information is from HTTP_PROXY / HTTPS_PROXY environment variables 

1446 or ~/.netrc file if present. 

1447 """ 

1448 return self._trust_env 

1449 

1450 @property 

1451 def trace_configs(self) -> List[TraceConfig]: 

1452 """A list of TraceConfig instances used for client tracing""" 

1453 return self._trace_configs 

1454 

1455 def detach(self) -> None: 

1456 """Detach connector from session without closing the former. 

1457 

1458 Session is switched to closed state anyway. 

1459 """ 

1460 self._connector = None 

1461 

1462 def __enter__(self) -> None: 

1463 raise TypeError("Use async with instead") 

1464 

1465 def __exit__( 

1466 self, 

1467 exc_type: Optional[Type[BaseException]], 

1468 exc_val: Optional[BaseException], 

1469 exc_tb: Optional[TracebackType], 

1470 ) -> None: 

1471 # __exit__ should exist in pair with __enter__ but never executed 

1472 pass # pragma: no cover 

1473 

1474 async def __aenter__(self) -> "ClientSession": 

1475 return self 

1476 

1477 async def __aexit__( 

1478 self, 

1479 exc_type: Optional[Type[BaseException]], 

1480 exc_val: Optional[BaseException], 

1481 exc_tb: Optional[TracebackType], 

1482 ) -> None: 

1483 await self.close() 

1484 

1485 

1486class _BaseRequestContextManager(Coroutine[Any, Any, _RetType], Generic[_RetType]): 

1487 

1488 __slots__ = ("_coro", "_resp") 

1489 

1490 def __init__(self, coro: Coroutine["asyncio.Future[Any]", None, _RetType]) -> None: 

1491 self._coro: Coroutine["asyncio.Future[Any]", None, _RetType] = coro 

1492 

1493 def send(self, arg: None) -> "asyncio.Future[Any]": 

1494 return self._coro.send(arg) 

1495 

1496 def throw(self, *args: Any, **kwargs: Any) -> "asyncio.Future[Any]": 

1497 return self._coro.throw(*args, **kwargs) 

1498 

1499 def close(self) -> None: 

1500 return self._coro.close() 

1501 

1502 def __await__(self) -> Generator[Any, None, _RetType]: 

1503 ret = self._coro.__await__() 

1504 return ret 

1505 

1506 def __iter__(self) -> Generator[Any, None, _RetType]: 

1507 return self.__await__() 

1508 

1509 async def __aenter__(self) -> _RetType: 

1510 self._resp: _RetType = await self._coro 

1511 return await self._resp.__aenter__() 

1512 

1513 async def __aexit__( 

1514 self, 

1515 exc_type: Optional[Type[BaseException]], 

1516 exc: Optional[BaseException], 

1517 tb: Optional[TracebackType], 

1518 ) -> None: 

1519 await self._resp.__aexit__(exc_type, exc, tb) 

1520 

1521 

1522_RequestContextManager = _BaseRequestContextManager[ClientResponse] 

1523_WSRequestContextManager = _BaseRequestContextManager[ClientWebSocketResponse] 

1524 

1525 

1526class _SessionRequestContextManager: 

1527 

1528 __slots__ = ("_coro", "_resp", "_session") 

1529 

1530 def __init__( 

1531 self, 

1532 coro: Coroutine["asyncio.Future[Any]", None, ClientResponse], 

1533 session: ClientSession, 

1534 ) -> None: 

1535 self._coro = coro 

1536 self._resp: Optional[ClientResponse] = None 

1537 self._session = session 

1538 

1539 async def __aenter__(self) -> ClientResponse: 

1540 try: 

1541 self._resp = await self._coro 

1542 except BaseException: 

1543 await self._session.close() 

1544 raise 

1545 else: 

1546 return self._resp 

1547 

1548 async def __aexit__( 

1549 self, 

1550 exc_type: Optional[Type[BaseException]], 

1551 exc: Optional[BaseException], 

1552 tb: Optional[TracebackType], 

1553 ) -> None: 

1554 assert self._resp is not None 

1555 self._resp.close() 

1556 await self._session.close() 

1557 

1558 

1559if sys.version_info >= (3, 11) and TYPE_CHECKING: 

1560 

1561 def request( 

1562 method: str, 

1563 url: StrOrURL, 

1564 *, 

1565 version: HttpVersion = http.HttpVersion11, 

1566 connector: Optional[BaseConnector] = None, 

1567 loop: Optional[asyncio.AbstractEventLoop] = None, 

1568 **kwargs: Unpack[_RequestOptions], 

1569 ) -> _SessionRequestContextManager: ... 

1570 

1571else: 

1572 

1573 def request( 

1574 method: str, 

1575 url: StrOrURL, 

1576 *, 

1577 version: HttpVersion = http.HttpVersion11, 

1578 connector: Optional[BaseConnector] = None, 

1579 loop: Optional[asyncio.AbstractEventLoop] = None, 

1580 **kwargs: Any, 

1581 ) -> _SessionRequestContextManager: 

1582 """Constructs and sends a request. 

1583 

1584 Returns response object. 

1585 method - HTTP method 

1586 url - request url 

1587 params - (optional) Dictionary or bytes to be sent in the query 

1588 string of the new request 

1589 data - (optional) Dictionary, bytes, or file-like object to 

1590 send in the body of the request 

1591 json - (optional) Any json compatible python object 

1592 headers - (optional) Dictionary of HTTP Headers to send with 

1593 the request 

1594 cookies - (optional) Dict object to send with the request 

1595 auth - (optional) BasicAuth named tuple represent HTTP Basic Auth 

1596 auth - aiohttp.helpers.BasicAuth 

1597 allow_redirects - (optional) If set to False, do not follow 

1598 redirects 

1599 version - Request HTTP version. 

1600 compress - Set to True if request has to be compressed 

1601 with deflate encoding. 

1602 chunked - Set to chunk size for chunked transfer encoding. 

1603 expect100 - Expect 100-continue response from server. 

1604 connector - BaseConnector sub-class instance to support 

1605 connection pooling. 

1606 read_until_eof - Read response until eof if response 

1607 does not have Content-Length header. 

1608 loop - Optional event loop. 

1609 timeout - Optional ClientTimeout settings structure, 5min 

1610 total timeout by default. 

1611 Usage:: 

1612 >>> import aiohttp 

1613 >>> async with aiohttp.request('GET', 'http://python.org/') as resp: 

1614 ... print(resp) 

1615 ... data = await resp.read() 

1616 <ClientResponse(https://www.python.org/) [200 OK]> 

1617 """ 

1618 connector_owner = False 

1619 if connector is None: 

1620 connector_owner = True 

1621 connector = TCPConnector(loop=loop, force_close=True) 

1622 

1623 session = ClientSession( 

1624 loop=loop, 

1625 cookies=kwargs.pop("cookies", None), 

1626 version=version, 

1627 timeout=kwargs.pop("timeout", sentinel), 

1628 connector=connector, 

1629 connector_owner=connector_owner, 

1630 ) 

1631 

1632 return _SessionRequestContextManager( 

1633 session._request(method, url, **kwargs), 

1634 session, 

1635 )