Merge pull request #114 from sbidoul/upgrade-deps

Upgrade dependencies, use Python 3.13
This commit is contained in:
Stéphane Bidoul 2025-03-01 14:11:53 +01:00 committed by GitHub
commit df8ae030fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 69 additions and 63 deletions

View file

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
python-version: ["3.12"] python-version: ["3.13"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v4 - uses: actions/setup-python@v4

View file

@ -2,14 +2,14 @@ default_language_version:
python: python3 python: python3
repos: repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0 rev: v5.0.0
hooks: hooks:
- id: check-toml - id: check-toml
- id: check-yaml - id: check-yaml
- id: end-of-file-fixer - id: end-of-file-fixer
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0 rev: v0.9.9
hooks: hooks:
- id: ruff - id: ruff
- id: ruff-format - id: ruff-format

View file

@ -1,4 +1,4 @@
FROM python:3.12 FROM python:3.13
LABEL maintainer="Stéphane Bidoul" LABEL maintainer="Stéphane Bidoul"

View file

@ -60,7 +60,7 @@ For running the builds:
For running the controller (runboat itself): For running the controller (runboat itself):
- Python 3.12 - Python 3.13
- sqlite3 >= 3.25 - sqlite3 >= 3.25
- `kubectl` - `kubectl`
- A `KUBECONFIG` or an in-cluster service account that provides access to the namespace - A `KUBECONFIG` or an in-cluster service account that provides access to the namespace

View file

@ -11,7 +11,7 @@ classifiers = [
] ]
dependencies = [ dependencies = [
"ansi2html", "ansi2html",
"fastapi>=0.93", "fastapi[all]>=0.112",
"gunicorn", "gunicorn",
"httpx", "httpx",
"jinja2", "jinja2",
@ -22,7 +22,7 @@ dependencies = [
"sse-starlette", "sse-starlette",
"uvicorn", "uvicorn",
] ]
requires-python = "==3.12.*" requires-python = "==3.13.*"
dynamic = ["version", "description"] dynamic = ["version", "description"]
[project.optional-dependencies] [project.optional-dependencies]
@ -58,6 +58,7 @@ select = [
"T20", # flake8-print "T20", # flake8-print
"PLE", # pylint errors "PLE", # pylint errors
"RUF", "RUF",
"FAST", # fastapi
] ]
[tool.ruff.lint.mccabe] [tool.ruff.lint.mccabe]

View file

@ -1,4 +1,4 @@
# frozen requirements generated by pip-deepfreeze # frozen requirements generated by pip-deepfreeze
mypy==1.10.1 mypy==1.15.0
mypy-extensions==1.0.0 mypy-extensions==1.0.0
types-urllib3==1.26.25.14 types-urllib3==1.26.25.14

View file

@ -1,9 +1,9 @@
# frozen requirements generated by pip-deepfreeze # frozen requirements generated by pip-deepfreeze
coverage==7.5.4 coverage==7.6.12
iniconfig==2.0.0 iniconfig==2.0.0
pluggy==1.5.0 pluggy==1.5.0
pytest==8.2.2 pytest==8.3.4
pytest-asyncio==0.23.7 pytest-asyncio==0.25.3
pytest-cov==5.0.0 pytest-cov==6.0.0
pytest-dotenv==0.5.2 pytest-dotenv==0.5.2
pytest-mock==3.14.0 pytest-mock==3.14.0

View file

