From 978041c6ee8ec671c4ccfe97e3d7ef82bb1da195 Mon Sep 17 00:00:00 2001 From: grillazz Date: Sun, 24 Aug 2025 15:40:06 +0200 Subject: [PATCH] lint and format --- app/exception_handlers.py | 82 ---------------------------- app/exception_handlers/__init__.py | 2 +- app/exception_handlers/base.py | 8 +-- app/exception_handlers/database.py | 13 +++-- app/exception_handlers/registry.py | 11 +++- app/exception_handlers/validation.py | 17 +++--- tests/api/test_stuff.py | 10 +++- 7 files changed, 37 insertions(+), 106 deletions(-) delete mode 100644 app/exception_handlers.py diff --git a/app/exception_handlers.py b/app/exception_handlers.py deleted file mode 100644 index 6298a3e..0000000 --- a/app/exception_handlers.py +++ /dev/null @@ -1,82 +0,0 @@ -import orjson -from fastapi import FastAPI, Request -from fastapi.exceptions import ResponseValidationError -from fastapi.responses import JSONResponse -from rotoger import AppStructLogger -from sqlalchemy.exc import SQLAlchemyError - -logger = AppStructLogger().get_logger() - - -# TODO: add reasoning for this in readme plus higligh using re-raise in db session -async def sqlalchemy_exception_handler( - request: Request, exc: SQLAlchemyError -) -> JSONResponse: - request_path = request.url.path - try: - raw_body = await request.body() - request_body = orjson.loads(raw_body) if raw_body else None - except orjson.JSONDecodeError: - request_body = None - - await logger.aerror( - "Database error occurred", - sql_error=repr(exc), - request_url=request_path, - request_body=request_body, - ) - - return JSONResponse( - status_code=500, - content={"message": "A database error occurred. Please try again later."}, - ) - - -async def response_validation_exception_handler( - request: Request, exc: ResponseValidationError -) -> JSONResponse: - request_path = request.url.path - try: - raw_body = await request.body() - request_body = orjson.loads(raw_body) if raw_body else None - except orjson.JSONDecodeError: - request_body = None - - errors = exc.errors() - - # Check if this is a None/null response case - is_none_response = False - for error in errors: - # Check for null input pattern - if error.get("input") is None and "valid dictionary" in error.get("msg", ""): - is_none_response = True - break - - await logger.aerror( - "Response validation error occurred", - validation_errors=errors, - request_url=request_path, - request_body=request_body, - is_none_response=is_none_response, - ) - - if is_none_response: - # Return 404 when response is None (resource not found) - return JSONResponse( - status_code=404, - content={"no_response": "The requested resource was not found"}, - ) - else: - # Return 422 when response exists but doesn't match expected format - return JSONResponse( - status_code=422, - content={"response_format_error": errors}, - ) - - -def register_exception_handlers(app: FastAPI) -> None: - """Register all exception handlers with the FastAPI app.""" - app.add_exception_handler(SQLAlchemyError, sqlalchemy_exception_handler) - app.add_exception_handler( - ResponseValidationError, response_validation_exception_handler - ) diff --git a/app/exception_handlers/__init__.py b/app/exception_handlers/__init__.py index e954044..e628985 100644 --- a/app/exception_handlers/__init__.py +++ b/app/exception_handlers/__init__.py @@ -1,3 +1,3 @@ from app.exception_handlers.registry import register_exception_handlers -__all__ = ["register_exception_handlers"] \ No newline at end of file +__all__ = ["register_exception_handlers"] diff --git a/app/exception_handlers/base.py b/app/exception_handlers/base.py index f105f16..9e63e6a 100644 --- a/app/exception_handlers/base.py +++ b/app/exception_handlers/base.py @@ -1,8 +1,7 @@ import orjson +from attrs import define, field from fastapi import Request from rotoger import AppStructLogger -from attrs import define, field - logger = AppStructLogger().get_logger() @@ -10,6 +9,7 @@ logger = AppStructLogger().get_logger() @define(slots=True) class RequestInfo: """Contains extracted request information.""" + path: str = field() body: dict = field(default=None) @@ -39,5 +39,5 @@ class BaseExceptionHandler: message, request_url=request_info.path, request_body=request_info.body, - **kwargs - ) \ No newline at end of file + **kwargs, + ) diff --git a/app/exception_handlers/database.py b/app/exception_handlers/database.py index 9750ad3..76bd0b9 100644 --- a/app/exception_handlers/database.py +++ b/app/exception_handlers/database.py @@ -1,6 +1,7 @@ from fastapi import Request from fastapi.responses import JSONResponse from sqlalchemy.exc import SQLAlchemyError + from app.exception_handlers.base import BaseExceptionHandler @@ -8,16 +9,16 @@ class SQLAlchemyExceptionHandler(BaseExceptionHandler): """Handles SQLAlchemy database exceptions.""" @classmethod - async def handle_exception(cls, request: Request, exc: SQLAlchemyError) -> JSONResponse: + async def handle_exception( + cls, request: Request, exc: SQLAlchemyError + ) -> JSONResponse: request_info = await cls.extract_request_info(request) await cls.log_error( - "Database error occurred", - request_info, - sql_error=repr(exc) + "Database error occurred", request_info, sql_error=repr(exc) ) return JSONResponse( status_code=500, - content={"message": "A database error occurred. Please try again later."} - ) \ No newline at end of file + content={"message": "A database error occurred. Please try again later."}, + ) diff --git a/app/exception_handlers/registry.py b/app/exception_handlers/registry.py index 8de9d45..9ba42b2 100644 --- a/app/exception_handlers/registry.py +++ b/app/exception_handlers/registry.py @@ -1,11 +1,16 @@ from fastapi import FastAPI -from sqlalchemy.exc import SQLAlchemyError from fastapi.exceptions import ResponseValidationError +from sqlalchemy.exc import SQLAlchemyError from app.exception_handlers.database import SQLAlchemyExceptionHandler from app.exception_handlers.validation import ResponseValidationExceptionHandler + def register_exception_handlers(app: FastAPI) -> None: """Register all exception handlers with the FastAPI app.""" - app.add_exception_handler(SQLAlchemyError, SQLAlchemyExceptionHandler.handle_exception) - app.add_exception_handler(ResponseValidationError, ResponseValidationExceptionHandler.handle_exception) \ No newline at end of file + app.add_exception_handler( + SQLAlchemyError, SQLAlchemyExceptionHandler.handle_exception + ) + app.add_exception_handler( + ResponseValidationError, ResponseValidationExceptionHandler.handle_exception + ) diff --git a/app/exception_handlers/validation.py b/app/exception_handlers/validation.py index cfd2a29..d081af4 100644 --- a/app/exception_handlers/validation.py +++ b/app/exception_handlers/validation.py @@ -9,14 +9,18 @@ class ResponseValidationExceptionHandler(BaseExceptionHandler): """Handles response validation exceptions.""" @classmethod - async def handle_exception(cls, request: Request, exc: ResponseValidationError) -> JSONResponse: + async def handle_exception( + cls, request: Request, exc: ResponseValidationError + ) -> JSONResponse: request_info = await cls.extract_request_info(request) errors = exc.errors() # Check if this is a None/null response case is_none_response = False for error in errors: - if error.get("input") is None and "valid dictionary" in error.get("msg", ""): + if error.get("input") is None and "valid dictionary" in error.get( + "msg", "" + ): is_none_response = True break @@ -24,16 +28,15 @@ class ResponseValidationExceptionHandler(BaseExceptionHandler): "Response validation error occurred", request_info, validation_errors=errors, - is_none_response=is_none_response + is_none_response=is_none_response, ) if is_none_response: return JSONResponse( status_code=404, - content={"no_response": "The requested resource was not found"} + content={"no_response": "The requested resource was not found"}, ) else: return JSONResponse( - status_code=422, - content={"response_format_error": errors} - ) \ No newline at end of file + status_code=422, content={"response_format_error": errors} + ) diff --git a/tests/api/test_stuff.py b/tests/api/test_stuff.py index 9445c7e..e420b07 100644 --- a/tests/api/test_stuff.py +++ b/tests/api/test_stuff.py @@ -27,13 +27,17 @@ async def test_add_stuff(client: AsyncClient): ) response = await client.post("/stuff", json=stuff) assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR - assert response.json() == snapshot({'message':'A database error occurred. Please try again later.'}) + assert response.json() == snapshot( + {"message": "A database error occurred. Please try again later."} + ) async def test_get_stuff(client: AsyncClient): - response = await client.get(f"/stuff/nonexistent") + response = await client.get("/stuff/nonexistent") assert response.status_code == status.HTTP_404_NOT_FOUND - assert response.json() == snapshot({'no_response':'The requested resource was not found'}) + assert response.json() == snapshot( + {"no_response": "The requested resource was not found"} + ) stuff = StuffFactory.build(factory_use_constructors=True).model_dump(mode="json") await client.post("/stuff", json=stuff) name = stuff["name"]