Skip to content

dataclasses's asdict() and astuple() factories should work with TypedDict and NamedTuple #8580

Closed as not planned
@tony

Description

@tony

Originally posted here

Let me know if I need to scope this better. Even if this gets closed, it's also fine - if you have a better scope / new information it may be worth making a new, improved issue.

I want to downstream users to export a typed tuple and dict from my Details dataclass, dataclasses.astuple and dataclasses.asdict

#!/usr/bin/env python
import dataclasses
from typing import NamedTuple, TypedDict, get_type_hints


class DetailsDict(TypedDict):
    name: str
    age: int
    address: str


class DetailsTuple(NamedTuple):
    name: str
    age: int
    address: str


@dataclasses.dataclass
class Details:
    name: str
    age: int
    address: str

    def to_dict(self) -> DetailsDict:
        # return dataclasses.asdict(self, dict_factory=DetailsDict)
        return DetailsDict(**dataclasses.asdict(self))

    def to_tuple(self) -> DetailsTuple:
        # return dataclasses.astuple(self, tuple_factory=DetailsTuple)
        return DetailsTuple(*dataclasses.astuple(self))


john = Details(name="John", age=25, address="123 Address St")
print(john)
print(john.to_dict())
print(john.to_tuple())
print(get_type_hints(john))
print(get_type_hints(john.to_dict))
print(get_type_hints(john.to_tuple))

Output:

Details(name='John', age=25, address='123 Address St')
{'name': 'John', 'age': 25, 'address': '123 Address St'}
DetailsTuple(name='John', age=25, address='123 Address St')
{'name': <class 'str'>, 'age': <class 'int'>, 'address': <class 'str'>}
{'return': <class '__main__.DetailsDict'>}
{'return': <class '__main__.DetailsTuple'>

Why would a user want to reuse dict/tuple/etc?

  • To maintain mypy strict = True compliance

    • inside of unit testing / assertions. In my case, I have typed pytest fixtures
  • They have an open source library and want tuples / dicts to be available for downstream use.

    In practice, I wanted my dataclasses in libvcs (here) to be able to let the enduser get typed dict/tuple's

    • Spreading into functions *params, **params, e.g. loading data

    • Reuse in args/kwargs of function declarations, e.g.

      Details(*DetailsTuple(name='John', age=25, address='123 Address St'))
      Details(**DetailsDict(**{'name': 'John', 'age': 25, 'address': '123 Address St'}))

Problem

  • Using typed factories (TypedDict, NamedTuple) with the same shape / types as a dataclass don't work

Related

#8518,
python/mypy#4128

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions