From b77da1ec9e73cb7c3a3d175ffed56db24b008946 Mon Sep 17 00:00:00 2001 From: pfrederiks Date: Fri, 14 Jun 2019 17:56:08 +0200 Subject: [PATCH] Add support for InitVar (#591) * Add support for InitVar * Annotate *initvars as Any * Simplify tests * Add line to HISTORY.rst * Use dataclasses.fields which also ignores ClassVars * tweak history --- HISTORY.rst | 4 ++++ pydantic/dataclasses.py | 8 ++++---- tests/test_dataclasses.py | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 4f497c2..c6373d8 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,10 @@ History ------- +v0.29 (unreleased) +.................. +* support dataclasses.InitVar, #592 by @pfrederiks + v0.28 (2019-06-06) .................. * fix support for JSON Schema generation when using models with circular references in Python 3.7, #572 by @tiangolo diff --git a/pydantic/dataclasses.py b/pydantic/dataclasses.py index 6ef8273..4dbae31 100644 --- a/pydantic/dataclasses.py +++ b/pydantic/dataclasses.py @@ -25,9 +25,9 @@ if TYPE_CHECKING: # pragma: no cover pass -def _pydantic_post_init(self: 'DataclassType') -> None: +def _pydantic_post_init(self: 'DataclassType', *initvars: Any) -> None: if self.__post_init_original__: - self.__post_init_original__() + self.__post_init_original__(*initvars) d = validate_model(self.__pydantic_model__, self.__dict__, cls=self.__class__)[0] object.__setattr__(self, '__dict__', d) object.__setattr__(self, '__initialised__', True) @@ -79,8 +79,8 @@ def _process_class( cls = dataclasses._process_class(_cls, init, repr, eq, order, unsafe_hash, frozen) # type: ignore fields: Dict[str, Any] = { - name: (field.type, field.default if field.default != dataclasses.MISSING else Required) - for name, field in cls.__dataclass_fields__.items() + field.name: (field.type, field.default if field.default != dataclasses.MISSING else Required) + for field in dataclasses.fields(cls) } cls.__post_init_original__ = post_init_original cls.__post_init_post_parse__ = post_init_post_parse diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py index d0b1f15..851eaa2 100644 --- a/tests/test_dataclasses.py +++ b/tests/test_dataclasses.py @@ -1,5 +1,6 @@ import dataclasses from datetime import datetime +from typing import ClassVar import pytest @@ -380,3 +381,44 @@ def test_nested_schema(): } }, } + + +def test_initvar(): + InitVar = dataclasses.InitVar + + @pydantic.dataclasses.dataclass + class TestInitVar: + x: int + y: InitVar + + tiv = TestInitVar(1, 2) + assert tiv.x == 1 + with pytest.raises(AttributeError): + tiv.y + + +def test_derived_field_from_initvar(): + InitVar = dataclasses.InitVar + + @pydantic.dataclasses.dataclass + class DerivedWithInitVar: + plusone: int = dataclasses.field(init=False) + number: InitVar[int] + + def __post_init__(self, number): + self.plusone = number + 1 + + derived = DerivedWithInitVar(1) + assert derived.plusone == 2 + with pytest.raises(TypeError): + DerivedWithInitVar("Not A Number") + + +def test_classvar(): + @pydantic.dataclasses.dataclass + class TestClassVar: + klassvar: ClassVar = "I'm a Class variable" + x: int + + tcv = TestClassVar(2) + assert tcv.klassvar == "I'm a Class variable"