You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the below example that uses the litestar DTO system with msgspec and pydantic v1, the API validator fails with the following error: litestar.exceptions.http_exceptions.ClientException: 400: Unsupported type: <class 'str'> - at $.display_name.
This is a potential regression after fixing this: #3710 as this case works fine in Litestar 2.11.
__all__ = ["GraphCrudController"]
import logging
import shortuuid
from litestar import Controller, post
from litestar.dto import DTOData
from dto.test_dtos import GraphReadDto, GraphWriteDto, GraphDto
log = logging.getLogger(__name__)
class GraphCrudController(Controller):
path = "/graphs"
dto = GraphWriteDto
return_dto = GraphReadDto
temp_data: GraphDto | None = None
@post(
path="/create",
summary="Create Graph",
)
async def create_graph(self, account_id: str, data: DTOData[GraphDto]) -> GraphDto:
log.info(
"Got a request to create a new graph object in account: %s", account_id
)
current_ts = time.time()
self.temp_data = data.create_instance(
id=shortuuid.uuid(),
account_id=account_id,
created_at=current_ts,
created_by="mock_user",
updated_at=current_ts,
updated_by="mock_user",
)
return self.temp_data
test_dtos.py
from typing import Annotated, Any
import shortuuid
from litestar.contrib.pydantic import PydanticDTO
from litestar.dto import DTOConfig
from pydantic import BaseModel
from pydantic.class_validators import validator
from pydantic.config import Extra
from pydantic.fields import Field
import time
class GeneralIdentifiers(BaseModel):
id: str = Field(default_factory=lambda: shortuuid.uuid())
created_at: int = Field(default_factory=lambda: time.time())
created_by: str
updated_at: int = Field(default_factory=lambda: time.time())
updated_by: str
class GraphBaseMeta(BaseModel):
display_name: str = Field(default_factory=lambda: shortuuid.uuid(), max_length=64)
version: float = Field(default=1.0)
account_id: str | None = Field(default=None)
description: str | None = Field(default=None, max_length=600)
class NodePosition(BaseModel):
x: float
y: float
class NodeParamData(BaseModel):
value: Any
show: bool = True
class Config:
extra = Extra.forbid
class Node(BaseModel):
id: str = Field(default_factory=lambda: shortuuid.uuid())
type: str
data: dict[str, NodeParamData]
position: NodePosition
class Edge(BaseModel):
id: str = Field(default_factory=lambda: shortuuid.uuid())
source: str
target: str
class GraphNodesEdges(BaseModel):
nodes: list[Node]
edges: list[Edge]
class GraphBase(GraphBaseMeta, GraphNodesEdges):
pass
class Graph(GraphBase, GeneralIdentifiers):
pass
class GraphDto(Graph):
@validator("nodes")
def validate_nodes(cls, value: list[Node]) -> list[Node]:
node_ids: set[str] = set()
for node in value:
if node.id:
if node.id in node_ids:
raise ValueError("Duplicate node ids are not allowed")
node_ids.add(node.id)
return value
write_config = DTOConfig(
exclude={
"id",
"account_id",
"created_at",
"created_by",
"updated_at",
"updated_by",
},
max_nested_depth=3,
)
read_config = DTOConfig(max_nested_depth=3)
GraphWriteDto = PydanticDTO[Annotated[GraphDto, write_config]]
GraphReadDto = PydanticDTO[Annotated[GraphDto, read_config]]
### Steps to reproduce
```bash
1. Run the application with the above MCVE. The dto class is under the Python package "dto", and the controller class is under the Python package "controllers". app.py located is in the root level of the project.
2. Run the following cURL(change the host/port if yours are configured differently):
curl --location 'localhost:8080/api/v1/accounts/123/graphs/create' \
--header 'Content-Type: application/json' \
--data '{
"display_name": "Test Graph",
"edges": [
{
"source": "source_test_id",
"sourceHandle": "handle_test",
"target": "target_test_id",
"targetHandle": "handle_test"
}
],
"public": true,
"nodes": [
{
"id": "source_test_id",
"base_type": "test",
"type": "test",
"position": {
"x": 10.5,
"y": 18.31231231
},
"data": {
"name": {
"show": true,
"value": "test"
}
}
},
{
"id": "target_test_id",
"base_type": "test",
"type": "test",
"position": {
"x": 15.5,
"y": 32.31231231
},
"data": {
"name": {
"show": true,
"value": "test"
}
}
}
]
}'
import sys; print('Python %s on %s' % (sys.version, sys.platform))
/Users/sergeyk/PycharmProjects/litestar-playground/.venv/bin/python -X pycache_prefix=/Users/sergeyk/Library/Caches/JetBrains/PyCharm2024.2/cpython-cache /Applications/PyCharm.app/Contents/plugins/python-ce/helpers/pydev/pydevd.py --module --multiprocess --qt-support=auto --client 127.0.0.1 --port 57713 --file litestar run --host 0.0.0.0 --port 8080
Connected to pydev debugger (build 242.23339.19)
INFO: Started server process [99855]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
INFO: 127.0.0.1:57717 - "POST /api/v1/accounts/123/graphs/create HTTP/1.1" 400 Bad Request
ERROR - 2024-10-01 19:48:33,156 - litestar - config - Uncaught exception (connection_type=http, path=/api/v1/accounts/123/graphs/create):
Traceback (most recent call last):
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/serialization/msgspec_hooks.py", line 139, in default_deserializer
raise TypeError(f"Unsupported type: {type(value)!r}")
TypeError: Unsupported type: <class 'str'>
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/serialization/msgspec_hooks.py", line 209, in decode_json
return msgspec.json.decode(
^^^^^^^^^^^^^^^^^^^^
msgspec.ValidationError: Unsupported type: <class 'str'> - at `$.display_name`
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/routes/http.py", line 173, in _get_response_data
kwargs = await parameter_model.to_kwargs(connection=request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/_kwargs/kwargs_model.py", line 380, in to_kwargs
await extractor(output, connection)
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/_kwargs/extractors.py", line 484, in extractor
values["data"] = await data_extractor(connection)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/_kwargs/extractors.py", line 502, in dto_extractor
return data_dto(connection).decode_bytes(body)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/contrib/pydantic/pydantic_dto_factory.py", line 104, in decode_bytes
returnsuper().decode_bytes(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/dto/base_dto.py", line 115, in decode_bytes
return backend.populate_data_from_raw(value, self.asgi_connection)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/dto/_codegen_backend.py", line 143, in populate_data_from_raw
data_as_builtins=self._transfer_to_dict(self.parse_raw(raw, asgi_connection)),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/dto/_backend.py", line 241, in parse_raw
result = decode_json(value=raw, target_type=self.annotation, type_decoders=type_decoders, strict=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/serialization/msgspec_hooks.py", line 219, in decode_json
raise SerializationException(str(msgspec_error)) from msgspec_error
litestar.exceptions.base_exceptions.SerializationException: Unsupported type: <class 'str'> - at `$.display_name`
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/middleware/_internal/exceptions/middleware.py", line 159, in __call__
await self.app(scope, receive, capture_response_started)
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/_asgi/asgi_router.py", line 100, in __call__
await asgi_app(scope, receive, send)
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/routes/http.py", line 80, in handle
response = await self._get_response_for_request(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/routes/http.py", line 132, in _get_response_for_request
return await self._call_handler_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/routes/http.py", line 152, in _call_handler_function
response_data, cleanup_group = await self._get_response_data(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/sergeyk/PycharmProjects/litestar-playground/.venv/lib/python3.11/site-packages/litestar/routes/http.py", line 175, in _get_response_data
raise ClientException(str(e)) from e
litestar.exceptions.http_exceptions.ClientException: 400: Unsupported type: <class 'str'> - at `$.display_name`
Description
In the below example that uses the litestar DTO system with msgspec and pydantic v1, the API validator fails with the following error: litestar.exceptions.http_exceptions.ClientException: 400: Unsupported type: <class 'str'> - at
$.display_name
.This is a potential regression after fixing this: #3710 as this case works fine in Litestar 2.11.
Python version: 3.11.9
Pydantic version: 1.10.18
URL to code causing the issue
No response
MCVE
app.py
graph_curd_v1_controller.py
test_dtos.py
Logs
Litestar Version
2.12.1
Platform
Note
While we are open for sponsoring on GitHub Sponsors and
OpenCollective, we also utilize Polar.sh to engage in pledge-based sponsorship.
Check out all issues funded or available for funding on our Polar.sh dashboard
The text was updated successfully, but these errors were encountered: