From f5d926ae290eea17436e29b9a1d851f44c4ccb8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Gremaud?= Date: Fri, 12 Jun 2026 01:33:24 +0200 Subject: [PATCH] fix: basedpyright + rank annotation --- highscore/scores/api/schemas.py | 4 +- highscore/scores/api/views.py | 33 +++++++++++----- prek.toml | 6 +++ pyproject.toml | 12 ++++++ uv.lock | 69 +++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 12 deletions(-) diff --git a/highscore/scores/api/schemas.py b/highscore/scores/api/schemas.py index d8ec750..afa9070 100644 --- a/highscore/scores/api/schemas.py +++ b/highscore/scores/api/schemas.py @@ -10,15 +10,15 @@ class ScoreIn(Schema, BaseSchema): class ScoreOut(Schema, BaseSchema): - id: int username: str points: int version: str | None created_at: str + rank: int @staticmethod def resolve_version(obj: Score) -> str | None: - return obj.version.name if obj.version_id else None + return obj.version.name if obj.version is not None else None @staticmethod def resolve_created_at(obj: Score) -> str: diff --git a/highscore/scores/api/views.py b/highscore/scores/api/views.py index a683b2c..f44ab15 100644 --- a/highscore/scores/api/views.py +++ b/highscore/scores/api/views.py @@ -1,5 +1,8 @@ from typing import Annotated +from django.db.models import F, QuerySet +from django.db.models.expressions import Window +from django.db.models.functions import Rank from django.http import HttpRequest from ninja import Header from ninja.pagination import PageNumberPagination, paginate @@ -11,14 +14,15 @@ from .schemas import ScoreIn, ScoreOut router = CamelCaseRouter() +GameVersionHeader = Annotated[str | None, Header(alias="X-Game-Version")] # pyright: ignore[reportCallIssue] -def _resolve_version(name: str | None) -> Version: + +def resolve_version(name: str | None) -> Version: if name: version, _ = Version.objects.get_or_create(name=name) return version - version = Version.objects.order_by("-created_at").first() - if version is None: - version = Version.objects.create(name="default") + + version, _ = Version.objects.get_or_create(name="default") return version @@ -26,9 +30,9 @@ def _resolve_version(name: str | None) -> Version: def submit_score( request: HttpRequest, payload: ScoreIn, - x_game_version: Annotated[str | None, Header(alias="X-Game-Version")] = None, + x_game_version: GameVersionHeader = None, ) -> Score: - version = _resolve_version(x_game_version) + version = resolve_version(x_game_version) return Score.objects.create(username=payload.username, points=payload.points, version=version) @@ -36,7 +40,16 @@ def submit_score( @paginate(PageNumberPagination, page_size=20) def list_scores( request: HttpRequest, - x_game_version: Annotated[str | None, Header(alias="X-Game-Version")] = None, -) -> list[Score]: - version = _resolve_version(x_game_version) - return Score.objects.filter(version=version).select_related("version") + x_game_version: GameVersionHeader = None, +) -> QuerySet[Score]: + version = resolve_version(x_game_version) + return ( + Score.objects.filter(version=version) + .select_related("version") + .annotate( + rank=Window( + expression=Rank(), + order_by=F("points").desc(), + ) + ) + ) diff --git a/prek.toml b/prek.toml index 2e2ef31..63946db 100644 --- a/prek.toml +++ b/prek.toml @@ -29,6 +29,12 @@ hooks = [ { id = "uv-lock" }, ] +[[repos]] +repo = "local" +hooks = [ + { id = "basedpyright", name = "basedpyright", entry = "uv run basedpyright highscore/", language = "system", types = ["python"], pass_filenames = false }, +] + [[repos]] repo = "builtin" hooks = [ diff --git a/pyproject.toml b/pyproject.toml index bbc36a7..5e29bda 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,9 @@ dependencies = [ [dependency-groups] dev = [ + "basedpyright>=1.39.7", "django-extensions>=4.1", + "django-stubs>=6.0.5", "ipython>=9.14.1", "ruff>=0.15.17", ] @@ -48,3 +50,13 @@ ignore = [ [tool.ruff.lint.isort] known-first-party = ["app", "scores"] + +[tool.basedpyright] +pythonVersion = "3.13" +venvPath = "." +venv = ".venv" +include = ["highscore"] +typeCheckingMode = "standard" + +[tool.django-stubs] +django_settings_module = "app.settings" diff --git a/uv.lock b/uv.lock index 981e6c5..73c1516 100644 --- a/uv.lock +++ b/uv.lock @@ -29,6 +29,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, ] +[[package]] +name = "basedpyright" +version = "1.39.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodejs-wheel-binaries" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/e5/0d685b5808436c628ab8b9edad6810b889d11044a962bc42b128543910ea/basedpyright-1.39.7.tar.gz", hash = "sha256:688d913a19c417870c164c630ed9cdd83a8d8b484b30ab8e99f5dec4ae9604a6", size = 25503256, upload-time = "2026-06-07T11:33:27.266Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/f4/5b1e8ea279ce8f97a6bb1518c84fa25f5794022053ce10eab22ad3f0b51b/basedpyright-1.39.7-py3-none-any.whl", hash = "sha256:81266deb6044c9be98fb4555e4b7b1a521d8aee06b66e80858d183b0e3991140", size = 13182666, upload-time = "2026-06-07T11:33:24.119Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -86,6 +98,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/21/0c/25f72060a39632fbd2d90e9c8b6052a09cd45b0598fc06c0758d313f0052/django_ninja-1.6.2-py3-none-any.whl", hash = "sha256:20095f5900bada22ea00cf1a58af50bdb285b2354c61a9d9b47d0dc89ac462d6", size = 2374994, upload-time = "2026-03-18T20:06:45.676Z" }, ] +[[package]] +name = "django-stubs" +version = "6.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "django-stubs-ext" }, + { name = "types-pyyaml" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/8a/8946216758eb66c5700a235e230af538d4ea474244c79452159b580425ba/django_stubs-6.0.5.tar.gz", hash = "sha256:7742b8e60afc68a8545158e2bdb103376d5a092f7902c17f370920a9c08eb957", size = 280490, upload-time = "2026-05-25T08:47:02.291Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/09/64ff51a4cf4e8bdf8423d249b32eca0676e69233009ce9cd5478ba2c9635/django_stubs-6.0.5-py3-none-any.whl", hash = "sha256:9fb9eede9b2fc47b36c3dc4a93652eb959dff45466ec4a580e4a22782192d746", size = 544132, upload-time = "2026-05-25T08:47:00.332Z" }, +] + +[[package]] +name = "django-stubs-ext" +version = "6.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/01/419bc3cd882f3ec645d5a4511085202dd6bd3ef8d385871dcd2d32cc15b3/django_stubs_ext-6.0.5.tar.gz", hash = "sha256:1cc325e991303849bce70e19748981b225ef08b37256f263e113caf97cd3bcc0", size = 6666, upload-time = "2026-05-25T08:46:36.012Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/bf/7ee71071d84ad4e0efcd77e2681afed254a5f65c27524441a9caf8c60467/django_stubs_ext-6.0.5-py3-none-any.whl", hash = "sha256:a9932c8233d6dd4e34ae0b192026379c1a9be8f0b7c27aa1fa09ae215169773e", size = 10362, upload-time = "2026-05-25T08:46:34.467Z" }, +] + [[package]] name = "executing" version = "2.2.1" @@ -153,6 +193,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/09/5b161152e2d90f7b87f781c2e1267494aef9c32498df793f73ad0a0a494a/matplotlib_inline-0.2.2-py3-none-any.whl", hash = "sha256:3c821cf1c209f59fb2d2d64abbf5b23b67bcb2210d663f9918dd851c6da1fcf6", size = 9534, upload-time = "2026-05-08T17:33:32.055Z" }, ] +[[package]] +name = "nodejs-wheel-binaries" +version = "24.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/22/2a5beb4e21417c73233d9f65cf6f3e96e891b80d2f550a8f630ebc6b88c6/nodejs_wheel_binaries-24.16.0.tar.gz", hash = "sha256:c973cb69dc5fd16e6f6dc6e579e2c3d5534e2a1f57619dddf5ba070efa7dde37", size = 8056, upload-time = "2026-05-30T16:52:09.807Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/d1/68b43b53cd0fa83ae6fd406705023ca988d9e0ca41c724d82e66fbeb2ef6/nodejs_wheel_binaries-24.16.0-py2.py3-none-macosx_13_0_arm64.whl", hash = "sha256:d9f8f677dcf30e37ac244f07869726abe043f01eb0f45722b1df31cc2af7093c", size = 55666374, upload-time = "2026-05-30T16:51:39.588Z" }, + { url = "https://files.pythonhosted.org/packages/e9/b2/40a989159599080da485de966c4c2d207e852ac7aa7864702626d96c8bf5/nodejs_wheel_binaries-24.16.0-py2.py3-none-macosx_13_0_x86_64.whl", hash = "sha256:3d0370fe7120ce9697a4f60d40480d2bd8808d9f30131458d5afc0040d4e5a51", size = 55838487, upload-time = "2026-05-30T16:51:43.383Z" }, + { url = "https://files.pythonhosted.org/packages/d7/a7/cd42174fb5ff6faff7fa8d326a18914d8f232098ab5de055b57c16fa13ca/nodejs_wheel_binaries-24.16.0-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:85dc92bbb79c851569c5925dcc2a4c915a034efab375f99e4e7e6bbe9cca8342", size = 60179540, upload-time = "2026-05-30T16:51:47.036Z" }, + { url = "https://files.pythonhosted.org/packages/2b/95/c8a1f9ae140aa28df8744d984d01d4b3af7cdd6555af12127f40ceb45a7d/nodejs_wheel_binaries-24.16.0-py2.py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:2f3036292811514ba847b3708492644764f88a833ac425c5f55007014308ddfd", size = 60716262, upload-time = "2026-05-30T16:51:50.711Z" }, + { url = "https://files.pythonhosted.org/packages/64/c9/7c35b3737f59e36d0249c265397b7bff570519b95301d6e16ea361e904ad/nodejs_wheel_binaries-24.16.0-py2.py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:db8a8a76ebd2b28ecbfc9ad464baa3707241b9e050a30e2efdf6f60c0f886502", size = 62230592, upload-time = "2026-05-30T16:51:55Z" }, + { url = "https://files.pythonhosted.org/packages/04/96/d931255cf9d11a84d6b54d882dba7434646467d568ccf070ea3418638df3/nodejs_wheel_binaries-24.16.0-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:f1a3d8f7b4491cbbd023ba3fc4e901fcca2d9fb80d57f24ba3890de8b1dbac03", size = 62841759, upload-time = "2026-05-30T16:51:59.407Z" }, + { url = "https://files.pythonhosted.org/packages/a2/7b/8b7a3f41bc255411be30b6d7d288aab8ffd9ea2055db8555ced3548007b9/nodejs_wheel_binaries-24.16.0-py2.py3-none-win_amd64.whl", hash = "sha256:bb136be9944f0662dcf1120f45193a6b75b13fac378971a95cc42c9f879a81aa", size = 42027734, upload-time = "2026-05-30T16:52:03.348Z" }, + { url = "https://files.pythonhosted.org/packages/17/66/1ed71f1f529b8ca727d42c7ceb9db0bef145ce4a13dfc86fb50aa44f3be6/nodejs_wheel_binaries-24.16.0-py2.py3-none-win_arm64.whl", hash = "sha256:8308940b5edd0a50dc5267ea36ba21c9f668e83fe0d9f293937174d3a7e31c36", size = 39714528, upload-time = "2026-05-30T16:52:06.421Z" }, +] + [[package]] name = "parso" version = "0.8.7" @@ -385,7 +441,9 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "basedpyright" }, { name = "django-extensions" }, + { name = "django-stubs" }, { name = "ipython" }, { name = "ruff" }, ] @@ -400,7 +458,9 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "basedpyright", specifier = ">=1.39.7" }, { name = "django-extensions", specifier = ">=4.1" }, + { name = "django-stubs", specifier = ">=6.0.5" }, { name = "ipython", specifier = ">=9.14.1" }, { name = "ruff", specifier = ">=0.15.17" }, ] @@ -437,6 +497,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/8d/1080ee4c231f361b6ce4470d556c8c435b67c7e0753aaa641497ee92f88b/traitlets-5.15.1-py3-none-any.whl", hash = "sha256:770a53705f84b81ac107e83a1b3328ff2dae16094d8fc3cfc004e4b22dfd8e92", size = 85858, upload-time = "2026-06-03T12:26:04.395Z" }, ] +[[package]] +name = "types-pyyaml" +version = "6.0.12.20260518" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/83/4a1afc3fbfcf5b8d46fc390cd95ed6b0dc9010a265f4e9f46314efffa37a/types_pyyaml-6.0.12.20260518.tar.gz", hash = "sha256:d917f83fb38462550338c1297faedd860b3ec83912b96b1e3d73255f7473e466", size = 17850, upload-time = "2026-05-18T06:01:58.675Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/a2/c01db32be2ae7d6a1689972f3c492b149ee4e164b12fdfd9f64b50888215/types_pyyaml-6.0.12.20260518-py3-none-any.whl", hash = "sha256:d2150f75a231c9fe9c7463bd29487d93e60bac90400287351384bc2284eba7cd", size = 20312, upload-time = "2026-05-18T06:01:57.368Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0"