Skip to content

Commit

Permalink
Merge pull request #33 from phalt/decimal-inputs
Browse files Browse the repository at this point in the history
Support for Decimal inputs
  • Loading branch information
phalt committed Oct 25, 2023
2 parents a01487f + 86cc234 commit ad0dbf0
Show file tree
Hide file tree
Showing 13 changed files with 84 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Improved support for Async clients which prevents a weird bug when running more than one event loop. Based on the suggestions from [this httpx issue](https://github.com/encode/httpcore/discussions/659).
- We now use [`ruff format`](https://astral.sh/blog/the-ruff-formatter) for coding formatting (not the client output).
- `Decimal` support now extends to Decimal input values.

## 0.7.1

Expand Down
14 changes: 6 additions & 8 deletions clientele/generators/standard/templates/async_methods.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@ async def get(url: str, headers: typing.Optional[dict] = None) -> httpx.Response
return await async_client.get(parse_url(url), headers=headers)


async def post(
url: str, data: dict, headers: typing.Optional[dict] = None
) -> httpx.Response:
async def post(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP POST request"""
json_data = json.dumps(data, default=json_serializer)
async with httpx.AsyncClient(headers=headers) as async_client:
return await async_client.post(parse_url(url), json=data, headers=headers)
return await async_client.post(parse_url(url), json=json_data, headers=headers)


async def put(
url: str, data: dict, headers: typing.Optional[dict] = None
) -> httpx.Response:
async def put(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP PUT request"""
json_data = json.dumps(data, default=json_serializer)
async with httpx.AsyncClient(headers=headers) as async_client:
return await async_client.put(parse_url(url), json=data, headers=headers)
return await async_client.put(parse_url(url), json=json_data, headers=headers)


async def delete(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:
Expand Down
15 changes: 12 additions & 3 deletions clientele/generators/standard/templates/http_py.jinja2
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import typing
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse
from __future__ import annotations
import json
{% if new_unions %}
import types
{% endif %}
import httpx # noqa
import typing
from decimal import Decimal
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

import httpx

from {{client_project_directory_path}} import config as c # noqa


def json_serializer(obj):
if isinstance(obj, Decimal):
return str(obj)


class APIException(Exception):
"""Could not match API response to return type of this function"""

Expand Down
6 changes: 3 additions & 3 deletions clientele/generators/standard/templates/schemas_py.jinja2
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations

import inspect # noqa
import typing # noqa
import inspect
import typing
from enum import Enum # noqa
from decimal import Decimal #noqa

import pydantic # noqa
import pydantic
17 changes: 11 additions & 6 deletions clientele/generators/standard/templates/sync_methods.jinja2
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@


def get(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:
""" Issue an HTTP GET request """
"""Issue an HTTP GET request"""
return client.get(parse_url(url), headers=headers)


def post(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
""" Issue an HTTP POST request """
return client.post(parse_url(url), json=data, headers=headers)
"""Issue an HTTP POST request"""
json_data = json.dumps(data, default=json_serializer)
return client.post(parse_url(url), json=json_data, headers=headers)


def put(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
""" Issue an HTTP PUT request """
return client.put(parse_url(url), json=data, headers=headers)
"""Issue an HTTP PUT request"""
json_data = json.dumps(data, default=json_serializer)
return client.put(parse_url(url), json=json_data, headers=headers)


def delete(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:
""" Issue an HTTP DELETE request """
"""Issue an HTTP DELETE request"""
return client.delete(parse_url(url), headers=headers)
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
## 0.8.0

- Improved support for Async clients which prevents a weird bug when running more than one event loop. Based on the suggestions from [this httpx issue](https://github.com/encode/httpcore/discussions/659).
- We now use [`ruff format`](https://astral.sh/blog/the-ruff-formatter) for coding formatting (not the client output).
- `Decimal` support now extends to Decimal input values.

## 0.7.1

Expand Down
9 changes: 7 additions & 2 deletions example_openapi_specs/best.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,15 @@
"my_input": {
"title": "My Input",
"type": "string"
}
},
"my_decimal_input": {
"title": "A Decimal input",
"type": "number",
"format": "decimal"
},
},
"required": [
"my_input"
"my_input", "my_decimal_input"
],
"title": "RequestDataRequest",
"type": "object"
Expand Down
17 changes: 14 additions & 3 deletions tests/async_test_client/http.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
from __future__ import annotations

import json
import types
import typing
from decimal import Decimal
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

import httpx # noqa
import httpx

from tests.async_test_client import config as c # noqa


def json_serializer(obj):
if isinstance(obj, Decimal):
return str(obj)


class APIException(Exception):
"""Could not match API response to return type of this function"""

Expand Down Expand Up @@ -121,14 +130,16 @@ async def get(url: str, headers: typing.Optional[dict] = None) -> httpx.Response

async def post(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP POST request"""
json_data = json.dumps(data, default=json_serializer)
async with httpx.AsyncClient(headers=headers) as async_client:
return await async_client.post(parse_url(url), json=data, headers=headers)
return await async_client.post(parse_url(url), json=json_data, headers=headers)


async def put(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP PUT request"""
json_data = json.dumps(data, default=json_serializer)
async with httpx.AsyncClient(headers=headers) as async_client:
return await async_client.put(parse_url(url), json=data, headers=headers)
return await async_client.put(parse_url(url), json=json_data, headers=headers)


async def delete(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:
Expand Down
7 changes: 4 additions & 3 deletions tests/async_test_client/schemas.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import annotations

import inspect # noqa
import typing # noqa
import inspect
import typing
from decimal import Decimal # noqa
from enum import Enum # noqa

import pydantic # noqa
import pydantic


class AnotherModel(pydantic.BaseModel):
Expand Down Expand Up @@ -58,6 +58,7 @@ class RequestDataAndParameterResponse(pydantic.BaseModel):

class RequestDataRequest(pydantic.BaseModel):
my_input: str
my_decimal_input: Decimal


class RequestDataResponse(pydantic.BaseModel):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_async_generated_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ async def test_request_data_request_data_post(respx_mock: MockRouter):
mock_path = "/request-data"
respx_mock.post(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = await client.request_data_request_data_post(data=data)
# Then
assert isinstance(response, schemas.RequestDataResponse)
Expand All @@ -186,7 +186,7 @@ async def test_request_data_request_data_put(respx_mock: MockRouter):
mock_path = "/request-data"
respx_mock.put(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = await client.request_data_request_data_put(data=data)
# Then
assert isinstance(response, schemas.RequestDataResponse)
Expand All @@ -205,7 +205,7 @@ async def test_request_data_path_request_data(respx_mock: MockRouter):
mock_path = f"/request-data/{path_parameter}"
respx_mock.post(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = await client.request_data_path_request_data(path_parameter, data=data)
# Then
assert isinstance(response, schemas.RequestDataAndParameterResponse)
Expand Down
17 changes: 14 additions & 3 deletions tests/test_client/http.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
from __future__ import annotations

import json
import types
import typing
from decimal import Decimal
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

import httpx # noqa
import httpx

from tests.test_client import config as c # noqa


def json_serializer(obj):
if isinstance(obj, Decimal):
return str(obj)


class APIException(Exception):
"""Could not match API response to return type of this function"""

Expand Down Expand Up @@ -120,12 +129,14 @@ def get(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:

def post(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP POST request"""
return client.post(parse_url(url), json=data, headers=headers)
json_data = json.dumps(data, default=json_serializer)
return client.post(parse_url(url), json=json_data, headers=headers)


def put(url: str, data: dict, headers: typing.Optional[dict] = None) -> httpx.Response:
"""Issue an HTTP PUT request"""
return client.put(parse_url(url), json=data, headers=headers)
json_data = json.dumps(data, default=json_serializer)
return client.put(parse_url(url), json=json_data, headers=headers)


def delete(url: str, headers: typing.Optional[dict] = None) -> httpx.Response:
Expand Down
7 changes: 4 additions & 3 deletions tests/test_client/schemas.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from __future__ import annotations

import inspect # noqa
import typing # noqa
import inspect
import typing
from decimal import Decimal # noqa
from enum import Enum # noqa

import pydantic # noqa
import pydantic


class AnotherModel(pydantic.BaseModel):
Expand Down Expand Up @@ -58,6 +58,7 @@ class RequestDataAndParameterResponse(pydantic.BaseModel):

class RequestDataRequest(pydantic.BaseModel):
my_input: str
my_decimal_input: Decimal


class RequestDataResponse(pydantic.BaseModel):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_generated_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def test_request_data_request_data_post(respx_mock: MockRouter):
mock_path = "/request-data"
respx_mock.post(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = client.request_data_request_data_post(data=data)
# Then
assert isinstance(response, schemas.RequestDataResponse)
Expand All @@ -169,7 +169,7 @@ def test_request_data_request_data_put(respx_mock: MockRouter):
mock_path = "/request-data"
respx_mock.put(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = client.request_data_request_data_put(data=data)
# Then
assert isinstance(response, schemas.RequestDataResponse)
Expand All @@ -187,7 +187,7 @@ def test_request_data_path_request_data(respx_mock: MockRouter):
mock_path = f"/request-data/{path_parameter}"
respx_mock.post(mock_path).mock(return_value=Response(json=mocked_response, status_code=200))
# When
data = schemas.RequestDataRequest(my_input="test")
data = schemas.RequestDataRequest(my_input="test", my_decimal_input=Decimal(0.1))
response = client.request_data_path_request_data(path_parameter, data=data)
# Then
assert isinstance(response, schemas.RequestDataAndParameterResponse)
Expand Down

0 comments on commit ad0dbf0

Please sign in to comment.