Skip to content

Commit 07a7b14

Browse files
committed
Drop Python 3.8, 3.9 and support 3.13, 3.14
This also fixes the various mypy issues with the codebase such that it passes.
1 parent 92a7b46 commit 07a7b14

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+360
-423
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ jobs:
1414
fail-fast: false
1515
matrix:
1616
include:
17+
- {name: '3.14', python: '3.14', tox: py314}
18+
- {name: '3.13', python: '3.13', tox: py313}
1719
- {name: '3.12', python: '3.12', tox: py312}
1820
- {name: '3.11', python: '3.11', tox: py311}
1921
- {name: '3.10', python: '3.10', tox: py310}
20-
- {name: '3.9', python: '3.9', tox: py39}
21-
- {name: '3.8', python: '3.8', tox: py38}
22-
- {name: 'format', python: '3.12', tox: format}
23-
- {name: 'mypy', python: '3.12', tox: mypy}
24-
- {name: 'pep8', python: '3.12', tox: pep8}
25-
- {name: 'package', python: '3.12', tox: package}
22+
- {name: 'format', python: '3.14', tox: format}
23+
- {name: 'mypy', python: '3.14', tox: mypy}
24+
- {name: 'pep8', python: '3.14', tox: pep8}
25+
- {name: 'package', python: '3.14', tox: package}
2626

2727
steps:
2828
- uses: actions/checkout@v4
@@ -56,7 +56,7 @@ jobs:
5656

5757
- uses: actions/setup-python@v5
5858
with:
59-
python-version: "3.12"
59+
python-version: "3.14"
6060

6161
- name: update pip
6262
run: |
@@ -92,7 +92,7 @@ jobs:
9292

9393
- uses: actions/setup-python@v5
9494
with:
95-
python-version: "3.10"
95+
python-version: "3.14"
9696

9797
- name: update pip
9898
run: |

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111

1212
- uses: actions/setup-python@v3
1313
with:
14-
python-version: 3.12
14+
python-version: 3.14
1515

1616
- run: |
1717
pip install pdm

.readthedocs.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
version: 2
22

33
build:
4-
os: ubuntu-22.04
4+
os: ubuntu-24.04
55
tools:
6-
python: "3.11"
6+
python: "3.14"
77

88
python:
99
install:

README.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ Hypercorn can be installed via `pip
3737
3838
$ pip install hypercorn
3939
40-
and requires Python 3.8 or higher.
41-
4240
With hypercorn installed ASGI frameworks (or apps) can be served via
4341
Hypercorn via the command line,
4442

docs/tutorials/installation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Installation
44
============
55

6-
Hypercorn is only compatible with Python 3.8 or higher and can be
6+
Hypercorn is only compatible with Python 3.10 or higher and can be
77
installed using pip or your favorite python package manager.
88

99
.. code-block:: sh

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ classifiers = [
1313
"Operating System :: OS Independent",
1414
"Programming Language :: Python",
1515
"Programming Language :: Python :: 3",
16-
"Programming Language :: Python :: 3.8",
17-
"Programming Language :: Python :: 3.9",
1816
"Programming Language :: Python :: 3.10",
1917
"Programming Language :: Python :: 3.11",
2018
"Programming Language :: Python :: 3.12",
19+
"Programming Language :: Python :: 3.13",
20+
"Programming Language :: Python :: 3.14",
2121
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
2222
"Topic :: Software Development :: Libraries :: Python Modules",
2323
]
@@ -28,15 +28,15 @@ repository = "https://github.com/pgjones/hypercorn/"
2828
dependencies = [
2929
"exceptiongroup >= 1.1.0; python_version < '3.11'",
3030
"h11",
31-
"h2 >= 3.1.0",
31+
"h2 >= 4.3.0",
3232
"priority",
3333
"taskgroup; python_version < '3.11'",
3434
"tomli; python_version < '3.11'",
3535
"typing_extensions; python_version < '3.11'",
3636
"wsproto >= 0.14.0"
3737
]
3838
documentation = "https://hypercorn.readthedocs.io"
39-
requires-python = ">=3.8"
39+
requires-python = ">=3.10"
4040

4141
[project.optional-dependencies]
4242
docs = ["pydata_sphinx_theme", "sphinxcontrib_mermaid"]
@@ -60,7 +60,7 @@ hypercorn = "hypercorn.__main__:main"
6060

6161
[tool.black]
6262
line-length = 100
63-
target-version = ["py38"]
63+
target-version = ["py310"]
6464

6565
[tool.isort]
6666
combine_as_imports = true

src/hypercorn/__main__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
import ssl
55
import sys
66
import warnings
7-
from typing import List, Optional
87

98
from .config import Config
109
from .run import run
1110

1211
sentinel = object()
1312

1413

15-
def _load_config(config_path: Optional[str]) -> Config:
14+
def _load_config(config_path: str | None) -> Config:
1615
if config_path is None:
1716
return Config()
1817
elif config_path.startswith("python:"):
@@ -23,7 +22,7 @@ def _load_config(config_path: Optional[str]) -> Config:
2322
return Config.from_toml(config_path)
2423

2524

26-
def main(sys_args: Optional[List[str]] = None) -> int:
25+
def main(sys_args: list[str] | None = None) -> int:
2726
parser = argparse.ArgumentParser()
2827
parser.add_argument(
2928
"application", help="The application to dispatch to as path.to.module:instance.path"

src/hypercorn/app_wrappers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from __future__ import annotations
22

33
import sys
4+
from collections.abc import Callable
45
from functools import partial
56
from io import BytesIO
6-
from typing import Callable, List, Optional, Tuple
77

88
from .typing import (
99
ASGIFramework,
@@ -76,22 +76,22 @@ async def handle_http(
7676
break
7777

7878
try:
79-
environ = _build_environ(scope, body)
79+
environ = _build_environ(scope, bytes(body))
8080
except InvalidPathError:
8181
await send({"type": "http.response.start", "status": 404, "headers": []})
8282
else:
8383
await sync_spawn(self.run_app, environ, partial(call_soon, send))
8484
await send({"type": "http.response.body", "body": b"", "more_body": False})
8585

8686
def run_app(self, environ: dict, send: Callable) -> None:
87-
headers: List[Tuple[bytes, bytes]]
87+
headers: list[tuple[bytes, bytes]]
8888
response_started = False
89-
status_code: Optional[int] = None
89+
status_code: int | None = None
9090

9191
def start_response(
9292
status: str,
93-
response_headers: List[Tuple[str, str]],
94-
exc_info: Optional[Exception] = None,
93+
response_headers: list[tuple[str, str]],
94+
exc_info: Exception | None = None,
9595
) -> None:
9696
nonlocal headers, response_started, status_code
9797

src/hypercorn/asyncio/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

33
import warnings
4-
from typing import Awaitable, Callable, Literal, Optional
4+
from collections.abc import Awaitable, Callable
5+
from typing import Literal
56

67
from .run import worker_serve
78
from ..config import Config
@@ -13,8 +14,8 @@ async def serve(
1314
app: Framework,
1415
config: Config,
1516
*,
16-
shutdown_trigger: Optional[Callable[..., Awaitable]] = None,
17-
mode: Optional[Literal["asgi", "wsgi"]] = None,
17+
shutdown_trigger: Callable[..., Awaitable] | None = None,
18+
mode: Literal["asgi", "wsgi"] | None = None,
1819
) -> None:
1920
"""Serve an ASGI or WSGI framework app given the config.
2021

src/hypercorn/asyncio/lifespan.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import asyncio
44
import sys
5+
from collections.abc import Callable
56
from functools import partial
6-
from typing import Any, Callable
7+
from typing import Any
78

89
from ..config import Config
910
from ..typing import AppWrapper, ASGIReceiveEvent, ASGISendEvent, LifespanScope, LifespanState

0 commit comments

Comments
 (0)