Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/release-notes/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -362,3 +362,9 @@
Add a new attribute :attr:`~litestar.middleware.ASGIMiddleware.should_bypass_for_scope`;
A callable which takes in a :class:`~litestar.types.Scope` and returns a boolean
to indicate whether to bypass the middleware for the current request.

.. change:: Fix KeyError when ClassVar exists on msgspec Struct
:type: bugfix
:pr: 4665

Fix a bug in :class:`MsgspecDTO` where a KeyError was raised if a :class:`msgspec.Struct` contained a :class:`~typing.ClassVar`. ClassVars are now correctly skipped when generating field definitions.
2 changes: 2 additions & 0 deletions litestar/dto/msgspec_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ def generate_field_definitions(cls, model_type: type[Struct]) -> Generator[DTOFi
property_fields = cls.get_property_fields(model_type)

for key, field_definition in cls.get_model_type_hints(model_type).items():
if key not in inspect_fields:
continue
kwarg_definition, extra = kwarg_definition_from_field(inspect_fields[key])
field_definition = dataclasses.replace(field_definition, kwarg_definition=kwarg_definition)
field_definition.extra.update(extra)
Expand Down
14 changes: 13 additions & 1 deletion tests/unit/test_contrib/test_msgspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import itertools
from dataclasses import replace
from typing import TYPE_CHECKING, Annotated
from typing import TYPE_CHECKING, Annotated, ClassVar
from unittest.mock import ANY

import pytest
Expand Down Expand Up @@ -216,3 +216,15 @@ def handler_3(data: Model3) -> None:
"required": ["foo", "regular_field"],
"title": "Model3",
}


def test_msgspec_dto_with_classvar() -> None:
class ModelWithClassVar(Struct):
regular_field: str
class_field: ClassVar[str] = "a string in the class"

field_defs = list(MsgspecDTO.generate_field_definitions(ModelWithClassVar))

# Only the regular field should be included, not the ClassVar
assert len(field_defs) == 1
assert field_defs[0].name == "regular_field"
Loading