Update fastapi and fix warnings

This commit is contained in:
2026-05-17 09:15:06 +02:00
parent e8266ffdc1
commit 3dc0031c20
6 changed files with 100 additions and 17 deletions

View File

@@ -28,9 +28,9 @@ async def landing_page(
transactions = sorted(transactions, key=lambda t: t.timestamp, reverse=True) transactions = sorted(transactions, key=lambda t: t.timestamp, reverse=True)
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"index.html.jinja", "index.html.jinja",
context={ context={
"request": request,
"user": user, "user": user,
"transactions": transactions, "transactions": transactions,
"focused_account": focused_account, "focused_account": focused_account,

View File

@@ -35,8 +35,9 @@ async def user_list(request: Request, session: SessionDep, user: UserDep):
groups = session.scalars(select(UserGroup)).all() groups = session.scalars(select(UserGroup)).all()
templates = get_jinja_renderer() templates = get_jinja_renderer()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"users.html.jinja", "users.html.jinja",
context={"request": request, "users": users, "all_groups": groups}, context={"users": users, "all_groups": groups},
) )
@@ -91,8 +92,9 @@ async def group_list(request: Request, session: SessionDep, user: UserDep):
groups = session.scalars(select(UserGroup)).all() groups = session.scalars(select(UserGroup)).all()
templates = get_jinja_renderer() templates = get_jinja_renderer()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"groups.html.jinja", "groups.html.jinja",
context={"request": request, "groups": groups}, context={"groups": groups},
) )
@@ -195,8 +197,9 @@ async def get_products(
templates = get_jinja_renderer() templates = get_jinja_renderer()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"products.html.jinja", "products.html.jinja",
context={"request": request, "products": products}, context={"products": products},
) )
@@ -211,9 +214,9 @@ async def edit_product_get(
templates = get_jinja_renderer() templates = get_jinja_renderer()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"product_edit.html.jinja", "product_edit.html.jinja",
context={ context={
"request": request,
"product": product, "product": product,
"edit_mode": True, "edit_mode": True,
"areas": areas, "areas": areas,
@@ -265,8 +268,9 @@ async def new_product_get(
templates = get_jinja_renderer() templates = get_jinja_renderer()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"product_edit.html.jinja", "product_edit.html.jinja",
context={"request": request, "edit_mode": False, "areas": areas}, context={"edit_mode": False, "areas": areas},
) )
@@ -310,8 +314,9 @@ async def get_accounts(
users = session.scalars(select(User)).all() users = session.scalars(select(User)).all()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"accounts.html.jinja", "accounts.html.jinja",
context={"request": request, "accounts": accounts, "users": users}, context={"accounts": accounts, "users": users},
) )

View File

@@ -20,8 +20,9 @@ async def get_shop(request: Request, session: SessionDep):
query = select(Area) query = select(Area)
areas = session.scalars(query).all() areas = session.scalars(query).all()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"shop.html.jinja", "shop.html.jinja",
context={"request": request, "areas": areas}, context={"areas": areas},
) )
@@ -29,9 +30,9 @@ async def get_shop(request: Request, session: SessionDep):
async def get_cart(request: Request, session: SessionDep, user: UserDep): async def get_cart(request: Request, session: SessionDep, user: UserDep):
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"order.html.jinja", "order.html.jinja",
context={ context={
"request": request,
"user": user, "user": user,
"order": user.shopping_cart, "order": user.shopping_cart,
"is_cart": True, "is_cart": True,
@@ -65,8 +66,9 @@ async def get_shop_area(request: Request, session: SessionDep, area_id: int):
query = select(Area).where(Area.id == area_id) query = select(Area).where(Area.id == area_id)
area = session.scalars(query).one() area = session.scalars(query).one()
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"area.html.jinja", "area.html.jinja",
context={"request": request, "area": area}, context={"area": area},
) )
@@ -143,6 +145,7 @@ async def get_order_details(
) )
return templates.TemplateResponse( return templates.TemplateResponse(
request,
"order.html.jinja", "order.html.jinja",
context={"request": request, "order": order, "is_cart": False}, context={"order": order, "is_cart": False},
) )

View File

