ruff/crates/ty_python_semantic/resources/mdtest/generics/legacy/paramspec.md

2.4 KiB

Legacy ParamSpec

Definition

Valid

from typing import ParamSpec

P = ParamSpec("P")
reveal_type(type(P))  # revealed: <class 'ParamSpec'>
reveal_type(P)  # revealed: typing.ParamSpec
reveal_type(P.__name__)  # revealed: Literal["P"]

The paramspec name can also be provided as a keyword argument:

from typing import ParamSpec

P = ParamSpec(name="P")
reveal_type(P.__name__)  # revealed: Literal["P"]

Must be directly assigned to a variable

from typing import ParamSpec

P = ParamSpec("P")
# error: [invalid-paramspec]
P1: ParamSpec = ParamSpec("P1")

# error: [invalid-paramspec]
tuple_with_typevar = ("foo", ParamSpec("W"))
reveal_type(tuple_with_typevar[1])  # revealed: ParamSpec
from typing_extensions import ParamSpec

T = ParamSpec("T")
# error: [invalid-paramspec]
P1: ParamSpec = ParamSpec("P1")

# error: [invalid-paramspec]
tuple_with_typevar = ("foo", ParamSpec("P2"))
reveal_type(tuple_with_typevar[1])  # revealed: ParamSpec

ParamSpec parameter must match variable name

from typing import ParamSpec

P1 = ParamSpec("P1")

# error: [invalid-paramspec]
P2 = ParamSpec("P3")

Accepts only a single name argument

The runtime should accept bounds and covariant and contravariant arguments in the declaration just as typing.TypeVar does, but for now we will defer the standardization of the semantics of those options to a later PEP.

from typing import ParamSpec

# error: [invalid-paramspec]
P1 = ParamSpec("P1", bound=int)
# error: [invalid-paramspec]
P2 = ParamSpec("P2", int, str)
# error: [invalid-paramspec]
P3 = ParamSpec("P3", covariant=True)
# error: [invalid-paramspec]
P4 = ParamSpec("P4", contravariant=True)

Defaults

[environment]
python-version = "3.13"

The default value for a ParamSpec can be either a list of types, ..., or another ParamSpec.

from typing import ParamSpec

P1 = ParamSpec("P1", default=[int, str])
P2 = ParamSpec("P2", default=...)
P3 = ParamSpec("P3", default=P2)

Other values are invalid.

# error: [invalid-paramspec]
P4 = ParamSpec("P4", default=int)

Forward references in stub files

Stubs natively support forward references, so patterns that would raise NameError at runtime are allowed in stub files:

from typing_extensions import ParamSpec

P = ParamSpec("P", default=[A, B])

class A: ...
class B: ...