Skip to content

SafeString coerced to str when Slots class uses Pydantic's BaseModel #30

@JuroOravec

Description

@JuroOravec

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:

Image

This happens only when I:

  1. Declare slots with Component.Slots
  2. Use Pydantic's BaseModel to define the Slots class
  3. 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:

Image

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions