typing icon indicating copy to clipboard operation
typing copied to clipboard

Feature request: Allow unpacking of type variable bound to typed dict

Open NeilGirdhar opened this issue 2 years ago • 6 comments

I'd like to have a family of classes where overrides have additional parameters to various methods:

from typing import Generic, Unpack

from typing_extensions import TypedDict, TypeVar, override


class EmptyDict(TypedDict, total=True):
    pass


Extra = TypeVar('Extra', bound=TypedDict, default=EmptyDict)


class C(Generic[Extra]):
    def f(self, **kwargs: Unpack[Extra]) -> None:  # error: Expected TypedDict type argument for Unpack (reportGeneralTypeIssues)
        pass


class D(C):
    @override
    def f(self) -> None:  # error: Method "f" overrides class "C" in an incompatible manner
        pass


class HasName(TypedDict, total=True):
    name: str


class E(C[HasName]):
    @override
    def f(self, name: str) -> None:  # This doesn't work.
        print(name)



D().f()
E().f("a")

See @erictraut's instructive comment on the issue here.

NeilGirdhar avatar May 03 '23 22:05 NeilGirdhar

This would be kwargs equivalent of being able to unpack TypeVarTuple. This would I think solve this request to be able to use Paramspec kwargs only.

I have a couple small use cases where this would be nice although they mostly follow other issue of more flexibility with preserving just args/kwargs/similar manipulation.

hmc-cs-mdrissi avatar May 03 '23 22:05 hmc-cs-mdrissi

I believe I hit this issue when I was trying to write a type stub for networkx (or nx).

nx.Graph and its variants allow arbitrary attributes to be associated with nodes, edges, and graphs. For example, adding a node has signature (ref):

class Graph:
    def add_node(self, node_for_adding, **attr): ...

I was trying to do this:

N = TypeVar("N")  # type for node ID
A = TypeVar("A", bound=TypedDict)  # type for node attribute

class Graph(Generic[N, A]):
    def add_node(self, node_for_adding: N, **attr: Unpack[A]) -> None: ...

jaywonchung avatar Sep 08 '23 20:09 jaywonchung

Yup, perfect example.

NeilGirdhar avatar Sep 09 '23 03:09 NeilGirdhar

Is there something I could help with to speed this up? Probably only possible way to halp is to draft a PEP?

Anyway, it would be really useful for a framework I'm building - https://github.com/paveldedik/ludic/blob/main/ludic/base.py#L293-L308

It seems I can already bound a subclass of a TypedDict in TypeVar and it works in mypy at least:

from typing import TypedDict, TypeVar

class Attrs(TypedDict):
    key: str

T = TypeVar("T", bound=Attrs)  # does not complain

This seems to work in mypy but I'm afraid there is not PEP for it.

paveldedik avatar May 06 '24 08:05 paveldedik