Skip to content

Commit

Permalink
fix: forward ref with nested models and optional fields
Browse files Browse the repository at this point in the history
PR pydantic#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 pydantic#1736
  • Loading branch information
PrettyWood committed Jul 22, 2020
1 parent e985857 commit 6961567
Show file tree
Hide file tree
Showing 3 changed files with 38 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 @@ -342,6 +342,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 @@ -374,11 +379,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
32 changes: 32 additions & 0 deletions tests/test_forward_ref.py
Expand Up @@ -439,3 +439,35 @@ class Foo(BaseModel):
raise AssertionError('error not raised')
"""
)


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 6961567

Please sign in to comment.