Skip to content

Commit

Permalink
Correct annotation of headers parameter of HTTP event handlers (#5854)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
mthuurne committed Aug 6, 2021
1 parent 59624ff commit 9bba8a4
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 40 deletions.
4 changes: 2 additions & 2 deletions stdlib/urllib/error.pyi
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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]
Expand Down
60 changes: 22 additions & 38 deletions stdlib/urllib/request.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -111,28 +111,20 @@ 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):
max_redirections: ClassVar[int] # undocumented
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
Expand Down Expand Up @@ -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
Expand All @@ -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: ...
Expand All @@ -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: ...
Expand Down Expand Up @@ -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
Expand All @@ -310,24 +294,24 @@ 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,
url: str,
fp: IO[bytes],
errcode: int,
errmsg: str,
headers: Mapping[str, str],
headers: HTTPMessage,
data: Optional[bytes] = ...,
retry: bool = ...,
) -> Optional[_UrlopenRet]: ... # undocumented
Expand All @@ -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] = ...
Expand Down

0 comments on commit 9bba8a4

Please sign in to comment.