Skip to content

Commit

Permalink
fix: forward ref with nested models and optional fields (#1752)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
PrettyWood committed Oct 8, 2020
1 parent d5e9d9a commit a2fc01a
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
1 change: 1 addition & 0 deletions changes/1736-PrettyWood.md
@@ -0,0 +1 @@
Fix behaviour with forward refs and optional fields in nested models
10 changes: 5 additions & 5 deletions pydantic/fields.py
Expand Up @@ -334,6 +334,11 @@ def prepare(self) -> None:
"""

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
Expand Down Expand Up @@ -366,11 +371,6 @@ def _set_default_and_type(self) -> None:
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

Expand Down
33 changes: 33 additions & 0 deletions tests/test_forward_ref.py
Expand Up @@ -439,3 +439,36 @@ class Foo(BaseModel):
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)

0 comments on commit a2fc01a

Please sign in to comment.