ruff/crates/ty_python_semantic/resources/mdtest/annotations/literal_string.md
2025-05-03 19:49:15 +02:00

3.3 KiB

LiteralString

LiteralString represents a string that is either defined directly within the source code or is made up of such components.

Parts of the testcases defined here were adapted from the specification's examples.

Usages

Valid places

It can be used anywhere a type is accepted:

from typing_extensions import LiteralString

x: LiteralString

def f():
    reveal_type(x)  # revealed: LiteralString

Within Literal

LiteralString cannot be used within Literal:

from typing_extensions import Literal, LiteralString

bad_union: Literal["hello", LiteralString]  # error: [invalid-type-form]
bad_nesting: Literal[LiteralString]  # error: [invalid-type-form]

Parameterized

LiteralString cannot be parameterized.

from typing_extensions import LiteralString

# error: [invalid-type-form]
a: LiteralString[str]

# error: [invalid-type-form]
# error: [unresolved-reference] "Name `foo` used when not defined"
b: LiteralString["foo"]

As a base class

Subclassing LiteralString leads to a runtime error.

from typing_extensions import LiteralString

class C(LiteralString): ...  # error: [invalid-base]

Inference

Common operations

from typing_extensions import LiteralString

foo: LiteralString = "foo"
reveal_type(foo)  # revealed: Literal["foo"]

bar: LiteralString = "bar"
reveal_type(foo + bar)  # revealed: Literal["foobar"]

baz: LiteralString = "baz"
baz += foo
reveal_type(baz)  # revealed: Literal["bazfoo"]

qux = (foo, bar)
reveal_type(qux)  # revealed: tuple[Literal["foo"], Literal["bar"]]

reveal_type(foo.join(qux))  # revealed: LiteralString

template: LiteralString = "{}, {}"
reveal_type(template)  # revealed: Literal["{}, {}"]
reveal_type(template.format(foo, bar))  # revealed: LiteralString

Assignability

Literal[""] is assignable to LiteralString, and LiteralString is assignable to str, but not vice versa.

from typing_extensions import Literal, LiteralString

def _(flag: bool):
    foo_1: Literal["foo"] = "foo"
    bar_1: LiteralString = foo_1  # fine

    foo_2 = "foo" if flag else "bar"
    reveal_type(foo_2)  # revealed: Literal["foo", "bar"]
    bar_2: LiteralString = foo_2  # fine

    foo_3: LiteralString = "foo" * 1_000_000_000
    bar_3: str = foo_2  # fine

    baz_1: str = repr(object())
    qux_1: LiteralString = baz_1  # error: [invalid-assignment]

    baz_2: LiteralString = "baz" * 1_000_000_000
    qux_2: Literal["qux"] = baz_2  # error: [invalid-assignment]

    baz_3 = "foo" if flag else 1
    reveal_type(baz_3)  # revealed: Literal["foo", 1]
    qux_3: LiteralString = baz_3  # error: [invalid-assignment]

Narrowing

from typing_extensions import LiteralString

lorem: LiteralString = "lorem" * 1_000_000_000

reveal_type(lorem)  # revealed: LiteralString

if lorem == "ipsum":
    reveal_type(lorem)  # revealed: Literal["ipsum"]

reveal_type(lorem)  # revealed: LiteralString

if "" < lorem == "ipsum":
    reveal_type(lorem)  # revealed: Literal["ipsum"]

typing.LiteralString

typing.LiteralString is only available in Python 3.11 and later:

[environment]
python-version = "3.11"
from typing import LiteralString

x: LiteralString = "foo"

def f():
    reveal_type(x)  # revealed: LiteralString