From abb3b40195e95d5b40bb3fb667ff33b84cb21ce1 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Wed, 9 Oct 2019 04:44:05 +0900 Subject: [PATCH 1/4] fix type field --- pydantic/main.py | 8 ++++++-- tests/test_edge_cases.py | 18 +++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pydantic/main.py b/pydantic/main.py index 5221650d3d..176c7007c4 100644 --- a/pydantic/main.py +++ b/pydantic/main.py @@ -18,7 +18,7 @@ from .schema import model_schema from .types import PyObject, StrBytes from .typing import AnyCallable, AnyType, ForwardRef, is_classvar, resolve_annotations, update_field_forward_refs -from .utils import GetterDict, ValueItems, truncate, validate_field_name +from .utils import GetterDict, ValueItems, lenient_issubclass, truncate, validate_field_name if TYPE_CHECKING: from .class_validators import ValidatorListDict @@ -175,7 +175,11 @@ def __new__(mcs, name, bases, namespace, **kwargs): elif is_valid_field(ann_name): validate_field_name(bases, ann_name) value = namespace.get(ann_name, ...) - if isinstance(value, untouched_types) and ann_type != PyObject: + if ( + isinstance(value, untouched_types) + and ann_type != PyObject + and not lenient_issubclass(getattr(ann_type, '__origin__', None), Type) + ): continue fields[ann_name] = ModelField.infer( name=ann_name, diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py index ed32b08dc6..5fde3decb1 100644 --- a/tests/test_edge_cases.py +++ b/tests/test_edge_cases.py @@ -1,7 +1,7 @@ import re from decimal import Decimal from enum import Enum -from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union import pytest @@ -957,15 +957,19 @@ def __init__(self, **data) -> None: Foobar(x=1) -def test_ignored_type(): - def foobar(): +def test_type_on_annotation(): + class FooBar: pass class Model(BaseModel): - a: int = foobar - b: int - - assert Model.__fields__.keys() == {'b'} + a: int = int + b: Type[int] + c: Type[int] = int + d: FooBar = FooBar + e: Type[FooBar] + f: Type[FooBar] = FooBar + + assert Model.__fields__.keys() == {'b', 'c', 'e', 'f'} def test_optional_subfields(): From e2c70e120a1dc800982a88f0b05ea3113232d00a Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Wed, 9 Oct 2019 05:14:48 +0900 Subject: [PATCH 2/4] update changes --- changes/880-koxudaxi.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/880-koxudaxi.md diff --git a/changes/880-koxudaxi.md b/changes/880-koxudaxi.md new file mode 100644 index 0000000000..0ee8dd6f9b --- /dev/null +++ b/changes/880-koxudaxi.md @@ -0,0 +1 @@ +Fix field of a type that has a default value. \ No newline at end of file From 4c41dd3ede53a6df897e9c7b78bfc7813e76f3ea Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Wed, 9 Oct 2019 10:36:49 +0900 Subject: [PATCH 3/4] add testcase --- tests/test_edge_cases.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py index 5fde3decb1..74301d8c7d 100644 --- a/tests/test_edge_cases.py +++ b/tests/test_edge_cases.py @@ -971,6 +971,35 @@ class Model(BaseModel): assert Model.__fields__.keys() == {'b', 'c', 'e', 'f'} + class Parent: + def echo(self): + return 'parent' + + class Child(Parent): + def echo(self): + return 'child' + + class Different: + def echo(self): + return 'different' + + class ModelParent(BaseModel): + v: Type[Parent] = Parent + + assert ModelParent(v=Parent).v().echo() == 'parent' + assert ModelParent().v().echo() == 'parent' + assert ModelParent(v=Child).v().echo() == 'child' + with pytest.raises(ValidationError) as exc_info: + ModelParent(v=Different) + assert exc_info.value.errors() == [ + { + 'loc': ('v',), + 'msg': 'subclass of Parent expected', + 'type': 'type_error.subclass', + 'ctx': {'expected_class': 'Parent'}, + } + ] + def test_optional_subfields(): class Model(BaseModel): From a5de5c94ae529f23a87460804cb9be5e74f2b7c4 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Wed, 9 Oct 2019 21:46:43 +0900 Subject: [PATCH 4/4] separate test for type fields --- tests/test_edge_cases.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py index 74301d8c7d..6c97c9a8b8 100644 --- a/tests/test_edge_cases.py +++ b/tests/test_edge_cases.py @@ -971,6 +971,8 @@ class Model(BaseModel): assert Model.__fields__.keys() == {'b', 'c', 'e', 'f'} + +def test_assign_type(): class Parent: def echo(self): return 'parent' @@ -983,14 +985,14 @@ class Different: def echo(self): return 'different' - class ModelParent(BaseModel): + class Model(BaseModel): v: Type[Parent] = Parent - assert ModelParent(v=Parent).v().echo() == 'parent' - assert ModelParent().v().echo() == 'parent' - assert ModelParent(v=Child).v().echo() == 'child' + assert Model(v=Parent).v().echo() == 'parent' + assert Model().v().echo() == 'parent' + assert Model(v=Child).v().echo() == 'child' with pytest.raises(ValidationError) as exc_info: - ModelParent(v=Different) + Model(v=Different) assert exc_info.value.errors() == [ { 'loc': ('v',),