diff --git a/frameworks/Python/emmett55/app.py b/frameworks/Python/emmett55/app.py index e417e8f75fa..d24f7e98d62 100644 --- a/frameworks/Python/emmett55/app.py +++ b/frameworks/Python/emmett55/app.py @@ -3,12 +3,19 @@ from random import randint, sample import asyncpg -from emmett55 import App, Pipe, current, request, response +from emmett55 import App, Pipe, request, response from emmett55.extensions import Extension, Signals, listen_signal -from emmett55.tools import service +from emmett55.tools import ServicePipe from renoir import Renoir +class NoResetConnection(asyncpg.Connection): + __slots__ = () + + def get_reset_query(self): + return "" + + class AsyncPG(Extension): __slots__ = ["pool"] @@ -23,10 +30,9 @@ async def build_pool(self): database='hello_world', host='tfb-database', port=5432, - min_size=16, - max_size=16, - max_queries=64_000_000_000, - max_inactive_connection_lifetime=0 + min_size=4, + max_size=4, + connection_class=NoResetConnection, ) @listen_signal(Signals.after_loop) @@ -40,18 +46,32 @@ class AsyncPGPipe(Pipe): def __init__(self, ext): self.ext = ext - async def open(self): - conn = current._db_conn = self.ext.pool.acquire() - current.db = await conn.__aenter__() + async def pipe(self, next_pipe, **kwargs): + async with self.ext.pool.acquire() as conn: + kwargs['db'] = conn + return await next_pipe(**kwargs) + - async def close(self): - await current._db_conn.__aexit__() +class TemplatePipe(Pipe): + __slots__ = ["template"] + output = "str" + + def __init__(self, template): + self.template = f"templates/{template}" + + async def pipe(self, next_pipe, **kwargs): + response.content_type = "text/html; charset=utf-8" + ctx = await next_pipe(**kwargs) + return templates.render(self.template, ctx) app = App(__name__) app.config.handle_static = False templates = Renoir() +json_routes = app.module(__name__, 'json') +json_routes.pipeline = [ServicePipe('json')] + db_ext = app.use_extension(AsyncPG) SQL_SELECT = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1' @@ -60,17 +80,15 @@ async def close(self): sort_key = itemgetter(1) -@app.route() -@service.json +@json_routes.route() async def json(): return {'message': 'Hello, World!'} -@app.route("/db", pipeline=[db_ext.pipe]) -@service.json -async def get_random_world(): +@json_routes.route("/db", pipeline=[db_ext.pipe]) +async def get_random_world(db): row_id = randint(1, 10000) - number = await current.db.fetchval(SQL_SELECT, row_id) + number = await db.fetchval(SQL_SELECT, row_id) return {'id': row_id, 'randomNumber': number} @@ -86,41 +104,32 @@ def get_qparam(): return rv -@app.route("/queries", pipeline=[db_ext.pipe]) -@service.json -async def get_random_worlds(): +@json_routes.route("/queries", pipeline=[db_ext.pipe]) +async def get_random_worlds(db): num_queries = get_qparam() row_ids = sample(range(1, 10000), num_queries) - worlds = [] - statement = await current.db.prepare(SQL_SELECT) - for row_id in row_ids: - number = await statement.fetchval(row_id) - worlds.append({'id': row_id, 'randomNumber': number}) - return worlds + rows = await db.fetchmany(SQL_SELECT, [(v,) for v in row_ids]) + return [{'id': row_id, 'randomNumber': number[0]} for row_id, number in zip(row_ids, rows)] -@app.route(pipeline=[db_ext.pipe], output='str') -async def fortunes(): - response.content_type = "text/html; charset=utf-8" - fortunes = await current.db.fetch('SELECT * FROM Fortune') +@app.route(pipeline=[TemplatePipe("fortunes.html"), db_ext.pipe]) +async def fortunes(db): + fortunes = await db.fetch('SELECT * FROM Fortune') fortunes.append(ROW_ADD) fortunes.sort(key=sort_key) - return templates.render("templates/fortunes.html", {"fortunes": fortunes}) + return {"fortunes": fortunes} -@app.route(pipeline=[db_ext.pipe]) -@service.json -async def updates(): +@json_routes.route(pipeline=[db_ext.pipe]) +async def updates(db): num_queries = get_qparam() updates = list(zip( sample(range(1, 10000), num_queries), sorted(sample(range(1, 10000), num_queries)) )) worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates] - statement = await current.db.prepare(SQL_SELECT) - for row_id, _ in updates: - await statement.fetchval(row_id) - await current.db.executemany(SQL_UPDATE, updates) + await db.executemany(SQL_SELECT, [(i[0],) for i in updates]) + await db.executemany(SQL_UPDATE, updates) return worlds diff --git a/frameworks/Python/emmett55/emmett55.dockerfile b/frameworks/Python/emmett55/emmett55.dockerfile index 49438fd442d..a3e5039a72f 100644 --- a/frameworks/Python/emmett55/emmett55.dockerfile +++ b/frameworks/Python/emmett55/emmett55.dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11-slim +FROM python:3.13-slim ADD ./ /emmett55 diff --git a/frameworks/Python/emmett55/requirements.txt b/frameworks/Python/emmett55/requirements.txt index 341cf834957..8641ee5f52f 100644 --- a/frameworks/Python/emmett55/requirements.txt +++ b/frameworks/Python/emmett55/requirements.txt @@ -1,3 +1,3 @@ -asyncpg==0.29.0 +asyncpg==0.30.0 emmett55[orjson,uvloop]>=1.2.0,<1.3.0 renoir==1.8.0 diff --git a/frameworks/Python/granian/app_asgi.py b/frameworks/Python/granian/app_asgi.py index d7c7b732c27..b6a727e8b0e 100644 --- a/frameworks/Python/granian/app_asgi.py +++ b/frameworks/Python/granian/app_asgi.py @@ -106,7 +106,6 @@ async def route_db(scope, receive, send): async def route_queries(scope, receive, send): num_queries = get_num_queries(scope) row_ids = sample(range(1, 10000), num_queries) - worlds = [] async with pool.acquire() as connection: rows = await connection.fetchmany(SQL_SELECT, [(v,) for v in row_ids]) diff --git a/frameworks/Python/granian/granian-nogil.dockerfile b/frameworks/Python/granian/granian-nogil.dockerfile index 5f0e4045f40..566ac8cca40 100644 --- a/frameworks/Python/granian/granian-nogil.dockerfile +++ b/frameworks/Python/granian/granian-nogil.dockerfile @@ -13,4 +13,4 @@ RUN uv pip install -r requirements-nogil.txt EXPOSE 8080 -CMD uv run python run_nogil.py rsgi st +CMD uv run python run_nogil.py rsgi mt diff --git a/frameworks/Python/granian/granian-rsgi.dockerfile b/frameworks/Python/granian/granian-rsgi.dockerfile index 1eb5066dfeb..a7616266d84 100644 --- a/frameworks/Python/granian/granian-rsgi.dockerfile +++ b/frameworks/Python/granian/granian-rsgi.dockerfile @@ -8,4 +8,4 @@ RUN pip install -r /granian/requirements.txt EXPOSE 8080 -CMD python run.py rsgi st +CMD python run.py rsgi mt diff --git a/frameworks/Python/granian/requirements-nogil.txt b/frameworks/Python/granian/requirements-nogil.txt index c49d8ced726..828e24cd711 100644 --- a/frameworks/Python/granian/requirements-nogil.txt +++ b/frameworks/Python/granian/requirements-nogil.txt @@ -1 +1 @@ -granian[rloop]>=2.5.0,<2.6.0 +granian[rloop]>=2.6.0,<2.7.0 diff --git a/frameworks/Python/granian/requirements.txt b/frameworks/Python/granian/requirements.txt index 8fc318454b4..d3895189e0d 100644 --- a/frameworks/Python/granian/requirements.txt +++ b/frameworks/Python/granian/requirements.txt @@ -1,4 +1,4 @@ asyncpg==0.30.0 -granian[uvloop]>=2.5.0,<2.6.0 +granian[uvloop]>=2.6.0,<2.7.0 jinja2==3.1.6 orjson==3.11.3