-
-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat: Customise status code & Enhance exceptions (#100)
Feat: Customise status code & Enhance exceptions
- Loading branch information
Showing
15 changed files
with
192 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from fastapi_class.exception.handler import ( | ||
UNKOWN_SERVER_ERROR_DETAIL, | ||
ExceptionAbstract, | ||
FormattedMessageException, | ||
) | ||
|
||
__all__ = [ | ||
"FormattedMessageException" "ExceptionAbstract", | ||
"UNKOWN_SERVER_ERROR_DETAIL", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from abc import ABC, abstractmethod | ||
from collections.abc import Iterable | ||
from typing import Any | ||
|
||
from fastapi import HTTPException, status | ||
|
||
UNKOWN_SERVER_ERROR_DETAIL = "Unknown server error" | ||
|
||
|
||
class ExceptionAbstract(ABC): | ||
_DEFAULT_DETAIL_SPECIAL_NAME = "__detail__" | ||
|
||
def __init__(self, *, exceptions: Iterable[tuple[int, str]] | None = None) -> None: | ||
self._exceptions = exceptions or [ | ||
(status.HTTP_500_INTERNAL_SERVER_ERROR, UNKOWN_SERVER_ERROR_DETAIL) | ||
] | ||
|
||
@classmethod | ||
@abstractmethod | ||
def __call__(cls, *args: Any, **kwds: Any) -> Any: | ||
raise NotImplementedError | ||
|
||
|
||
class FormattedMessageException(ExceptionAbstract): | ||
def __call__(self, *_, **kwargs): | ||
_exception = self._exceptions[0] | ||
|
||
try: | ||
detail = _exception[1].format(**kwargs) | ||
except (IndexError, KeyError): | ||
detail = _exception[1] | ||
return HTTPException(status_code=_exception[0], detail=detail) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
import logging | ||
|
||
logging.getLogger("fastapi_class").addHandler(logging.NullHandler()) | ||
logger = logging.getLogger("fastapi_class").addHandler(logging.NullHandler()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from typing import Any, Generic, TypeVar | ||
|
||
T = TypeVar("T") | ||
|
||
|
||
class Factory(Generic[T]): | ||
def __call__(self, *args: Any, **kwds: Any) -> T: | ||
pass # pragma: no cover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import pytest | ||
|
||
from fastapi_class import logger | ||
|
||
|
||
@pytest.fixture | ||
def setup_logger(): | ||
return logger | ||
|
||
|
||
def test_logger_disable(setup_logger): | ||
logger = setup_logger | ||
logger.disabled = True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
from typing import Any | ||
|
||
import pytest | ||
from fastapi.responses import Response | ||
from pydantic import BaseModel | ||
|
||
from fastapi_class import Metadata | ||
from tests.factory import Factory | ||
|
||
|
||
@pytest.fixture(name="metadata_factory") | ||
def fixture_metadata_factory(): | ||
def _factory(data: dict[str, Any] | None = None): | ||
data = data or {} | ||
return Metadata( | ||
data.get("methods", ["GET"]), | ||
name=data.get("name", "test"), | ||
path=data.get("path", "test"), | ||
status_code=data.get("status_code", 200), | ||
response_model=data.get("response_model", BaseModel), | ||
response_class=data.get("response_class", Response), | ||
) | ||
|
||
return _factory | ||
|
||
|
||
@pytest.fixture(name="metadata") | ||
def fixture_metadata(metadata_factory: Factory[Metadata]): | ||
return metadata_factory() | ||
|
||
|
||
def test_metadata_dynamic_optional_fields__get_when_field_exist(metadata: Metadata): | ||
assert metadata.methods == ["GET"] | ||
assert metadata.name == "test" | ||
assert metadata.status_code == 200 | ||
assert metadata.response_model == BaseModel | ||
assert metadata.response_class == Response | ||
|
||
|
||
def test_metadata_dynamic_optional_fields__raise_when_field_doesnt_exist( | ||
metadata: Metadata, | ||
): | ||
with pytest.raises(AttributeError): | ||
metadata.non_existing | ||
with pytest.raises(AttributeError): | ||
metadata.or_default | ||
|
||
|
||
def test_metadata_dynamic_optional_fields_default__when_field_exists( | ||
metadata_factory: Factory[Metadata], | ||
): | ||
metadata = metadata_factory({"name": "", "methods": [], "status_code": None}) | ||
|
||
assert metadata.name_or_default("test") == "test" | ||
assert metadata.methods_or_default(["test"]) == ["test"] | ||
assert metadata.status_code_or_default(123) == 123 | ||
|
||
|
||
def test_metadata_dynamic_optional_fields_default__when_field_doesnt_exist( | ||
metadata: Metadata, | ||
): | ||
with pytest.raises(AttributeError): | ||
metadata.non_existing_or_default("test") |
Oops, something went wrong.