Skip to content

Commit

Permalink
fix: support pydantic.Field(kw_only=True) with inherited dataclasses
Browse files Browse the repository at this point in the history
closes #7770
  • Loading branch information
PrettyWood committed Oct 14, 2023
1 parent cde930f commit 2069ae8
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 1 deletion.
14 changes: 13 additions & 1 deletion pydantic/dataclasses.py
Expand Up @@ -12,7 +12,7 @@
from ._internal import _dataclasses as _pydantic_dataclasses
from ._migration import getattr_migration
from .config import ConfigDict
from .fields import Field
from .fields import Field, FieldInfo

if TYPE_CHECKING:
from ._internal._dataclasses import PydanticDataclass
Expand Down Expand Up @@ -185,6 +185,18 @@ def create_dataclass(cls: type[Any]) -> type[PydanticDataclass]:
bases = bases + (generic_base,)
cls = types.new_class(cls.__name__, bases)

# If we have something like `x: int = Field(default=0, kw_only=True)`
# we need to make sure that it's understood by `dataclasses`
# as `field(default=Field(...), kw_only=True)` to allow some usages with inheritance
for field_name in cls.__annotations__:
try:
field_value = getattr(cls, field_name)
except AttributeError:
# no default value has been set for this field
continue
if isinstance(field_value, FieldInfo) and field_value.kw_only:
setattr(cls, field_name, dataclasses.field(default=field_value, kw_only=True))

cls = dataclasses.dataclass( # type: ignore[call-overload]
cls,
# the value of init here doesn't affect anything except that it makes it easier to generate a signature
Expand Down
15 changes: 15 additions & 0 deletions tests/test_dataclasses.py
Expand Up @@ -1644,6 +1644,21 @@ class A:
assert A(b='hi').b == 'hi'


@pytest.mark.skipif(sys.version_info < (3, 10), reason='kw_only is not available in python < 3.10')
def test_kw_only_subclass():
@pydantic.dataclasses.dataclass
class A:
x: int
y: int = pydantic.Field(default=0, kw_only=True)

@pydantic.dataclasses.dataclass
class B(A):
z: int

assert B(1, 2) == B(x=1, y=0, z=2)
assert B(1, y=2, z=3) == B(x=1, y=2, z=3)


def dataclass_decorators(include_identity: bool = False, exclude_combined: bool = False):
decorators = [pydantic.dataclasses.dataclass, dataclasses.dataclass]
ids = ['pydantic', 'stdlib']
Expand Down

0 comments on commit 2069ae8

Please sign in to comment.