Skip to content

should mypy recognize pep-681 @dataclass_transform on a method as well as a function? #19824

Open

Description

@zzzeek

Just noticed that trying to make an object method provide @dataclass_transform functionality is not recognized by mypy as a pep-681 use of @dataclass_transform (it does not complain either, just silently ignores it):

from typing import dataclass_transform

class SomeClassThing:
    @dataclass_transform()
    def make_a_dataclass(self, cls: type) -> type:
        return cls

sct = SomeClassThing()

@sct.make_a_dataclass
class MyClass:
    x: int
    y: str

m1 = MyClass(x=5, y="y")

mypy:

test4.py:16: error: Unexpected keyword argument "x" for "MyClass"  [call-arg]
test4.py:16: error: Unexpected keyword argument "y" for "MyClass"  [call-arg]
Found 2 errors in 1 file (checked 1 source file)

the above would need to be reorganized like this:

from typing import Callable
from typing import dataclass_transform

class SomeClassThing:
    pass

@dataclass_transform()
def make_a_dataclass(sct: SomeClassThing) -> Callable[[type], type]:
    def decorate(cls: type) -> type:
        return cls
    return decorate

sct = SomeClassThing()

@make_a_dataclass(sct)
class MyClass:
    x: int
    y: str

m1 = MyClass(x=5, y="y")

where mypy is happy:

Success: no issues found in 1 source file

SQLAlchemy has a pep-681 feature that mostly uses the superclass approach, however we also offer a decorator that looks like @mapper_registry.mapped_as_dataclass(), and I just noticed that while pyright has always accepted this, mypy does not. So I'm adding an alternative decorator of the above form @mapped_as_dataclass(mapper_registry). Took a look at pep-681 and it discusses @dataclass_transform applied to a function or a class, not a method. So I'm out of luck. but it seems ....like it should work? pyright does it....

Activity

  1. sterliakov commented on Sep 10, 2025

    @sterliakov
    Collaborator

    Funny enough, the typing spec does not mention methods either. I'm inclined to say that @dataclass_transform should be supported on methods (and it doesn't contradict PEP language, as methods are actually functions at the time when decorator is applied to then), but this is really somewhat grey area.

  2. tommie-lie commented on Nov 9, 2025

    @tommie-lie

    I have another usecase for that: Decorators that are implemented as a class using __call__ to do the decoration needs @dataclass_transform on methods (and in this case methods that are not "visible" on the call site) as well:

    class decorator:
        @dataclass_transform
        def __call__(self, cls):
              return dataclass(cls)
    
    
    @decorator()
    class DataclassLike:
        i: int

    In this case, instances of DataclassLike are not recognized as dataclasses by mypy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions