From 9bba8a4b83b8d209f227c473b439bd6851c51562 Mon Sep 17 00:00:00 2001 From: Maarten ter Huurne Date: Fri, 6 Aug 2021 10:55:49 +0200 Subject: [PATCH] Correct annotation of headers parameter of HTTP event handlers (#5854) * Use HTTPMessage for the headers parameter of HTTP event handlers While the documentation of `BaseHandler.http_error_default()` describes the `hdrs` (`headers` in most other handlers) as "a mapping object with the headers of the error", the implementation that is located in `URLopener._open_generic_http()` will pass `response.msg` instead, which is of type `http.client.HTTPMessage`. * Use Message for the headers parameter of HTTPError When the standard library constructs `HTTPError`, it will pass an `http.client.HTTPMessage`, which is a subclass of `email.message.Message`. Picking the superclass for the annotations gives users the flexibility to for example the result of the `email.message_from_X()` functions. The only thing unique to `HTTPMessage` is the undocumented `getallmatchingheaders()` method, which is only called by `http.server.CGIHTTPRequestHandler.run_cgi()`. That class gets its headers from `http.client.parse_headers()` and not from `HTTPError`, so I think it's safe to use `Message` as the annotation. --- stdlib/urllib/error.pyi | 4 +-- stdlib/urllib/request.pyi | 60 ++++++++++++++------------------------- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/stdlib/urllib/error.pyi b/stdlib/urllib/error.pyi index d6ef9ff5f..e7c919ef8 100644 --- a/stdlib/urllib/error.pyi +++ b/stdlib/urllib/error.pyi @@ -1,5 +1,5 @@ from email.message import Message -from typing import IO, Mapping, Optional, Tuple, Union +from typing import IO, Optional, Tuple, Union from urllib.response import addinfourl # Stubs for urllib.error @@ -10,7 +10,7 @@ class URLError(IOError): class HTTPError(URLError, addinfourl): code: int - def __init__(self, url: str, code: int, msg: str, hdrs: Mapping[str, str], fp: Optional[IO[bytes]]) -> None: ... + def __init__(self, url: str, code: int, msg: str, hdrs: Message, fp: Optional[IO[bytes]]) -> None: ... class ContentTooShortError(URLError): content: Tuple[str, Message] diff --git a/stdlib/urllib/request.pyi b/stdlib/urllib/request.pyi index cbbb48270..32836cff0 100644 --- a/stdlib/urllib/request.pyi +++ b/stdlib/urllib/request.pyi @@ -111,7 +111,7 @@ class BaseHandler: class HTTPDefaultErrorHandler(BaseHandler): def http_error_default( - self, req: Request, fp: IO[bytes], code: int, msg: str, hdrs: Mapping[str, str] + self, req: Request, fp: IO[bytes], code: int, msg: str, hdrs: HTTPMessage ) -> HTTPError: ... # undocumented class HTTPRedirectHandler(BaseHandler): @@ -119,20 +119,12 @@ class HTTPRedirectHandler(BaseHandler): max_repeats: ClassVar[int] # undocumented inf_msg: ClassVar[str] # undocumented def redirect_request( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str], newurl: str + self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage, newurl: str ) -> Optional[Request]: ... - def http_error_301( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... - def http_error_302( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... - def http_error_303( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... - def http_error_307( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... + def http_error_301(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... + def http_error_302(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... + def http_error_303(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... + def http_error_307(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... class HTTPCookieProcessor(BaseHandler): cookiejar: CookieJar @@ -169,7 +161,7 @@ class AbstractBasicAuthHandler: passwd: HTTPPasswordMgr add_password: Callable[[str, Union[str, Sequence[str]], str, str], None] def __init__(self, password_mgr: Optional[HTTPPasswordMgr] = ...) -> None: ... - def http_error_auth_reqed(self, authreq: str, host: str, req: Request, headers: Mapping[str, str]) -> None: ... + def http_error_auth_reqed(self, authreq: str, host: str, req: Request, headers: HTTPMessage) -> None: ... def http_request(self, req: Request) -> Request: ... # undocumented def http_response(self, req: Request, response: HTTPResponse) -> HTTPResponse: ... # undocumented def https_request(self, req: Request) -> Request: ... # undocumented @@ -178,20 +170,16 @@ class AbstractBasicAuthHandler: class HTTPBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): auth_header: ClassVar[str] # undocumented - def http_error_401( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... + def http_error_401(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... class ProxyBasicAuthHandler(AbstractBasicAuthHandler, BaseHandler): auth_header: ClassVar[str] - def http_error_407( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... + def http_error_407(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... class AbstractDigestAuthHandler: def __init__(self, passwd: Optional[HTTPPasswordMgr] = ...) -> None: ... def reset_retry_count(self) -> None: ... - def http_error_auth_reqed(self, auth_header: str, host: str, req: Request, headers: Mapping[str, str]) -> None: ... + def http_error_auth_reqed(self, auth_header: str, host: str, req: Request, headers: HTTPMessage) -> None: ... def retry_http_digest_auth(self, req: Request, auth: str) -> Optional[_UrlopenRet]: ... def get_cnonce(self, nonce: str) -> str: ... def get_authorization(self, req: Request, chal: Mapping[str, str]) -> str: ... @@ -200,15 +188,11 @@ class AbstractDigestAuthHandler: class HTTPDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler): auth_header: ClassVar[str] # undocumented - def http_error_401( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... + def http_error_401(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... class ProxyDigestAuthHandler(BaseHandler, AbstractDigestAuthHandler): auth_header: ClassVar[str] # undocumented - def http_error_407( - self, req: Request, fp: IO[bytes], code: int, msg: str, headers: Mapping[str, str] - ) -> Optional[_UrlopenRet]: ... + def http_error_407(self, req: Request, fp: IO[bytes], code: int, msg: str, headers: HTTPMessage) -> Optional[_UrlopenRet]: ... class AbstractHTTPHandler(BaseHandler): # undocumented def __init__(self, debuglevel: int = ...) -> None: ... @@ -293,10 +277,10 @@ class URLopener: def cleanup(self) -> None: ... # undocumented def close(self) -> None: ... # undocumented def http_error( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] = ... + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] = ... ) -> _UrlopenRet: ... # undocumented def http_error_default( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str] + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage ) -> _UrlopenRet: ... # undocumented def open_data(self, url: str, data: Optional[bytes] = ...) -> addinfourl: ... # undocumented def open_file(self, url: str) -> addinfourl: ... # undocumented @@ -310,16 +294,16 @@ class FancyURLopener(URLopener): def prompt_user_passwd(self, host: str, realm: str) -> Tuple[str, str]: ... def get_user_passwd(self, host: str, realm: str, clear_cache: int = ...) -> Tuple[str, str]: ... # undocumented def http_error_301( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] = ... + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] = ... ) -> Optional[Union[_UrlopenRet, addinfourl]]: ... # undocumented def http_error_302( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] = ... + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] = ... ) -> Optional[Union[_UrlopenRet, addinfourl]]: ... # undocumented def http_error_303( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] = ... + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] = ... ) -> Optional[Union[_UrlopenRet, addinfourl]]: ... # undocumented def http_error_307( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] = ... + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] = ... ) -> Optional[Union[_UrlopenRet, addinfourl]]: ... # undocumented def http_error_401( self, @@ -327,7 +311,7 @@ class FancyURLopener(URLopener): fp: IO[bytes], errcode: int, errmsg: str, - headers: Mapping[str, str], + headers: HTTPMessage, data: Optional[bytes] = ..., retry: bool = ..., ) -> Optional[_UrlopenRet]: ... # undocumented @@ -337,15 +321,15 @@ class FancyURLopener(URLopener): fp: IO[bytes], errcode: int, errmsg: str, - headers: Mapping[str, str], + headers: HTTPMessage, data: Optional[bytes] = ..., retry: bool = ..., ) -> Optional[_UrlopenRet]: ... # undocumented def http_error_default( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str] + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage ) -> addinfourl: ... # undocumented def redirect_internal( - self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: Mapping[str, str], data: Optional[bytes] + self, url: str, fp: IO[bytes], errcode: int, errmsg: str, headers: HTTPMessage, data: Optional[bytes] ) -> Optional[_UrlopenRet]: ... # undocumented def retry_http_basic_auth( self, url: str, realm: str, data: Optional[bytes] = ...