diff --git a/poetry.lock b/poetry.lock index 84d1b43..7689de4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1868,4 +1868,4 @@ compiler = ["black", "isort", "jinja2"] [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "f9503e42026d0807dc3ed344b5f8e6fa3f1c7ffa9c66b086de929aefaa8cb8c6" +content-hash = "58b357685be67e8852b589ee0df3011b37dc1a2460ece732c0fa4c922f62bddd" diff --git a/pyproject.toml b/pyproject.toml index 043f021..6d43e2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ packages = [ python = "^3.7" black = { version = ">=19.3b0", optional = true } grpclib = "^0.4.1" +importlib-metadata = { version = ">=1.6.0", python = "<3.8" } jinja2 = { version = ">=3.0.3", optional = true } python-dateutil = "^2.8" isort = {version = "^5.11.5", optional = true} diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index ed42cf5..6215254 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1373,6 +1373,9 @@ class Message(ABC): value = [i.to_pydict(casing, include_default_values) for i in value] if value or include_default_values: output[cased_name] = value + elif value is None: + if include_default_values: + output[cased_name] = None elif ( value._serialized_on_wire or include_default_values diff --git a/src/betterproto/_version.py b/src/betterproto/_version.py index e40ec96..484794b 100644 --- a/src/betterproto/_version.py +++ b/src/betterproto/_version.py @@ -1,4 +1,7 @@ -from pkg_resources import get_distribution +try: + from importlib import metadata +except ImportError: # for Python<3.8 + import importlib_metadata as metadata # type: ignore -__version__ = get_distribution("betterproto").version +__version__ = metadata.version("betterproto") diff --git a/tests/test_features.py b/tests/test_features.py index 2deef2b..940cd51 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -265,6 +265,32 @@ def test_optional_flag(): assert Request().parse(b"\n\x00").flag is False +def test_optional_datetime_to_dict(): + @dataclass + class Request(betterproto.Message): + date: Optional[datetime] = betterproto.message_field(1, optional=True) + + # Check dict serialization + assert Request().to_dict() == {} + assert Request().to_dict(include_default_values=True) == {"date": None} + assert Request(date=datetime(2020, 1, 1)).to_dict() == { + "date": "2020-01-01T00:00:00Z" + } + assert Request(date=datetime(2020, 1, 1)).to_dict(include_default_values=True) == { + "date": "2020-01-01T00:00:00Z" + } + + # Check pydict serialization + assert Request().to_pydict() == {} + assert Request().to_pydict(include_default_values=True) == {"date": None} + assert Request(date=datetime(2020, 1, 1)).to_pydict() == { + "date": datetime(2020, 1, 1) + } + assert Request(date=datetime(2020, 1, 1)).to_pydict( + include_default_values=True + ) == {"date": datetime(2020, 1, 1)} + + def test_to_json_default_values(): @dataclass class TestMessage(betterproto.Message):