From 7e37fc47e70d61558e6462c53f3e88ea519ed32c Mon Sep 17 00:00:00 2001 From: s_kovalev Date: Wed, 2 Apr 2025 11:28:37 +0400 Subject: [PATCH 1/2] Aiohttp switch to orjson --- frameworks/Python/aiohttp/app/views.py | 11 +++++++---- frameworks/Python/aiohttp/requirements.txt | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/frameworks/Python/aiohttp/app/views.py b/frameworks/Python/aiohttp/app/views.py index 8fd659aa93f..8368e53e228 100644 --- a/frameworks/Python/aiohttp/app/views.py +++ b/frameworks/Python/aiohttp/app/views.py @@ -1,11 +1,10 @@ -from functools import partial from operator import attrgetter, itemgetter from pathlib import Path from random import randint import jinja2 -import ujson -from aiohttp.web import Response, json_response +import orjson +from aiohttp.web import Response from sqlalchemy import select from .models import sa_fortunes, sa_worlds, Fortune, World @@ -16,7 +15,6 @@ READ_SELECT_ORM = select(World.randomnumber) WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$2 WHERE id=$1' -json_response = partial(json_response, dumps=ujson.dumps) template_path = Path(__file__).parent / 'templates' / 'fortune.jinja' template = jinja2.Template(template_path.read_text()) sort_fortunes_orm = attrgetter('message') @@ -34,6 +32,11 @@ def get_num_queries(request): return 500 return num_queries +def json_response(payload): + return Response( + body=orjson.dumps(payload), + content_type="application/json", + ) async def json(request): """ diff --git a/frameworks/Python/aiohttp/requirements.txt b/frameworks/Python/aiohttp/requirements.txt index 82efc712810..342729596fd 100644 --- a/frameworks/Python/aiohttp/requirements.txt +++ b/frameworks/Python/aiohttp/requirements.txt @@ -1,8 +1,8 @@ -aiohttp==3.11.14 +aiohttp==3.11.16 asyncpg==0.30.0 gunicorn==23.0.0 -jinja2==3.1.5 +jinja2==3.1.6 psycopg2==2.9.10 SQLAlchemy==2.0.39 -ujson==5.10.0 +orjson==3.10.16 uvloop==0.21.0 From 18e3020f2e67c6c351edb415c46c7c4fa1891d33 Mon Sep 17 00:00:00 2001 From: s_kovalev Date: Mon, 7 Apr 2025 18:46:08 +0400 Subject: [PATCH 2/2] ensure that update runs over unique ids --- frameworks/Python/aiohttp/app/views.py | 33 ++++++++++++++-------- frameworks/Python/aiohttp/requirements.txt | 1 - 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/frameworks/Python/aiohttp/app/views.py b/frameworks/Python/aiohttp/app/views.py index 8368e53e228..ef2b04ed7bc 100644 --- a/frameworks/Python/aiohttp/app/views.py +++ b/frameworks/Python/aiohttp/app/views.py @@ -1,11 +1,12 @@ from operator import attrgetter, itemgetter from pathlib import Path -from random import randint +from random import randint, sample import jinja2 import orjson from aiohttp.web import Response from sqlalchemy import select +from sqlalchemy.orm.attributes import flag_modified from .models import sa_fortunes, sa_worlds, Fortune, World @@ -77,7 +78,7 @@ async def multiple_database_queries_orm(request): result = [] async with request.app['db_session']() as sess: for id_ in ids: - num = await sess.scalar(READ_SELECT_ORM.filter_by(id=id_)) + num = await sess.scalar(READ_SELECT_ORM.where(World.id == id_)) result.append({'id': id_, 'randomNumber': num}) return json_response(result) @@ -131,14 +132,21 @@ async def updates(request): Test 5 ORM """ num_queries = get_num_queries(request) - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] - updates.sort() - worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] + + ids = sample(range(1, 10000 + 1), num_queries) + ids.sort() + worlds = [] async with request.app['db_session'].begin() as sess: - for id_, number in updates: - world = await sess.get(World, id_, populate_existing=True) - world.randomnumber = number + for row_id in ids: + random_number = randint(1, 10000) + world = await sess.get(World, row_id, populate_existing=True) + world.randomnumber = random_number + # force sqlalchemy to UPDATE entry even if the value has not changed + # doesn't make sense in a real application, added only for pass `tfb verify` + flag_modified(world, "randomnumber") + worlds.append({'id': row_id, 'randomNumber': random_number}) + return json_response(worlds) async def updates_raw(request): @@ -146,15 +154,16 @@ async def updates_raw(request): Test 5 RAW """ num_queries = get_num_queries(request) - updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] - updates.sort() + ids = sample(range(1, 10000 + 1), num_queries) + ids.sort() + updates = [(row_id, randint(1, 10000)) for row_id in ids] worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] async with request.app['pg'].acquire() as conn: stmt = await conn.prepare(READ_ROW_SQL) - for id_, _ in updates: + for row_id in ids: # the result of this is the int previous random number which we don't actually use - await stmt.fetchval(id_) + await stmt.fetchval(row_id) await conn.executemany(WRITE_ROW_SQL, updates) return json_response(worlds) diff --git a/frameworks/Python/aiohttp/requirements.txt b/frameworks/Python/aiohttp/requirements.txt index 342729596fd..aec2ed27c64 100644 --- a/frameworks/Python/aiohttp/requirements.txt +++ b/frameworks/Python/aiohttp/requirements.txt @@ -2,7 +2,6 @@ aiohttp==3.11.16 asyncpg==0.30.0 gunicorn==23.0.0 jinja2==3.1.6 -psycopg2==2.9.10 SQLAlchemy==2.0.39 orjson==3.10.16 uvloop==0.21.0