@ -1,55 +1,59 @@
# frozen requirements generated by pip-deepfreeze # frozen requirements generated by pip-deepfreeze
annotated-types==0.7.0 annotated-types==0.7.0
ansi2html==1.9.2 ansi2html==1.9.2
anyio==4.4.0 anyio==4.8.0
cachetools==5.3.3 cachetools==5.5.2
certifi==2024.7.4 certifi==2025.1.31
charset-normalizer==3.3.2 charset-normalizer==3.4.1
click==8.1.7 click==8.1.8
dnspython==2.6.1 dnspython==2.7.0
durationpy==0.9
email-validator==2.2.0 email-validator==2.2.0
fastapi==0.111.0 fastapi==0.115.10
fastapi-cli==0.0.4 fastapi-cli==0.0.7
google-auth==2.31.0 google-auth==2.38.0
gunicorn==22.0.0 gunicorn==23.0.0
h11==0.14.0 h11==0.14.0
httpcore==1.0.5 httpcore==1.0.7
httptools==0.6.1 httptools==0.6.4
httpx==0.27.0 httpx==0.28.1
idna==3.7 idna==3.10
jinja2==3.1.4 itsdangerous==2.2.0
kubernetes==30.1.0 jinja2==3.1.5
kubernetes==32.0.1
markdown-it-py==3.0.0 markdown-it-py==3.0.0
markupsafe==2.1.5 markupsafe==3.0.2
mdurl==0.1.2 mdurl==0.1.2
oauthlib==3.2.2 oauthlib==3.2.2
orjson==3.10.6 orjson==3.10.15
packaging==24.1 packaging==24.2
pyasn1==0.6.0 pyasn1==0.6.1
pyasn1-modules==0.4.0 pyasn1-modules==0.4.1
pydantic==2.8.2 pydantic==2.10.6
pydantic-core==2.20.1 pydantic-core==2.27.2
pydantic-settings==2.3.4 pydantic-extra-types==2.10.2
pygments==2.18.0 pydantic-settings==2.8.1
pygments==2.19.1
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
python-dotenv==1.0.1 python-dotenv==1.0.1
python-multipart==0.0.9 python-multipart==0.0.20
pyyaml==6.0.1 pyyaml==6.0.2
requests==2.32.3 requests==2.32.3
requests-oauthlib==2.0.0 requests-oauthlib==2.0.0
rich==13.7.1 rich==13.9.4
rich-toolkit==0.13.2
rsa==4.9 rsa==4.9
shellingham==1.5.4 shellingham==1.5.4
six==1.16.0 six==1.17.0
sniffio==1.3.1 sniffio==1.3.1
sse-starlette==2.1.2 sse-starlette==2.2.1
starlette==0.37.2 starlette==0.46.0
typer==0.12.3 typer==0.15.2
typing-extensions==4.12.2 typing-extensions==4.12.2
ujson==5.10.0 ujson==5.10.0
urllib3==2.2.2 urllib3==2.3.0
uvicorn==0.30.1 uvicorn==0.34.0
uvloop==0.19.0 uvloop==0.21.0
watchfiles==0.22.0 watchfiles==1.0.4
websocket-client==1.8.0 websocket-client==1.8.0
websockets==12.0 websockets==15.0

View file

@ -224,7 +224,7 @@ class BuildEventSource:
return return
self.queue.put_nowait(self._serialize(event, build)) self.queue.put_nowait(self._serialize(event, build))
async def events(self) -> AsyncGenerator[str, None]: async def events(self) -> AsyncGenerator[str]:
for build in controller.db.search( for build in controller.db.search(
repo=self.repo, repo=self.repo,
target_branch=self.target_branch, target_branch=self.target_branch,

View file

@ -7,7 +7,7 @@ from . import __version__, api, controller, k8s, webhooks, webui
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
await k8s.load_kube_config() await k8s.load_kube_config()
await controller.controller.start() await controller.controller.start()
yield yield

View file

@ -86,7 +86,7 @@ class WatchException(Exception):
def _watch( def _watch(
list_method: Callable[..., Any], *args: Any, **kwargs: Any list_method: Callable[..., Any], *args: Any, **kwargs: Any
) -> Generator[tuple[str | None, Any], None, None]: ) -> Generator[tuple[str | None, Any]]:
while True: while True:
try: try:
# perform a first query # perform a first query
@ -121,7 +121,7 @@ def _watch(
@sync_to_async_iterator @sync_to_async_iterator
def watch_deployments() -> Generator[V1Deployment, None, None]: def watch_deployments() -> Generator[V1Deployment]:
appsv1 = client.AppsV1Api() appsv1 = client.AppsV1Api()
yield from _watch( yield from _watch(
appsv1.list_namespaced_deployment, namespace=settings.build_namespace appsv1.list_namespaced_deployment, namespace=settings.build_namespace
@ -129,7 +129,7 @@ def watch_deployments() -> Generator[V1Deployment, None, None]:
@sync_to_async_iterator @sync_to_async_iterator
def watch_jobs() -> Generator[V1Job, None, None]: def watch_jobs() -> Generator[V1Job]:
batchv1 = client.BatchV1Api() batchv1 = client.BatchV1Api()
yield from _watch(batchv1.list_namespaced_job, namespace=settings.build_namespace) yield from _watch(batchv1.list_namespaced_job, namespace=settings.build_namespace)
@ -178,7 +178,7 @@ def make_deployment_vars(
@contextmanager @contextmanager
def _get_kubefiles_path(kubefiles_path: Path | None) -> Generator[Path, None, None]: def _get_kubefiles_path(kubefiles_path: Path | None) -> Generator[Path]:
if kubefiles_path: if kubefiles_path:
yield kubefiles_path yield kubefiles_path
else: else:
@ -191,7 +191,7 @@ def _get_kubefiles_path(kubefiles_path: Path | None) -> Generator[Path, None, No
@contextmanager @contextmanager
def _render_kubefiles( def _render_kubefiles(
kubefiles_path: Path | None, deployment_vars: DeploymentVars kubefiles_path: Path | None, deployment_vars: DeploymentVars
) -> Generator[Path, None, None]: ) -> Generator[Path]:
with ( with (
_get_kubefiles_path(kubefiles_path) as kubefiles_path, _get_kubefiles_path(kubefiles_path) as kubefiles_path,
tempfile.TemporaryDirectory() as tmp_dir, tempfile.TemporaryDirectory() as tmp_dir,
@ -299,7 +299,7 @@ def log(build_name: str, job_kind: DeploymentMode | None) -> str | None:
container=pod.metadata.annotations.get( container=pod.metadata.annotations.get(
"kubectl.kubernetes.io/default-container" "kubectl.kubernetes.io/default-container"
), ),
tail_lines=None if job_kind else None, tail_lines=None,
follow=False, follow=False,
), ),
) )

View file

@ -28,8 +28,8 @@ def sync_to_async(func: Callable[P, R]) -> Callable[P, Awaitable[R]]:
def sync_to_async_iterator( def sync_to_async_iterator(
iterator_func: Callable[P, Generator[R, None, None]], iterator_func: Callable[P, Generator[R]],
) -> Callable[P, AsyncGenerator[R, None]]: ) -> Callable[P, AsyncGenerator[R]]:
@sync_to_async @sync_to_async
def async_next(iterator: Iterator[R]) -> R: def async_next(iterator: Iterator[R]) -> R:
try: try:
@ -38,11 +38,11 @@ def sync_to_async_iterator(
raise StopAsyncIteration() from e raise StopAsyncIteration() from e
@sync_to_async @sync_to_async
def async_iterator_func(*args: Any, **kwargs: Any) -> Generator[R, None, None]: def async_iterator_func(*args: Any, **kwargs: Any) -> Generator[R]:
return iterator_func(*args, **kwargs) return iterator_func(*args, **kwargs)
@wraps(iterator_func) @wraps(iterator_func)
async def inner(*args: Any, **kwargs: Any) -> AsyncGenerator[R, None]: async def inner(*args: Any, **kwargs: Any) -> AsyncGenerator[R]:
iterator = await async_iterator_func(*args, **kwargs) iterator = await async_iterator_func(*args, **kwargs)
while True: while True:
try: try:

View file

@ -1,5 +1,6 @@
import hmac import hmac
import logging import logging
from typing import Annotated
from fastapi import APIRouter, BackgroundTasks, Header, Request from fastapi import APIRouter, BackgroundTasks, Header, Request
@ -31,8 +32,8 @@ def _verify_github_signature(
async def receive_payload( async def receive_payload(
background_tasks: BackgroundTasks, background_tasks: BackgroundTasks,
request: Request, request: Request,
x_github_event: str = Header(...), x_github_event: Annotated[str, Header(...)],
x_hub_signature_256: str | None = Header(None), x_hub_signature_256: Annotated[str | None, Header(...)] = None,
) -> None: ) -> None:
body = await request.body() body = await request.body()
if not _verify_github_signature( if not _verify_github_signature(