@@ -2,7 +2,7 @@ import datetime
import decimal import decimal
import typing import typing
from sqlalchemy import Column, ForeignKey, Numeric, Table, func, select from sqlalchemy import Column, ForeignKey, Numeric, Table, and_, func, select
from sqlalchemy.exc import NoResultFound from sqlalchemy.exc import NoResultFound
from sqlalchemy.orm import ( from sqlalchemy.orm import (
DeclarativeBase, DeclarativeBase,
@@ -175,8 +175,17 @@ class Product(Base):
) )
current_details: Mapped["ProductDetails"] = relationship( current_details: Mapped["ProductDetails"] = relationship(
"ProductDetails", "ProductDetails",
primaryjoin="and_(Product.id == ProductDetails.product_id, ProductDetails.valid_from <= func.now())", primaryjoin=lambda: and_(
order_by="ProductDetails.valid_from.desc()", Product.id == ProductDetails.product_id,
ProductDetails.valid_from
== select(func.max(ProductDetails.valid_from))
.where(
ProductDetails.product_id == Product.id,
ProductDetails.valid_from <= func.now(),
)
.correlate(Product)
.scalar_subquery(),
),
uselist=False, uselist=False,
viewonly=True, viewonly=True,
) )

View File

@@ -32,6 +32,7 @@ def test_user_permissions(test_db):
user = User(username="normie", display_name="Normal User") user = User(username="normie", display_name="Normal User")
admin = User(username="admin", display_name="Admin User") admin = User(username="admin", display_name="Admin User")
test_db.add(user) test_db.add(user)
test_db.add(admin)
group = UserGroup(name="Admins", description="A group for admins") group = UserGroup(name="Admins", description="A group for admins")
group.permissions.append(Permission(scope="area", action="edit")) group.permissions.append(Permission(scope="area", action="edit"))

71
uv.lock generated
View File

