Merge pull request #238 from grillazz/rotoger-one-more-time

rotoger-one-more-time
This commit is contained in:
Ordinary Hobbit
2026-03-09 18:11:03 +01:00
committed by GitHub
6 changed files with 54 additions and 16 deletions
+21 -2
View File
@@ -1,4 +1,8 @@
from collections.abc import Callable
from typing import Annotated, Any
from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import ValidationError, WrapValidator
from rotoger import get_logger
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.ext.asyncio import AsyncSession
@@ -22,12 +26,26 @@ async def create_random_stuff(
return {"id": str(random_stuff.id)}
failed_items: list[dict] = [] # Global or pass via context
def catch_invalid(v: Any, handler: Callable[[Any], Any] ) -> Any:
try:
return handler(v)
except ValidationError:
failed_items.append(v) # Intercept here!
return None # Or raise if needed
@router.post("/add_many", status_code=status.HTTP_201_CREATED)
async def create_multi_stuff(
payload: list[StuffSchema], db_session: AsyncSession = Depends(get_db)
payload: list[Annotated[StuffSchema, WrapValidator(catch_invalid)]], db_session: AsyncSession = Depends(get_db)
):
await logger.ainfo(f">>>{failed_items}")
try:
stuff_instances = [Stuff(**stuff.model_dump()) for stuff in payload]
await logger.ainfo(f">>>{failed_items}")
await logger.ainfo(f">>>{payload}")
stuff_instances = [
Stuff(**stuff.model_dump()) for stuff in payload if stuff is not None
]
db_session.add_all(stuff_instances)
await db_session.commit()
except SQLAlchemyError as ex:
@@ -39,6 +57,7 @@ async def create_multi_stuff(
await logger.ainfo(
f"{len(stuff_instances)} Stuff instances inserted into the database."
)
return {"inserted": len(stuff_instances)}
return True
+3 -3
View File
@@ -21,12 +21,12 @@ from app.middleware.profiler import ProfilingMiddleware
from app.redis import get_redis
from app.services.auth import AuthBearer
logger = get_logger()
templates = Jinja2Templates(directory=Path(__file__).parent.parent / "templates")
@asynccontextmanager
async def lifespan(app: FastAPI):
app.logger = get_logger()
app.redis = await get_redis()
postgres_dsn = global_settings.postgres_url.unicode_string()
try:
@@ -35,12 +35,12 @@ async def lifespan(app: FastAPI):
min_size=5,
max_size=20,
)
await logger.ainfo(
await app.logger.ainfo(
"Postgres pool created", idle_size=app.postgres_pool.get_idle_size()
)
yield
except Exception as e:
await logger.aerror("Error during app startup", error=repr(e))
await app.logger.aerror("Error during app startup", error=repr(e))
raise
finally:
await app.redis.close()
-1
View File
@@ -5,7 +5,6 @@ from pydantic import BaseModel, ConfigDict, Field
config = ConfigDict(from_attributes=True)
class RandomStuff(BaseModel):
chaos: dict[str, Any] = Field(
..., description="Pretty chaotic JSON data can be added here..."
+20
View File
@@ -0,0 +1,20 @@
from granian import Granian
def startup():
print("Server starting up...")
def shutdown():
print("Server shutting down...")
server = Granian(
"main:app",
host="0.0.0.0", # Bind to all interfaces
port=8000,
workers=4,
interface="asgi",
blocking_threads=8 # Optional: threads per worker for blocking ops
)
server.on_startup(startup)
server.on_shutdown(shutdown)
server.serve_forever()
+2 -2
View File
@@ -22,14 +22,14 @@ dependencies = [
"redis==7.1.0",
"bcrypt==5.0.0",
"polars[pyarrow]==1.36.1",
"python-multipart==0.0.20",
"python-multipart==0.0.22",
"fastexcel==0.18.0",
"inline-snapshot==0.31.1",
"dirty-equals==0.11",
"polyfactory==3.1.0",
"granian==2.6.0",
"apscheduler[redis,sqlalchemy]>=4.0.0a6",
"rotoger==0.2.1",
"rotoger==0.3.0",
"pyinstrument>=5.1.2",
]
Generated
+8 -8
View File
@@ -438,10 +438,10 @@ requires-dist = [
{ name = "pyjwt", specifier = "==2.10.1" },
{ name = "pytest", specifier = "==9.0.2" },
{ name = "pytest-cov", specifier = "==7.0.0" },
{ name = "python-multipart", specifier = "==0.0.20" },
{ name = "python-multipart", specifier = "==0.0.22" },
{ name = "redis", specifier = "==7.1.0" },
{ name = "rich", specifier = "==14.2.0" },
{ name = "rotoger", specifier = "==0.2.1" },
{ name = "rotoger", specifier = "==0.3.0" },
{ name = "sqlalchemy", specifier = "==2.0.45" },
{ name = "uvicorn", extras = ["standard"], specifier = "==0.38.0" },
{ name = "uvloop", specifier = "==0.22.1" },
@@ -1075,11 +1075,11 @@ wheels = [
[[package]]
name = "python-multipart"
version = "0.0.20"
version = "0.0.22"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" }
sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" },
{ url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" },
]
[[package]]
@@ -1196,7 +1196,7 @@ wheels = [
[[package]]
name = "rotoger"
version = "0.2.1"
version = "0.3.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs" },
@@ -1204,9 +1204,9 @@ dependencies = [
{ name = "structlog" },
{ name = "whenever" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9d/ad/75a22ddd259505547fd47c36ea984688e3b56d9cbc49c0f98bb95c84c01b/rotoger-0.2.1.tar.gz", hash = "sha256:823bb39c781d6038d2aae1c2c3f6d74c0abb1e9f07b257c079028d6ae3f2589d", size = 1647, upload-time = "2025-11-13T16:12:27.833Z" }
sdist = { url = "https://files.pythonhosted.org/packages/06/40/475df92ef562d22489a1b07bc41cf1094dce1d4d03475f59112b97070560/rotoger-0.3.0.tar.gz", hash = "sha256:e407e3f4cf4948886bd26b35bd54e635f58703db406f5a706e4c4579dc273241", size = 2714, upload-time = "2026-03-01T17:08:46.78Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/e7/da/9422061c62499eaafcf90c4adf3e13c51031d4b593af899451825fa85a7b/rotoger-0.2.1-py3-none-any.whl", hash = "sha256:849ed131068ab724991c38c32fb63e4904efb79e29bf084f37ec11a31ec0c703", size = 2603, upload-time = "2025-11-13T16:12:26.895Z" },
{ url = "https://files.pythonhosted.org/packages/72/85/2164d61cff7594366d5797cc6f33784a05e83a39841701860bbbc41631dc/rotoger-0.3.0-py3-none-any.whl", hash = "sha256:08d3c239f05c0551a9cdb682332f4c1e981844b1b0afa7b1e04c50730bbe2098", size = 3458, upload-time = "2026-03-01T17:08:47.684Z" },
]
[[package]]