-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
TypedDict does not support type refinement in subclasses #7435
Comments
I don't think there is any fundamental reason to prohibit this, it is just simplicity of implementation and maintenance. I think if people will ask for this, then we can reconsider. Making as low priority for now. |
Just a post to get information about any advancement on this ? Thanks for the efforts, typing in python helps a lot ! |
+1! I am working around this by using a normal class with attributes instead of a mapping, but I have to constantly hush the linter about "too many attributes". |
Allowing type refinement of a mutable dict key is dangerous from a type perspective and should probably remain an error. Consider the following: def mutate_superdict(b: SuperDict):
b["type"] = "error"
def func(b: Bar):
b["type"] = "bar"
mutate_superdict(b)
# The revealed type doesn't match reality!
reveal_type(b["type"]) # Literal["bar"]
print(b["type"]) # "error"
func({"type": "bar"}) It's the same reason why you cannot assign a Incidentally, pyright is consistent with mypy here and does not allow type refinements for TypedDict keys. As for generating errors about "too many attributes", I'm failing to understand why that limitation is required. PEP 589 is mostly silent on that topic, with the exception of this statement about constructors:
And even here, I'm not sure why this limitation is required for type safety. |
Oh no. Its a quirk of my workaround, not anything related to mypy. What you said makes sense to me, though. Im happy to take back the +1 |
@erictraut – thanks for this comment, very insightful! Following on, doesn't this argument apply to subclassing any mutable type? E.g. the plain class Super:
def __init__(self, type: str) -> None:
self.type: str = type
class Foo(Super):
def __init__(self, type: Literal["foo"]) -> None:
self.type: Literal["foo"] = type # hinting this as e.g. `int` would cause a type error (at least does in Pyright)
f = Foo(type="foo")
def mutate_super(s: Super) -> None:
s.type = "error"
def func(f: Foo) -> None:
f.type = "foo"
mutate_super(f)
# The revealed type doesn't match reality!
reveal_type(f.type) # Literal["bar"]
print(f.type) # "error"
func(Foo(type="foo")) Is there something special about Or is it simply that it's a newer addition to Python and its inheritance is being analysed more carefully than of the rest of the language? |
@kkom, you make a good point. This can be unsafe with regular subclassing as well. I think there are two reasons for the apparent inconsistency. The first, as you point out, is that |
I mostly get what's being said here, but I believe changing a TypedDict's shape based on a discriminant field is a good idea? It should probably (at least) be allowed when the superclass has a discriminant field which is a union of literals, then the union can be narrowed to a single literal for each type and extra fields can be added? It's a fairly common idiom in other (typed) languages, and is often a thing in untyped Python as well. |
Could type refinement potentially be implemented for keys marked with ReadOnly, since the type checker will enforce that these keys are not modified?
|
Are you reporting a bug, or opening a feature request?
Feature Request
Please insert below the code you are checking with mypy.
What is the actual behavior/output?
Even though
Literal['bar']
is compatible with typestr
, as shown in the other two examples, the following error is returned.What is the behavior/output you expect?
PEP 589 states the following:
The current behavior of TypedDict is in-line with the specification, but that restriction prevents type refinement for subtypes, a restriction that is not shared by regular classes or NamedTuple subclasses. PEP 589 does not appear to mention why that additional restriction is given to typed dicts specifically, and this restricts how well TypedDict is able to express certain structures.
Could this limitation be lifted or is there a specific reason for it to apply?
The text was updated successfully, but these errors were encountered: