8000 More accurate `dataclasses.dataclass` overloads by max-muoto · Pull Request #14095 · python/typeshed · GitHub
[go: up one dir, main page]

Skip to content

More accurate dataclasses.dataclass overloads #14095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main 8000
Choose a base branch
from

Conversation

max-muoto
Copy link
Contributor
@max-muoto max-muoto commented May 17, 2025

At runtime, you're additional able to pass in supported key-word arguments to dataclass instead of, as the the stubs would suggest either pass in cls or just pass in key-word arguments. This is clearly visible from the cpython implementation:

def dataclass(cls=None, /, *, init=True, repr=True, eq=True, order=False,
              unsafe_hash=False, frozen=False, match_args=True,
              kw_only=False, slots=False, weakref_slot=False):
    """Add dunder methods based on the fields defined in the class.

    Examines PEP 526 __annotations__ to determine fields.

    If init is true, an __init__() method is added to the class. If repr
    is true, a __repr__() method is added. If order is true, rich
    comparison dunder methods are added. If unsafe_hash is true, a
    __hash__() method is added. If frozen is true, fields may not be
    assigned to after instance creation. If match_args is true, the
    __match_args__ tuple is added. If kw_only is true, then by default
    all fields are keyword-only. If slots is true, a new class with a
    __slots__ attribute is returned.
    """

    def wrap(cls):
        return _process_class(cls, init, repr, eq, order, unsafe_hash,
                              frozen, match_args, kw_only, slots,
                              weakref_slot)

    # See if we're being called as @dataclass or @dataclass().
    if cls is None:
        # We're called with parens.
        return wrap

    # We're called as @dataclass without parens.
    return wrap(cls)

Perhaps there's some valid reason we're not doing this relating to type-checker implementations, but would be curious to know if that's the case.

@max-muoto max-muoto changed the title More accurate dataclass types More accurate dataclasses.dataclass overloads May 17, 2025
@max-muoto max-muoto marked this pull request as ready for review May 17, 2025 17:27
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

pydantic (https://github.com/pydantic/pydantic)
+ pydantic/v1/dataclasses.py:214: error: Incompatible types in assignment (expression has type "type[Any]", variable has type "DataclassProxy")  [assignment]
- pydantic/v1/dataclasses.py:214: error: No overload variant of "dataclass" matches argument types "type[Any]", "bool", "bool", "bool", "bool", "bool", "bool", "bool"  [call-overload]
- pydantic/v1/dataclasses.py:214: note: Possible overload variants:
- pydantic/v1/dataclasses.py:214: note:     def dataclass(None, /) -> Callable[[type[_T]], type[_T]]
- pydantic/v1/dataclasses.py:214: note:     def [_T] dataclass(type[_T], /) -> type[_T]
- pydantic/v1/dataclasses.py:214: note:     def dataclass(*, init: bool = ..., repr: bool = ..., eq: bool = ..., order: bool = ..., unsafe_hash: bool = ..., frozen: bool = ..., match_args: bool = ..., kw_only: bool = ..., slots: bool = ..., weakref_slot: bool = ...) -> Callable[[type[_T]], type[_T]]
+ pydantic/dataclasses.py:257: error: Unused "type: ignore" comment  [unused-ignore]

@max-muoto
Copy link
Contributor Author

For pydantic.dataclasses a false posistive is resolved:

cls = dataclasses.dataclass(  # type: ignore[call-overload]
    cls,
    # the value of init here doesn't affect anything except that it makes it easier to generate a signature
    init=True,
    repr=repr,
    eq=eq,
    order=order,
    unsafe_hash=unsafe_hash,
    frozen=frozen_,
    **kwargs,
)

@max-muoto
Copy link
Contributor Author
max-muoto commented May 17, 2025

Diff from mypy_primer, showing the effect of this PR on open source code:

pydantic (https://github.com/pydantic/pydantic)
+ pydantic/v1/dataclasses.py:214: error: Incompatible types in assignment (expression has type "type[Any]", variable has type "DataclassProxy")  [assignment]
- pydantic/v1/dataclasses.py:214: error: No overload variant of "dataclass" matches argument types "type[Any]", "bool", "bool", "bool", "bool", "bool", "bool", "bool"  [call-overload]
- pydantic/v1/dataclasses.py:214: note: Possible overload variants:
- pydantic/v1/dataclasses.py:214: note:     def dataclass(None, /) -> Callable[[type[_T]], type[_T]]
- pydantic/v1/dataclasses.py:214: note:     def [_T] dataclass(type[_T], /) -> type[_T]
- pydantic/v1/dataclasses.py:214: note:     def dataclass(*, init: bool = ..., repr: bool = ..., eq: bool = ..., order: bool = ..., unsafe_hash: bool = ..., frozen: bool = ..., match_args: bool = ..., kw_only: bool = ..., slots: bool = ..., weakref_slot: bool = ...) -> Callable[[type[_T]], type[_T]]
+ pydantic/dataclasses.py:257: error: Unused "type: ignore" comment  [unused-ignore]

In pydantic.v1.dataclasses an error is resolved around missing overload:

if should_use_proxy:
    dc_cls_doc = ''
    dc_cls = DataclassProxy(cls)
    default_validate_on_init = False
else:
    dc_cls_doc = cls.__doc__ or ''  # needs to be done before generating dataclass
    if sys.version_info >= (3, 10):
        dc_cls = dataclasses.dataclass(
            cls,
            init=init,
            repr=repr,
            eq=eq,
            order=order,
            unsafe_hash=unsafe_hash,
            frozen=frozen,
            kw_only=kw_only,
        )
    else:
        dc_cls = dataclasses.dataclass(  # type: ignore
            cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen
        )
    default_validate_on_init = True

The new error is just the result of overriding a variable that's typed differently from type[Any].

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant
0