typing
typing copied to clipboard
Inferring keyword arguments from attributes
I'm making an alternative python AST. Just like the ast
module, I want attributes to be set on a node using keyword arguments.
The only problem with using
class Node:
attr: int
def __init__(self, **kwargs: object):
for name, value in kwargs.items(): # alternative: self.__dict__.update(kwargs)
setattr(self, name, value)
is that mypy
doesn't catch it when I supply invalid types for the attributes, e.g. Node(attr='invalid')
, or when assigning to a non-existing attribute, e.g. Node(nonexistant=1)
.
The ast
module has this problem too:
from ast import For
For(name=1) # no error
For(body=1) # no error
For().name = 1 # [attr-defined]
For().body = 1 # [assignment]
One approach to solving this would be to add a class decorator to typing
(or mypy_extensions
, I don't know what the best place is) that implements that __init__
method, and lets type checkers know that it accepts the same keyword arguments as its attributes. This would also help with type-checking code that's using the ast.AST
constructor.
The dataclass_transform
mechanism described in PEP 681 is probably what you're looking for here.
Or perhaps dataclass
with kw_only
would meet your needs.
PEP 692 may also be useful to you
Hello @erictraut,
dataclass_transform
seems to be what I'm looking for, but it doesn't seem to work?
from typing_extensions import dataclass_transform
@dataclass_transform(eq_default=False, kw_only_default=True)
class AttrKwargs:
def __init__(self, **kwargs: object):
for name, value in kwargs.items():
setattr(self, name, value)
class N1(AttrKwargs):
a: str
class N2(N1):
b: int
N1(a=1) # no error
N1(b=1) # no error
N2(a=1) # no error
N2(b=1) # no error
Using a decorator instead of a superclass also doesn't work... Can you give an example of how to use it in my situation? I would ideally not change N2
at all.
Mypy doesn't support dataclass_transform yet.
Mypy doesn't support dataclass_transform yet.
Ah, that explains it. Maybe there should be a warning when using it, instead of just ignoring it?
dataclass
requires adding the decorator to each class, and there doesn't seem to be an option to leave attributes empty if they are not given.
I'm assuming that dataclass_transform
essentially does the same as dataclass
here, just not functional, so that also won't really work if that's the case...
Is there some other way to do this?
Now that mypy supports dataclass_transform
, I think this can be closed.