-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
There's an error where Pydantic incorrectly coerces SafeString to str.
The end result is that Django template receives a plain string instead of SafeString, thus incorrectly escaping the HTML content:
This happens only when I:
- Declare slots with
Component.Slots - Use Pydantic's
BaseModelto define theSlotsclass - Pass in the slots as
SafeString
E.g.
from pydantic import BaseModel
from django_components import Component, SlotInput
class Table(Component):
class Slots(BaseModel):
project_nav: SlotInput
Table.render(
slots={
"project_nav": ProjectNav.render(...),
}
)I know that this is an issue with how Pydantic handles the SlotInput type, because the values are coerced to str only once Slots class is instantiated:
Solution
I have recently read through Pydantic docs page on union types and they have an unusual way of handling unions, so I believe this might the case.
Don't know the internals of Pydantic, so I think we should raise this with Pydantic project to ask for help.
For context, the definition of SlotInput is:
TSlotData = TypeVar("TSlotData", bound=Mapping)
SlotResult = Union[str, SafeString]
class SlotFunc(Protocol, Generic[TSlotData]):
def __call__(self, ctx: SlotContext[TSlotData]) -> SlotResult:
...
@dataclass
class Slot(Generic[TSlotData]):
...
SlotInput = Union[SlotResult, SlotFunc[TSlotData], Slot[TSlotData]]Moreover, definition of SafeString is
class SafeString(str, SafeData):
...And our Component.render() returns SafeString instances. So I don't understand why Pydantic is coercing that to str instead of SafeString.
Based on their "exactness" logic in their docs, I would have expected that SafeString instance would match SafeString class over str