Skip to content

dataclass_transform doesn't work when the decorator returns a callable protocol #11015

@decorator-factory

Description

@decorator-factory

Code (pyright 1.1.406, Python 3.14):

from collections.abc import Callable
from typing import Protocol, dataclass_transform
from dataclasses import dataclass


@dataclass_transform(kw_only_default=True)
def rescoped[T: type](*, frozen: bool = False) -> Callable[[T], T]:
    return dataclass(frozen=frozen)  # pyright: ignore[reportUnknownVariableType]

@rescoped()
class Foo:
    x: str
    y: int

FOO = Foo(x="a", y=42)  # works


class Decorator(Protocol):
    def __call__[T: type](self, t: T, /) -> T:
        ...

@dataclass_transform(kw_only_default=True)
def spec(*, frozen: bool = False) -> Decorator:
    return dataclass(frozen=frozen)  # pyright: ignore[reportUnknownVariableType]

@spec()
class Bar:
    x: str
    y: int

BAR = Bar(x="a", y=42)
#         ^^^^^^^^^^^
# reportCallIssue: no parameter named "x", "y"

As I understand, the return types of spec and rescoped have the same semantics in pyright. However, pyright doesn't seem to recognize that Bar is a dataclass in the spec version. As far as I know (from this discourse thread), spec in this sample is the "official" way of returning a generic callable (while rescoped is an unofficial way that's supported by mypy and pyright)

Metadata

Metadata

Assignees

No one assigned

    Labels

    addressed in next versionIssue is fixed and will appear in next published versionbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions