Background

typing.Literal was defined with static type checking in mind. During static type checking, Literal requires the value being checked to be a literal value, matching one of the Literal value(s) specified. In a static type checking context, this behaviour is both intuitive and obvious.


Problem

During dynamic type checking, Literal can be specified in a type hint, but there is no obvious way to determine at runtime whether the value being checked is sourced from a Python literal or elsewhere. For example, it could have been loaded from JSON. Furthermore, it is not necessarily desirable to make such a determination at runtime.

Pydantic currently validates a value against a Literal type hint without regard to whether it is a Python literal. It appears to simply check for type and value equality against the defined Literal values in the type hint. (This is originally how I interpreted Literal would behave when I first encountered it.) I believe this makes Pydantic’s use of Literal incompatible with static type checking tools like mypy.


Ideas

1. Codify Pydantic’s current behavior without changing static type checking behavior (in PEP 586 or elsewhere)
This would lead to many situations where code would pass type checking at runtime, but fail static type checking due to constraints on literal values.

2. Relax Literal’s “literalness” static type checking behavior
I believe this would conflict with developers’ objectives of keeping the value “safe” by requiring it be literally supplied, not allowing it to be deserialized or built dynamically. (Discussed previously on this list.)

3. Just use Enum
I would argue Enum is unnecessary verbose, requiring the definition of a class, separate members, subclassing and dunders (e.g. __str__) to handle string values. It requires unnecessary naming of values, and requires avoiding “invalid” names. (3.11’s StrEnum could mitigate some of this?)

4. Define a new “relaxed” Literal type hint
Define a new type hint, paralleling Literal’s syntax, relaxing the requirement that the value be an actual literal. Candidate names like Figure[...], Value[...], enum[...]. It would likely not be included in stdlib, so would likely be implemented by dynamic type checking libraries.


What are your thoughts? Thanks in advance for your consideration.