fix: forward ref with nested models and optional fields (#1752)

* fix: forward ref with nested models and optional fields

PR #1712 introduced a regression for forward refs in `ModelField.prepare`
as it would not return early for forward refs anymore.
Optional fields would hence have `required` set to `True`.

closes #1736

* test: skip python 3.6 as __future__.annotations is not defined
This commit is contained in:
PrettyWood
2020-10-08 21:26:30 +02:00
committed by GitHub
parent d5e9d9abc8
commit a2fc01a59b
3 changed files with 39 additions and 5 deletions
+1
View File
@@ -0,0 +1 @@
Fix behaviour with forward refs and optional fields in nested models
+5 -5
View File
@@ -334,6 +334,11 @@ class ModelField(Representation):
"""
self._set_default_and_type()
if self.type_.__class__ == ForwardRef:
# self.type_ is currently a ForwardRef and there's nothing we can do now,
# user will need to call model.update_forward_refs()
return
self._type_analysis()
if self.required is Undefined:
self.required = True
@@ -366,11 +371,6 @@ class ModelField(Representation):
if self.type_ is None:
raise errors_.ConfigError(f'unable to infer type for attribute "{self.name}"')
if self.type_.__class__ == ForwardRef:
# self.type_ is currently a ForwardRef and there's nothing we can do now,
# user will need to call model.update_forward_refs()
return
if self.required is False and default_value is None:
self.allow_none = True
+33
View File
@@ -439,3 +439,36 @@ else:
raise AssertionError('error not raised')
"""
)
@skip_pre_37
def test_forward_ref_optional(create_module):
module = create_module(
"""
from __future__ import annotations
from pydantic import BaseModel, Field
from typing import List, Optional
class Spec(BaseModel):
spec_fields: List[str] = Field(..., alias="fields")
filter: Optional[str]
sort: Optional[str]
class PSpec(Spec):
g: Optional[GSpec]
class GSpec(Spec):
p: Optional[PSpec]
PSpec.update_forward_refs()
class Filter(BaseModel):
g: Optional[GSpec]
p: Optional[PSpec]
"""
)
Filter = module.Filter
assert isinstance(Filter(p={'sort': 'some_field:asc', 'fields': []}), Filter)