[Python] Why is pylance not able to statically determine Literal Union type in dictionary value

Discussão em 'Python' iniciado por Stack, Julho 1, 2025.

  1. Stack

    Stack Membro Participativo

    When writing a to_ChatCompletionMessageParam() instance method, I have the following implementation:

    def to_ChatCompletionMessageParam(self) -> ChatCompletionMessageParam:
    author: Literal["assistant", "user"] = self.author
    result: ChatCompletionMessageParam = {
    "role": author,
    "content": self.item.value()
    }

    ...

    return result


    The type of ChatCompletionMessageParam is a union of multiple TypedDict objects that can be coerced to a regular dictionary literal. What's important is that each type in the union has a field which is a required Literal. For example:

    ChatCompletionMessageParam: TypeAlias = Union[ChatCompletionUserMessageParam, ChatCompletionAssistantMessageParam]

    class ChatCompletionUserMessageParam(TypedDict, total=False):
    content: Required[Union[str, Iterable[ChatCompletionContentPartParam]]]
    """The contents of the user message."""

    role: Required[Literal["user"]]
    """The role of the messages author, in this case `user`."""

    ...

    class ChatCompletionAssistantMessageParam(TypedDict, total=False):
    role: Required[Literal["assistant"]]
    """The role of the messages author, in this case `assistant`."""

    content: Union[str, Iterable[ContentArrayOfContentPart], None]
    """The contents of the assistant message.

    Required unless `tool_calls` or `function_call` is specified.
    """

    ...


    The only fix I have right now is doing an explicit Literal check such as

    def to_ChatCompletionMessageParam(self) -> ChatCompletionMessageParam:
    author: Literal["assistant", "user"] = self.author

    if author == "assistant":
    result: ChatCompletionMessageParam = {
    "role": author,
    "content": self.item.value()
    }
    else:
    result: ChatCompletionMessageParam = {
    "role": author,
    "content": self.item.value()
    }
    return result


    Is this is a bug or is there a specific edge-case that pylance is unable to rule out in the simplified code?

    TL;DR: When creating a dictionary literal that's meant to have a union type of multiple dictionary entries that require a Literal value for a field, pylance is unable to check that a supplied value type checks.

    Continue reading...

Compartilhe esta Página