@@ -51,6 +51,15 @@ dev = [
{ name = "pytest", specifier = ">=8.4.2" }, { name = "pytest", specifier = ">=8.4.2" },
] ]
[[package]]
name = "annotated-doc"
version = "0.0.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" },
]
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
version = "0.7.0" version = "0.7.0"
@@ -160,24 +169,29 @@ wheels = [
[[package]] [[package]]
name = "fastapi" name = "fastapi"
version = "0.119.0" version = "0.136.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "annotated-doc" },
{ name = "pydantic" }, { name = "pydantic" },
{ name = "starlette" }, { name = "starlette" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
{ name = "typing-inspection" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/0a/f9/5c5bcce82a7997cc0eb8c47b7800f862f6b56adc40486ed246e5010d443b/fastapi-0.119.0.tar.gz", hash = "sha256:451082403a2c1f0b99c6bd57c09110ed5463856804c8078d38e5a1f1035dbbb7", size = 336756, upload-time = "2025-10-11T17:13:40.53Z" } sdist = { url = "https://files.pythonhosted.org/packages/5d/45/c130091c2dfa061bbfe3150f2a5091ef1adf149f2a8d2ae769ecaf6e99a2/fastapi-0.136.1.tar.gz", hash = "sha256:7af665ad7acfa0a3baf8983d393b6b471b9da10ede59c60045f49fbc89a0fa7f", size = 397448, upload-time = "2026-04-23T16:49:44.046Z" }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/70/584c4d7cad80f5e833715c0a29962d7c93b4d18eed522a02981a6d1b6ee5/fastapi-0.119.0-py3-none-any.whl", hash = "sha256:90a2e49ed19515320abb864df570dd766be0662c5d577688f1600170f7f73cf2", size = 107095, upload-time = "2025-10-11T17:13:39.048Z" }, { url = "https://files.pythonhosted.org/packages/5a/ff/2e4eca3ade2c22fe1dea7043b8ee9dabe47753349eb1b56a202de8af6349/fastapi-0.136.1-py3-none-any.whl", hash = "sha256:a6e9d7eeada96c93a4d69cb03836b44fa34e2854accb7244a1ece36cd4781c3f", size = 117683, upload-time = "2026-04-23T16:49:42.437Z" },
] ]
[package.optional-dependencies] [package.optional-dependencies]
standard = [ standard = [
{ name = "email-validator" }, { name = "email-validator" },
{ name = "fastapi-cli", extra = ["standard"] }, { name = "fastapi-cli", extra = ["standard"] },
{ name = "fastar" },
{ name = "httpx" }, { name = "httpx" },
{ name = "jinja2" }, { name = "jinja2" },
{ name = "pydantic-extra-types" },
{ name = "pydantic-settings" },
{ name = "python-multipart" }, { name = "python-multipart" },
{ name = "uvicorn", extra = ["standard"] }, { name = "uvicorn", extra = ["standard"] },
] ]
@@ -220,6 +234,30 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/68/79/7f5a5e5513e6a737e5fb089d9c59c74d4d24dc24d581d3aa519b326bedda/fastapi_cloud_cli-0.3.1-py3-none-any.whl", hash = "sha256:7d1a98a77791a9d0757886b2ffbf11bcc6b3be93210dd15064be10b216bf7e00", size = 19711, upload-time = "2025-10-09T11:32:57.118Z" }, { url = "https://files.pythonhosted.org/packages/68/79/7f5a5e5513e6a737e5fb089d9c59c74d4d24dc24d581d3aa519b326bedda/fastapi_cloud_cli-0.3.1-py3-none-any.whl", hash = "sha256:7d1a98a77791a9d0757886b2ffbf11bcc6b3be93210dd15064be10b216bf7e00", size = 19711, upload-time = "2025-10-09T11:32:57.118Z" },
] ]
[[package]]
name = "fastar"
version = "0.11.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/03/0f/0aeb3fc50046617702acc0078b277b58367fd62eb727b9ec733ae0e8bbcc/fastar-0.11.0.tar.gz", hash = "sha256:aa7f100f7313c03fdb20f1385927ba95671071ba308ad0c1763fef295e1895ce", size = 70238, upload-time = "2026-04-13T17:11:17.143Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/d6/3be260037e86fb694e88d47f583bac3a0188c99cee1a6b257ac26cb6b53c/fastar-0.11.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:33f544b08b4541b678e53749b4552a44720d96761fb79c172b005b1089c443ed", size = 707975, upload-time = "2026-04-13T17:09:58.866Z" },
{ url = "https://files.pythonhosted.org/packages/e1/cd/7867aefb1784662554a335f2952c75a50f0c70585ed0d2210d6cc15e5627/fastar-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:91c1c792447e4a642745f347ff9847c52af39633071c57ee67ed53c157fc3506", size = 628460, upload-time = "2026-04-13T17:09:43.776Z" },
{ url = "https://files.pythonhosted.org/packages/e5/2b/d11d84bdd5e0e377771b955755771e3460b290da5809cb78c1b735ee2228/fastar-0.11.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:881247e6b6eaea59fc6569f9b61447aa6b9fc2ee864e048b4643d69c52745805", size = 863054, upload-time = "2026-04-13T17:09:13.048Z" },
{ url = "https://files.pythonhosted.org/packages/25/39/d3f428b318fa940b1b6e785b8d54fc895dfb5d5b945ef8d5442ffa904fb2/fastar-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:863b7929845c9fec92ef6c8d59579cf46af5136655e5342f8df5cebe46cab06c", size = 760247, upload-time = "2026-04-13T17:07:57.396Z" },
{ url = "https://files.pythonhosted.org/packages/9e/04/03949aee82aabb8ede06ac5a4a5579ffaf98a8fe59ce958494508ff15513/fastar-0.11.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96b4a57df12bf3211662627a3ea29d62ecb314a2434a0d0843f9fc23e47536e5", size = 756512, upload-time = "2026-04-13T17:08:12.415Z" },
{ url = "https://files.pythonhosted.org/packages/3f/0c/2ca1ae0a3828ca51047962d932b80daca2522db73e8cb9d040cb6ebe28d5/fastar-0.11.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceef1c2c4df7b7b8ebd3f5d718bbf457b9bbdf25ce0bd07870211ec4fbd9aff4", size = 922183, upload-time = "2026-04-13T17:08:27.187Z" },
{ url = "https://files.pythonhosted.org/packages/65/68/7fe808b1f73a68e686f25434f538c6dc10ef4dfb3db0ace22cd861744bf8/fastar-0.11.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8e545918441910a779659d4759ad0eef349e935fbdb4668a666d3681567eb05", size = 816394, upload-time = "2026-04-13T17:08:57.657Z" },
{ url = "https://files.pythonhosted.org/packages/1f/17/07d086080f8a83b8d7966955e29bcdbd6a060f5bd949dc9d5abd3658cead/fastar-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28095bb8f821e85fc2764e1a55f03e5e2876dee2abe7cd0ee9420d929905d643", size = 818983, upload-time = "2026-04-13T17:09:28.46Z" },
{ url = "https://files.pythonhosted.org/packages/fb/e2/2c4edf0910af2e814ff6d65b77a91196d472ca8a9fb2033bd983f6856caa/fastar-0.11.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0fafb95ecbe70f666a5e9b35dd63974ccdc9bb3d99ccdbd4014a823ec3e659b5", size = 884689, upload-time = "2026-04-13T17:08:42.763Z" },
{ url = "https://files.pythonhosted.org/packages/fa/ba/04fdcbd6558e60de4ced3b55230fac47675d181252582b2fcec3c74608e5/fastar-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af48fed039b94016629dcdad1c95c90c486326dd068de2b0a4df419ee09b6821", size = 970677, upload-time = "2026-04-13T17:10:15.124Z" },
{ url = "https://files.pythonhosted.org/packages/df/b3/2b860a9658550167dbd5824c85e88d0b4b912bf493e42a6322544d6e483d/fastar-0.11.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:74cd96163f39b8638ab4e8d49708ca887959672a22871d8170d01f067319533b", size = 1034026, upload-time = "2026-04-13T17:10:32.318Z" },
{ url = "https://files.pythonhosted.org/packages/b7/9b/fa42ea1188b144bac4b1b60753dfd449974a4d5eda132029ee7711569f94/fastar-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e8b993cb5613bab495ed482810bedc0986633fcb9a3b55c37ec88e0d6714f6a", size = 1071147, upload-time = "2026-04-13T17:10:48.833Z" },
{ url = "https://files.pythonhosted.org/packages/95/c8/d2e501556dca9f1fbc9246111a31792fb49ad908fa4927f34938a97a3604/fastar-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfe39d91fc28e37e06162d94afe01050220edb7df554acb5b702b5503e564816", size = 1028377, upload-time = "2026-04-13T17:11:06.374Z" },
{ url = "https://files.pythonhosted.org/packages/db/33/5f11f23eca0a569cd052507bc45dda2e5468697f8665728d25be44120f7d/fastar-0.11.0-cp313-cp313-win32.whl", hash = "sha256:c5f63d4d99ff4bfb37c659982ec413358bdee747005348756cc50a04d412d989", size = 454089, upload-time = "2026-04-13T17:11:46.821Z" },
{ url = "https://files.pythonhosted.org/packages/da/2f/35ff03c939cba7a255a9132367873fec6c355fd06a7f84fedcbaf4c8129f/fastar-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8690ed1928d31ded3ada308e1086525fb3871f5fa81e1b69601a3f7774004583", size = 486312, upload-time = "2026-04-13T17:11:32.86Z" },
{ url = "https://files.pythonhosted.org/packages/ef/71/ee9246cbfcbfd4144558f35e7e9a306ffe0a7564730a5188c45f21d2dab8/fastar-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:d977ded9d98a0719a305e0a4d5ee811f1d3e856d853a50acb8ae833c3cd6d5d2", size = 461975, upload-time = "2026-04-13T17:11:22.589Z" },
]
[[package]] [[package]]
name = "greenlet" name = "greenlet"
version = "3.2.4" version = "3.2.4"
@@ -488,6 +526,33 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/de/b20f4ab954d6d399499c33ec4fafc46d9551e11dc1858fb7f5dca0748ceb/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89", size = 1970034, upload-time = "2025-10-14T10:21:30.869Z" }, { url = "https://files.pythonhosted.org/packages/fc/de/b20f4ab954d6d399499c33ec4fafc46d9551e11dc1858fb7f5dca0748ceb/pydantic_core-2.41.4-cp313-cp313t-win_arm64.whl", hash = "sha256:19f3684868309db5263a11bace3c45d93f6f24afa2ffe75a647583df22a2ff89", size = 1970034, upload-time = "2025-10-14T10:21:30.869Z" },
] ]
[[package]]
name = "pydantic-extra-types"
version = "2.11.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/71/dba38ee2651f84f7842206adbd2233d8bbdb59fb85e9fa14232486a8c471/pydantic_extra_types-2.11.1.tar.gz", hash = "sha256:46792d2307383859e923d8fcefa82108b1a141f8a9c0198982b3832ab5ef1049", size = 172002, upload-time = "2026-03-16T08:08:03.92Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/17/c1/3226e6d7f5a4f736f38ac11a6fbb262d701889802595cdb0f53a885ac2e0/pydantic_extra_types-2.11.1-py3-none-any.whl", hash = "sha256:1722ea2bddae5628ace25f2aa685b69978ef533123e5638cfbddb999e0100ec1", size = 79526, upload-time = "2026-03-16T08:08:02.533Z" },
]
[[package]]
name = "pydantic-settings"
version = "2.14.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "python-dotenv" },
{ name = "typing-inspection" },
]
sdist = { url = "https://files.pythonhosted.org/packages/07/60/1d1e59c9c90d54591469ada7d268251f71c24bdb765f1a8a832cee8c6653/pydantic_settings-2.14.1.tar.gz", hash = "sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa", size = 235551, upload-time = "2026-05-08T13:40:06.542Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/8d/f1af3832f5e6eb13ba94ee809e72b8ecb5eef226d27ee0bef7d963d943c7/pydantic_settings-2.14.1-py3-none-any.whl", hash = "sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de", size = 60964, upload-time = "2026-05-08T13:40:04.958Z" },
]
[[package]] [[package]]
name = "pygments" name = "pygments"
version = "2.19.2" version = "2.19.2"