diff --git a/h11/_connection.py b/h11/_connection.py index a812298..e37d82a 100644 --- a/h11/_connection.py +++ b/h11/_connection.py @@ -428,7 +428,7 @@ def _extract_next_receive_event( # return that event, and then the state will change and we'll # get called again to generate the actual ConnectionClosed(). if hasattr(self._reader, "read_eof"): - event = self._reader.read_eof() # type: ignore[attr-defined] + event = self._reader.read_eof() else: event = ConnectionClosed() if event is None: @@ -505,7 +505,13 @@ def send(self, event: ConnectionClosed) -> None: ... @overload - def send(self, event: Event) -> bytes: + def send( + self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] + ) -> bytes: + ... + + @overload + def send(self, event: Event) -> Optional[bytes]: ... def send(self, event: Event) -> Optional[bytes]: diff --git a/h11/_events.py b/h11/_events.py index 075bf8a..ca1c3ad 100644 --- a/h11/_events.py +++ b/h11/_events.py @@ -7,8 +7,8 @@ import re from abc import ABC -from dataclasses import dataclass, field -from typing import Any, cast, Dict, List, Tuple, Union +from dataclasses import dataclass +from typing import List, Tuple, Union from ._abnf import method, request_target from ._headers import Headers, normalize_and_validate diff --git a/h11/tests/test_against_stdlib_http.py b/h11/tests/test_against_stdlib_http.py index f0eff63..3f66a10 100644 --- a/h11/tests/test_against_stdlib_http.py +++ b/h11/tests/test_against_stdlib_http.py @@ -13,7 +13,7 @@ @contextmanager def socket_server( - handler: Callable[..., socketserver.BaseRequestHandler] + handler: Callable[..., socketserver.BaseRequestHandler], ) -> Generator[socketserver.TCPServer, None, None]: httpd = socketserver.TCPServer(("127.0.0.1", 0), handler) thread = threading.Thread( @@ -39,17 +39,17 @@ def translate_path(self, path: str) -> str: def test_h11_as_client() -> None: with socket_server(SingleMindedRequestHandler) as httpd: - with closing(socket.create_connection(httpd.server_address)) as s: + with closing(socket.create_connection(httpd.server_address)) as s: # type: ignore[arg-type] c = h11.Connection(h11.CLIENT) s.sendall( - c.send( # type: ignore[arg-type] + c.send( h11.Request( method="GET", target="/foo", headers=[("Host", "localhost")] ) ) ) - s.sendall(c.send(h11.EndOfMessage())) # type: ignore[arg-type] + s.sendall(c.send(h11.EndOfMessage())) data = bytearray() while True: @@ -96,7 +96,7 @@ def handle(self) -> None: }, } ) - s.sendall(c.send(h11.Response(status_code=200, headers=[]))) # type: ignore[arg-type] + s.sendall(c.send(h11.Response(status_code=200, headers=[]))) s.sendall(c.send(h11.Data(data=info.encode("ascii")))) s.sendall(c.send(h11.EndOfMessage())) @@ -104,7 +104,7 @@ def handle(self) -> None: def test_h11_as_server() -> None: with socket_server(H11RequestHandler) as httpd: host, port = httpd.server_address - url = f"http://{host}:{port}/some-path" + url = f"http://{host}:{port}/some-path" # type: ignore[str-bytes-safe] with closing(urlopen(url)) as f: assert f.getcode() == 200 data = f.read() diff --git a/h11/tests/test_connection.py b/h11/tests/test_connection.py index f45cb97..01260dc 100644 --- a/h11/tests/test_connection.py +++ b/h11/tests/test_connection.py @@ -7,7 +7,6 @@ ConnectionClosed, Data, EndOfMessage, - Event, InformationalResponse, Request, Response, @@ -17,7 +16,6 @@ CLOSED, DONE, ERROR, - IDLE, MIGHT_SWITCH_PROTOCOL, MUST_CLOSE, SEND_BODY, @@ -48,15 +46,15 @@ def test__keep_alive() -> None: ) ) assert not _keep_alive( - Request(method="GET", target="/", headers=[], http_version="1.0") # type: ignore[arg-type] + Request(method="GET", target="/", headers=[], http_version="1.0") ) - assert _keep_alive(Response(status_code=200, headers=[])) # type: ignore[arg-type] + assert _keep_alive(Response(status_code=200, headers=[])) assert not _keep_alive(Response(status_code=200, headers=[("Connection", "close")])) assert not _keep_alive( Response(status_code=200, headers=[("Connection", "a, b, cLOse, foo")]) ) - assert not _keep_alive(Response(status_code=200, headers=[], http_version="1.0")) # type: ignore[arg-type] + assert not _keep_alive(Response(status_code=200, headers=[], http_version="1.0")) def test__body_framing() -> None: @@ -135,7 +133,7 @@ def test_Connection_basics_and_content_length() -> None: assert p.conn[CLIENT].their_http_version is None assert p.conn[SERVER].their_http_version == b"1.1" - data = p.send(SERVER, InformationalResponse(status_code=100, headers=[])) # type: ignore[arg-type] + data = p.send(SERVER, InformationalResponse(status_code=100, headers=[])) assert data == b"HTTP/1.1 100 \r\n\r\n" data = p.send(SERVER, Response(status_code=200, headers=[("Content-Length", "11")])) @@ -247,7 +245,7 @@ def test_client_talking_to_http10_server() -> None: assert c.our_state is DONE # No content-length, so Http10 framing for body assert receive_and_get(c, b"HTTP/1.0 200 OK\r\n\r\n") == [ - Response(status_code=200, headers=[], http_version="1.0", reason=b"OK") # type: ignore[arg-type] + Response(status_code=200, headers=[], http_version="1.0", reason=b"OK") ] assert c.our_state is MUST_CLOSE assert receive_and_get(c, b"12345") == [Data(data=b"12345")] @@ -261,14 +259,14 @@ def test_server_talking_to_http10_client() -> None: # No content-length, so no body # NB: no host header assert receive_and_get(c, b"GET / HTTP/1.0\r\n\r\n") == [ - Request(method="GET", target="/", headers=[], http_version="1.0"), # type: ignore[arg-type] + Request(method="GET", target="/", headers=[], http_version="1.0"), EndOfMessage(), ] assert c.their_state is MUST_CLOSE # We automatically Connection: close back at them assert ( - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\nConnection: close\r\n\r\n" ) @@ -356,7 +354,7 @@ def test_automagic_connection_close_handling() -> None: p.send( SERVER, # no header here... - [Response(status_code=204, headers=[]), EndOfMessage()], # type: ignore[arg-type] + [Response(status_code=204, headers=[]), EndOfMessage()], # ...but oh look, it arrived anyway expect=[ Response(status_code=204, headers=[("connection", "close")]), @@ -390,7 +388,7 @@ def setup() -> ConnectionPair: # Disabled by 100 Continue p = setup() - p.send(SERVER, InformationalResponse(status_code=100, headers=[])) # type: ignore[arg-type] + p.send(SERVER, InformationalResponse(status_code=100, headers=[])) for conn in p.conns: assert not conn.client_is_waiting_for_100_continue assert not conn.they_are_waiting_for_100_continue @@ -471,7 +469,7 @@ def test_max_incomplete_event_size_countermeasure() -> None: # Even more data comes in, still no problem c.receive_data(b"X" * 1000) # We can respond and reuse to get the second pipelined request - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) c.start_next_cycle() assert get_all_events(c) == [ @@ -481,7 +479,7 @@ def test_max_incomplete_event_size_countermeasure() -> None: # But once we unpause and try to read the next message, and find that it's # incomplete and the buffer is *still* way too large, then *that's* a # problem: - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) c.start_next_cycle() with pytest.raises(RemoteProtocolError): @@ -547,7 +545,7 @@ def test_pipelining() -> None: assert c.next_event() is PAUSED - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) assert c.their_state is DONE assert c.our_state is DONE @@ -564,7 +562,7 @@ def test_pipelining() -> None: EndOfMessage(), ] assert c.next_event() is PAUSED - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) c.start_next_cycle() @@ -574,7 +572,7 @@ def test_pipelining() -> None: ] # Doesn't pause this time, no trailing data assert c.next_event() is NEED_DATA - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) # Arrival of more data triggers pause @@ -683,7 +681,7 @@ def setup() -> ConnectionPair: sc.send(EndOfMessage()) sc.start_next_cycle() assert get_all_events(sc) == [ - Request(method="GET", target="/", headers=[], http_version="1.0"), # type: ignore[arg-type] + Request(method="GET", target="/", headers=[], http_version="1.0"), EndOfMessage(), ] @@ -845,7 +843,7 @@ def test_pipelined_close() -> None: EndOfMessage(), ] assert c.states[CLIENT] is DONE - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) assert c.states[SERVER] is DONE c.start_next_cycle() @@ -860,7 +858,7 @@ def test_pipelined_close() -> None: ConnectionClosed(), ] assert c.states == {CLIENT: CLOSED, SERVER: SEND_RESPONSE} - c.send(Response(status_code=200, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) c.send(EndOfMessage()) assert c.states == {CLIENT: CLOSED, SERVER: MUST_CLOSE} c.send(ConnectionClosed()) @@ -919,7 +917,7 @@ def test_errors() -> None: # But we can still yell at the client for sending us gibberish if role is SERVER: assert ( - c.send(Response(status_code=400, headers=[])) # type: ignore[arg-type] + c.send(Response(status_code=400, headers=[])) == b"HTTP/1.1 400 \r\nConnection: close\r\n\r\n" ) @@ -946,8 +944,8 @@ def conn(role: Type[Sentinel]) -> Connection: http_version="1.0", ) elif role is SERVER: - good = Response(status_code=200, headers=[]) # type: ignore[arg-type,assignment] - bad = Response(status_code=200, headers=[], http_version="1.0") # type: ignore[arg-type,assignment] + good = Response(status_code=200, headers=[]) # type: ignore[assignment] + bad = Response(status_code=200, headers=[], http_version="1.0") # type: ignore[assignment] # Make sure 'good' actually is good c = conn(role) c.send(good) @@ -1063,14 +1061,14 @@ def setup(method: bytes, http_version: bytes) -> Connection: # No Content-Length, HTTP/1.1 peer, should use chunked c = setup(method, b"1.1") assert ( - c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" b"Transfer-Encoding: chunked\r\n\r\n" ) # No Content-Length, HTTP/1.0 peer, frame with connection: close c = setup(method, b"1.0") assert ( - c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" # type: ignore[arg-type] + c.send(Response(status_code=200, headers=[])) == b"HTTP/1.1 200 \r\n" b"Connection: close\r\n\r\n" ) diff --git a/h11/tests/test_events.py b/h11/tests/test_events.py index bc6c313..d691545 100644 --- a/h11/tests/test_events.py +++ b/h11/tests/test_events.py @@ -2,12 +2,10 @@ import pytest -from .. import _events from .._events import ( ConnectionClosed, Data, EndOfMessage, - Event, InformationalResponse, Request, Response, @@ -101,13 +99,13 @@ def test_events() -> None: with pytest.raises(LocalProtocolError): InformationalResponse(status_code=200, headers=[("Host", "a")]) - resp = Response(status_code=204, headers=[], http_version="1.0") # type: ignore[arg-type] + resp = Response(status_code=204, headers=[], http_version="1.0") assert resp.status_code == 204 assert resp.headers == [] assert resp.http_version == b"1.0" with pytest.raises(LocalProtocolError): - resp = Response(status_code=100, headers=[], http_version="1.0") # type: ignore[arg-type] + resp = Response(status_code=100, headers=[], http_version="1.0") with pytest.raises(LocalProtocolError): Response(status_code="100", headers=[], http_version="1.0") # type: ignore[arg-type] @@ -128,7 +126,7 @@ def test_events() -> None: def test_intenum_status_code() -> None: # https://github.com/python-hyper/h11/issues/72 - r = Response(status_code=HTTPStatus.OK, headers=[], http_version="1.0") # type: ignore[arg-type] + r = Response(status_code=HTTPStatus.OK, headers=[], http_version="1.0") assert r.status_code == HTTPStatus.OK assert type(r.status_code) is not type(HTTPStatus.OK) assert type(r.status_code) is int diff --git a/h11/tests/test_helpers.py b/h11/tests/test_helpers.py index c329c76..9a30dc6 100644 --- a/h11/tests/test_helpers.py +++ b/h11/tests/test_helpers.py @@ -1,12 +1,4 @@ -from .._events import ( - ConnectionClosed, - Data, - EndOfMessage, - Event, - InformationalResponse, - Request, - Response, -) +from .._events import Data, EndOfMessage, Response from .helpers import normalize_data_events @@ -15,7 +7,7 @@ def test_normalize_data_events() -> None: [ Data(data=bytearray(b"1")), Data(data=b"2"), - Response(status_code=200, headers=[]), # type: ignore[arg-type] + Response(status_code=200, headers=[]), Data(data=b"3"), Data(data=b"4"), EndOfMessage(), @@ -25,7 +17,7 @@ def test_normalize_data_events() -> None: ] ) == [ Data(data=b"12"), - Response(status_code=200, headers=[]), # type: ignore[arg-type] + Response(status_code=200, headers=[]), Data(data=b"34"), EndOfMessage(), Data(data=b"567"), diff --git a/h11/tests/test_io.py b/h11/tests/test_io.py index 2874122..42137b0 100644 --- a/h11/tests/test_io.py +++ b/h11/tests/test_io.py @@ -3,7 +3,6 @@ import pytest from .._events import ( - ConnectionClosed, Data, EndOfMessage, Event, @@ -20,18 +19,7 @@ READERS, ) from .._receivebuffer import ReceiveBuffer -from .._state import ( - CLIENT, - CLOSED, - DONE, - IDLE, - MIGHT_SWITCH_PROTOCOL, - MUST_CLOSE, - SEND_BODY, - SEND_RESPONSE, - SERVER, - SWITCHED_PROTOCOL, -) +from .._state import CLIENT, IDLE, SEND_RESPONSE, SERVER from .._util import LocalProtocolError from .._writers import ( ChunkedWriter, @@ -61,7 +49,7 @@ ), ( (SERVER, SEND_RESPONSE), - Response(status_code=200, headers=[], reason=b"OK"), # type: ignore[arg-type] + Response(status_code=200, headers=[], reason=b"OK"), b"HTTP/1.1 200 OK\r\n\r\n", ), ( @@ -73,7 +61,7 @@ ), ( (SERVER, SEND_RESPONSE), - InformationalResponse(status_code=101, headers=[], reason=b"Upgrade"), # type: ignore[arg-type] + InformationalResponse(status_code=101, headers=[], reason=b"Upgrade"), b"HTTP/1.1 101 Upgrade\r\n\r\n", ), ] @@ -182,7 +170,7 @@ def test_readers_unusual() -> None: tr( READERS[CLIENT, IDLE], b"HEAD /foo HTTP/1.0\r\n\r\n", - Request(method="HEAD", target="/foo", headers=[], http_version="1.0"), # type: ignore[arg-type] + Request(method="HEAD", target="/foo", headers=[], http_version="1.0"), ) tr( diff --git a/pyproject.toml b/pyproject.toml index edd11ae..64a6883 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,3 +38,9 @@ showcontent = true directory = "misc" name = "Miscellaneous internal changes" showcontent = true + +[tool.mypy] +strict = true +warn_unused_configs = true +warn_unused_ignores = true +show_error_codes = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 85dcc1f..0000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[mypy] -strict = true -warn_unused_configs = true -warn_unused_ignores = true -show_error_codes = true diff --git a/tox.ini b/tox.ini index 8394aa1..a28db7d 100644 --- a/tox.ini +++ b/tox.ini @@ -3,10 +3,10 @@ envlist = format, py{38, 39, 310, 311, 312, py3}, mypy [gh-actions] python = - 3.8: py38 + 3.8: py38, format, mypy 3.9: py39 3.10: py310 - 3.11: py311, format, mypy + 3.11: py311 3.12: py312 pypy-3.9: pypy3 pypy-3.10: pypy3 @@ -16,7 +16,7 @@ deps = -r{toxinidir}/test-requirements.txt commands = pytest --cov=h11 --cov-config=.coveragerc h11 [testenv:format] -basepython = python3.10 +basepython = python3.8 deps = -r{toxinidir}/format-requirements.txt commands = black --check --diff h11/ bench/ examples/ fuzz/ @@ -25,7 +25,7 @@ commands = [testenv:mypy] basepython = python3.8 deps = - mypy + mypy==1.8.0 pytest commands = mypy h11/