Skip to content

Commit

Permalink
Merge pull request #211 from prkumar/master
Browse files Browse the repository at this point in the history
Release v0.9.3
  • Loading branch information
prkumar committed Nov 22, 2020
2 parents 73ea8ae + 47715bc commit e84e10c
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 3 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog`_, and this project adheres to the
`Semantic Versioning`_ scheme.

0.9.3_ - 2020-11-22
====================
Added
-----
- Support for serialization using a subclass of `pydantic`_'s `BaseModel` that
contains fields of a complex type, such as `datetime`.
(`#207`_ by `@leiserfg`_)
- Support for passing a subclass of `pydantic`'s `BaseModel` as the request
body. (`#209`_ by `@lust4life`_)

0.9.2_ - 2020-10-18
====================
Added
Expand Down Expand Up @@ -367,6 +377,8 @@ Added
.. _#198: https://github.com/prkumar/uplink/pull/198
.. _#200: https://github.com/prkumar/uplink/pull/200
.. _#204: https://github.com/prkumar/uplink/pull/204
.. _#207: https://github.com/prkumar/uplink/pull/207
.. _#209: https://github.com/prkumar/uplink/pull/209

.. Contributors
.. _@daa: https://github.com/daa
Expand All @@ -376,3 +388,5 @@ Added
.. _@kadrach: https://github.com/kadrach
.. _@cognifloyd: https://github.com/cognifloyd
.. _@gmcrocetti: https://github.com/gmcrocetti
.. _@leiserfg: https://github.com/leiserfg
.. _@lust4life: https://github.com/lust4life
2 changes: 1 addition & 1 deletion docs/source/user/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Request Body
============
The :py:class:`~uplink.Body` annotation identifies a method argument as the
the HTTP request body:
HTTP request body:
.. code-block:: python
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/test_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,46 @@ def test_create_request_body_converter(self, pydantic_model_mock):

assert result == expected_result
model_mock.dict.assert_called_once()
model_mock.dict.assert_called_once()

def test_convert_complex_model(self):
from json import loads
from datetime import datetime
from typing import List

class ComplexModel(pydantic.BaseModel):
when = datetime.utcnow() # type: datetime
where = 'http://example.com' # type: pydantic.AnyUrl
some = [1] # type: List[int]

model = ComplexModel()
request_body = {}
expected_result = loads(model.json())

converter = converters.PydanticConverter()
request_converter = converter.create_request_body_converter(ComplexModel)

result = request_converter.convert(request_body)

assert result == expected_result

def test_create_request_body_converter_with_original_model(
self, pydantic_model_mock
):
expected_result = {"id": 0}

model_mock, model = pydantic_model_mock
model_mock.dict.return_value = expected_result

request_body = model()

converter = converters.PydanticConverter()
request_converter = converter.create_request_body_converter(model)

result = request_converter.convert(request_body)

assert result == expected_result
model_mock.dict.assert_called_once()

def test_create_request_body_converter_without_schema(self, mocker):
expected_result = None
Expand Down
2 changes: 1 addition & 1 deletion uplink/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
that is used both in distribution (i.e., setup.py) and within the
codebase.
"""
__version__ = "0.9.2"
__version__ = "0.9.3"
21 changes: 20 additions & 1 deletion uplink/converters/pydantic_.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,31 @@
from uplink.utils import is_subclass


def _encode_pydantic(obj):
from pydantic.json import pydantic_encoder

# json atoms
if isinstance(obj, (str, int, float, bool)) or obj is None:
return obj

# json containers
if isinstance(obj, dict):
return {_encode_pydantic(k): _encode_pydantic(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_encode_pydantic(i) for i in obj]

# pydantic types
return _encode_pydantic(pydantic_encoder(obj))


class _PydanticRequestBody(Converter):
def __init__(self, model):
self._model = model

def convert(self, value):
return self._model(**value).dict()
if isinstance(value, self._model):
return _encode_pydantic(value)
return _encode_pydantic(self._model.parse_obj(value))


class _PydanticResponseBody(Converter):
Expand Down

0 comments on commit e84e10c

Please sign in to comment.