fix: basedpyright + rank annotation

This commit is contained in:
Loïc Gremaud 2026-06-12 01:33:24 +02:00
parent 9d9ee53a14
commit f5d926ae29
Signed by: Legrems
GPG Key ID: D4620E6DF3E0121D
5 changed files with 112 additions and 12 deletions

View File

@ -10,15 +10,15 @@ class ScoreIn(Schema, BaseSchema):
class ScoreOut(Schema, BaseSchema): class ScoreOut(Schema, BaseSchema):
id: int
username: str username: str
points: int points: int
version: str | None version: str | None
created_at: str created_at: str
rank: int
@staticmethod @staticmethod
def resolve_version(obj: Score) -> str | None: 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 @staticmethod
def resolve_created_at(obj: Score) -> str: def resolve_created_at(obj: Score) -> str:

View File

@ -1,5 +1,8 @@
from typing import Annotated 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 django.http import HttpRequest
from ninja import Header from ninja import Header
from ninja.pagination import PageNumberPagination, paginate from ninja.pagination import PageNumberPagination, paginate
@ -11,14 +14,15 @@ from .schemas import ScoreIn, ScoreOut
router = CamelCaseRouter() 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: if name:
version, _ = Version.objects.get_or_create(name=name) version, _ = Version.objects.get_or_create(name=name)
return version return version
version = Version.objects.order_by("-created_at").first()
if version is None: version, _ = Version.objects.get_or_create(name="default")
version = Version.objects.create(name="default")
return version return version
@ -26,9 +30,9 @@ def _resolve_version(name: str | None) -> Version:
def submit_score( def submit_score(
request: HttpRequest, request: HttpRequest,
payload: ScoreIn, payload: ScoreIn,
x_game_version: Annotated[str | None, Header(alias="X-Game-Version")] = None, x_game_version: GameVersionHeader = None,
) -> Score: ) -> 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) return Score.objects.create(username=payload.username, points=payload.points, version=version)
@ -36,7 +40,16 @@ def submit_score(
@paginate(PageNumberPagination, page_size=20) @paginate(PageNumberPagination, page_size=20)
def list_scores( def list_scores(
request: HttpRequest, request: HttpRequest,
x_game_version: Annotated[str | None, Header(alias="X-Game-Version")] = None, x_game_version: GameVersionHeader = None,
) -> list[Score]: ) -> QuerySet[Score]:
version = _resolve_version(x_game_version) version = resolve_version(x_game_version)
return Score.objects.filter(version=version).select_related("version") return (
Score.objects.filter(version=version)
.select_related("version")
.annotate(
rank=Window(
expression=Rank(),
order_by=F("points").desc(),
)
)
)

View File

@ -29,6 +29,12 @@ hooks = [
{ id = "uv-lock" }, { id = "uv-lock" },
] ]
[[repos]]
repo = "local"
hooks = [
{ id = "basedpyright", name = "basedpyright", entry = "uv run basedpyright highscore/", language = "system", types = ["python"], pass_filenames = false },
]
[[repos]] [[repos]]
repo = "builtin" repo = "builtin"
hooks = [ hooks = [

View File

@ -13,7 +13,9 @@ dependencies = [
[dependency-groups] [dependency-groups]
dev = [ dev = [
"basedpyright>=1.39.7",
"django-extensions>=4.1", "django-extensions>=4.1",
"django-stubs>=6.0.5",
"ipython>=9.14.1", "ipython>=9.14.1",
"ruff>=0.15.17", "ruff>=0.15.17",
] ]
@ -48,3 +50,13 @@ ignore = [
[tool.ruff.lint.isort] [tool.ruff.lint.isort]
known-first-party = ["app", "scores"] 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"

69
uv.lock
View File

@ -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" }, { 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]] [[package]]
name = "colorama" name = "colorama"
version = "0.4.6" 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" }, { 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]] [[package]]
name = "executing" name = "executing"
version = "2.2.1" 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" }, { 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]] [[package]]
name = "parso" name = "parso"
version = "0.8.7" version = "0.8.7"
@ -385,7 +441,9 @@ dependencies = [
[package.dev-dependencies] [package.dev-dependencies]
dev = [ dev = [
{ name = "basedpyright" },
{ name = "django-extensions" }, { name = "django-extensions" },
{ name = "django-stubs" },
{ name = "ipython" }, { name = "ipython" },
{ name = "ruff" }, { name = "ruff" },
] ]
@ -400,7 +458,9 @@ requires-dist = [
[package.metadata.requires-dev] [package.metadata.requires-dev]
dev = [ dev = [
{ name = "basedpyright", specifier = ">=1.39.7" },
{ name = "django-extensions", specifier = ">=4.1" }, { name = "django-extensions", specifier = ">=4.1" },
{ name = "django-stubs", specifier = ">=6.0.5" },
{ name = "ipython", specifier = ">=9.14.1" }, { name = "ipython", specifier = ">=9.14.1" },
{ name = "ruff", specifier = ">=0.15.17" }, { 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" }, { 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]] [[package]]
name = "typing-extensions" name = "typing-extensions"
version = "4.15.0" version = "4.15.0"