From 0a0d8341a8955a36f6710395a0b7256e47afc434 Mon Sep 17 00:00:00 2001 From: Bryan Kristiono <15132982+Kristinus@users.noreply.github.com> Date: Thu, 24 Aug 2023 12:35:00 -0400 Subject: [PATCH 1/4] Include Enum to NinjaJSONEncoder --- ninja/responses.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ninja/responses.py b/ninja/responses.py index 440e98c51..557e894ee 100644 --- a/ninja/responses.py +++ b/ninja/responses.py @@ -1,5 +1,6 @@ from ipaddress import IPv4Address, IPv6Address from typing import Any, FrozenSet +from enum import Enum from django.core.serializers.json import DjangoJSONEncoder from django.http import JsonResponse @@ -22,6 +23,8 @@ def default(self, o: Any) -> Any: return o.model_dump() if isinstance(o, (IPv4Address, IPv6Address)): return str(o) + if isinstance(o, Enum): + return str(o) return super().default(o) From feac322aecefaa5b365c67c2d0167d6e80cb390a Mon Sep 17 00:00:00 2001 From: Bryan Kristiono <15132982+Kristinus@users.noreply.github.com> Date: Fri, 25 Aug 2023 10:14:43 -0400 Subject: [PATCH 2/4] add test --- ninja/responses.py | 2 +- tests/test_response.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ninja/responses.py b/ninja/responses.py index 557e894ee..babd366e6 100644 --- a/ninja/responses.py +++ b/ninja/responses.py @@ -1,6 +1,6 @@ +from enum import Enum from ipaddress import IPv4Address, IPv6Address from typing import Any, FrozenSet -from enum import Enum from django.core.serializers.json import DjangoJSONEncoder from django.http import JsonResponse diff --git a/tests/test_response.py b/tests/test_response.py index 0ef0986b2..688186e64 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -1,4 +1,5 @@ import json +from enum import Enum from ipaddress import IPv4Address, IPv6Address from typing import List, Union @@ -30,6 +31,11 @@ def __init__(self, id, user_name, password): self.password = password +class MyEnum(Enum): + first = "first" + second = "second" + + def to_camel(string: str) -> str: return "".join(word.capitalize() for word in string.split("_")) @@ -157,3 +163,10 @@ def test_ipv6address_encoding(): response = Response(data) response_data = json.loads(response.content) assert response_data["ipv6"] == str(data["ipv6"]) + + +def test_enum_encoding(): + data = {"enum": MyEnum.first} + response = Response(data) + response_data = json.loads(response.content) + assert response_data["enum"] == str(data["enum"]) From 601d1dea8f96d39784649363c0a0edc6bd0481c3 Mon Sep 17 00:00:00 2001 From: AlTosterino Date: Wed, 30 Aug 2023 20:26:33 +0200 Subject: [PATCH 3/4] #822 "ValidationError" and "HttpError" are not unpickable --- ninja/errors.py | 8 ++++++-- tests/test_errors.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/test_errors.py diff --git a/ninja/errors.py b/ninja/errors.py index 1be1dff87..3c1056a7e 100644 --- a/ninja/errors.py +++ b/ninja/errors.py @@ -39,14 +39,18 @@ class ValidationError(Exception): """ def __init__(self, errors: List[DictStrAny]) -> None: - super().__init__() self.errors = errors + super().__init__(errors) class HttpError(Exception): def __init__(self, status_code: int, message: str) -> None: self.status_code = status_code - super().__init__(message) + self.message = message + super().__init__(status_code, message) + + def __str__(self) -> str: + return self.message def set_default_exc_handlers(api: "NinjaAPI") -> None: diff --git a/tests/test_errors.py b/tests/test_errors.py new file mode 100644 index 000000000..b19c0159c --- /dev/null +++ b/tests/test_errors.py @@ -0,0 +1,26 @@ +import pickle + +from ninja.errors import HttpError, ValidationError + + +def test_validation_error_is_picklable_and_unpicklable(): + error_to_serialize = ValidationError([{"testkey": "testvalue"}]) + + serialized = pickle.dumps(error_to_serialize) + assert serialized # Not empty + + deserialized = pickle.loads(serialized) + assert isinstance(deserialized, ValidationError) + assert deserialized.errors == error_to_serialize.errors + + +def test_http_error_is_picklable_and_unpicklable(): + error_to_serialize = HttpError(500, "Test error") + + serialized = pickle.dumps(error_to_serialize) + assert serialized # Not empty + + deserialized = pickle.loads(serialized) + assert isinstance(deserialized, HttpError) + assert deserialized.status_code == error_to_serialize.status_code + assert deserialized.message == error_to_serialize.message From c201be39808f7dcca54282a8cf887d2516dba1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2EYasoob=20Ullah=20Khalid=20=E2=98=BA?= Date: Mon, 4 Sep 2023 02:53:26 -0400 Subject: [PATCH 4/4] Fixed an anchor href in async-support.md --- docs/docs/guides/async-support.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/guides/async-support.md b/docs/docs/guides/async-support.md index 935c2b467..05a4cb8ab 100644 --- a/docs/docs/guides/async-support.md +++ b/docs/docs/guides/async-support.md @@ -66,7 +66,7 @@ uvicorn your_project.asgi:application --reload ### Test -Go to your browser and open http://127.0.0.1:8000/api/say-after?delay=3&word=hello (**delay=3**) +Go to your browser and open http://127.0.0.1:8000/api/say-after?delay=3&word=hello (**delay=3**) After a 3-second wait you should see the "hello" message. Now let's flood this operation with **100 parallel requests**: