diff --git a/HISTORY.rst b/HISTORY.rst index 73d2eda..400b0fb 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -8,6 +8,7 @@ v0.23 (unreleased) * improve documentation for contributing section, # 441 @pilosus * improve README.rst to include essential information about the package, #446 by @pilosus * ``IntEnum`` support, #444 by @potykion +* fix ``ForwardRef`` collection bug, #450 by @tigerwings v0.22 (2019-03-29) .................... diff --git a/pydantic/validators.py b/pydantic/validators.py index 3794a05..547d443 100644 --- a/pydantic/validators.py +++ b/pydantic/validators.py @@ -10,7 +10,7 @@ from uuid import UUID from . import errors from .datetime_parse import parse_date, parse_datetime, parse_duration, parse_time -from .utils import AnyCallable, AnyType, change_exception, display_as_type, is_callable_type, sequence_like +from .utils import AnyCallable, AnyType, ForwardRef, change_exception, display_as_type, is_callable_type, sequence_like if TYPE_CHECKING: # pragma: no cover from .fields import Field @@ -357,7 +357,7 @@ _VALIDATORS: List[Tuple[AnyType, List[AnyCallable]]] = [ def find_validators(type_: AnyType, arbitrary_types_allowed: bool = False) -> List[AnyCallable]: - if type_ is Any: + if type_ is Any or type(type_) == ForwardRef: return [] if type_ is Pattern: return pattern_validators diff --git a/tests/test_py37.py b/tests/test_py37.py index 68ed363..d8c98a2 100644 --- a/tests/test_py37.py +++ b/tests/test_py37.py @@ -5,7 +5,7 @@ import sys import pytest -from pydantic import ConfigError +from pydantic import ConfigError, ValidationError skip_not_37 = pytest.mark.skipif(sys.version_info < (3, 7), reason='testing >= 3.7 behaviour only') @@ -83,6 +83,40 @@ Foo.update_forward_refs() assert module.Foo(b={'a': '321'}).dict() == {'a': 123, 'b': {'a': 321, 'b': None}} +@skip_not_37 +def test_self_forward_ref_collection(create_module): + module = create_module( + """ +from typing import ForwardRef, List, Dict +from pydantic import BaseModel + +Foo = ForwardRef('Foo') + +class Foo(BaseModel): + a: int = 123 + b: Foo = None + c: List[Foo] = [] + d: Dict[str, Foo] = {} + +Foo.update_forward_refs() + """ + ) + + assert module.Foo().dict() == {'a': 123, 'b': None, 'c': [], 'd': {}} + assert module.Foo(b={'a': '321'}, c=[{'a': 234}], d={'bar': {'a': 345}}).dict() == { + 'a': 123, + 'b': {'a': 321, 'b': None, 'c': [], 'd': {}}, + 'c': [{'a': 234, 'b': None, 'c': [], 'd': {}}], + 'd': {'bar': {'a': 345, 'b': None, 'c': [], 'd': {}}}, + } + + with pytest.raises(ValidationError) as exc_info: + module.Foo(b={'a': '321'}, c=[{'b': 234}], d={'bar': {'a': 345}}) + assert exc_info.value.errors() == [ + {'loc': ('c', 0, 'b'), 'msg': 'value is not a valid dict', 'type': 'type_error.dict'} + ] + + @skip_not_37 def test_self_forward_ref_local(create_module): module = create_module(