-
Notifications
You must be signed in to change notification settings - Fork 2
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
with OrderedIntersection
#42
Comments
Is that actually useful though? A Maybe there’s a situation I’m not thinking of where it’s not clear to the checker that the protocol is satisfied? Or if you want to override what the dict’s behaviour is for the checker, but that’s rather type unsafe. |
Yeah I'm inclined to agree that maybe it's not that helpful a subcase, and probably not worth making more effort for people - I just wanted to point out that theoretically there exists a scenario with a valid interpretation. Personally, I think it works best to just say |
I'm inclined to think that there's valuable behavior we're excluding here, but there's some things I need to flesh out more and bring into this other discussion: https://discuss.python.org/t/treat-typeddict-as-structured-types-w-r-t-subclassing/43582/9 The TLDR here is that TypedDicts are a structural type similar to protocols. Anything from an ORM to a API wrapper dealing with json web apis might have a reason to return objects that behave like a typed dict with a specific schema most of the time, but have additional methods on them. I'll circle back to this once I've examined the implications of it more, if there's an inconsistency that ends up inappropriate without more machinery, we can decide to keep it that limited, this might be a situation where TypedDict needs to change or have additional things added to be usable for such cases, or it might just work out of the box. |
Are (edit:) instances of subclasses of |
No. Thanks for pointing that out! I'm going to go ahead and note down why only intersections with typeddicts are allowed, but that it isn't a limitation of intersections while retaining a note that it would be possible to change typeddict in the future to allow more Not our problem, as the definition we're working towards requires consistency with all operands at assignment, so the limitations of typeddict will prevent other cases for now. |
I like this plan. 👍 In my mind, I would expect the following to be true:
(I have put zero thought into whether applies when types If non-pure-dicts are never allowed to to be assigned to If the above policy on assignability to |
I really oppose the idea of limiting Intersection with TypedDicts only with TypedDicts. This really would decrease the value of For instance just today we had to case that some general settings are provided as TypedDict (to allow defining the values) but it should be ReadOnly for all attributes. In reality the object itself would be a MappingProxy which would lead to runtime failures anyway. Another use case is Maybe some of you will argue, that these classes provide |
@CarliJoy I have found zero type system features that need explicit banning from the definition we're working towards for intersections at this time, and largely agree with you. The ORM case I was considering is quite akin to pandas dataframes. I do think this will require changes to the spec of TypedDict to be properly supported. type checkers currently do not synthesize |
@CarliJoy This is interesting! Isn't this:
...in violation with LSP? @mikeshardmind editing note: I've modified some part of this post as there were some points I hadn't thought of - see the one below. |
@CarliJoy I think this part of your argument is very persuasive for me, so I'll address that here - in this situation really class Test:
def foo(self) -> int:
return 1
def __getitem__(self, key: str):
if key == 'one':
return "test"
elif key == "two":
return 2
elif key == "three":
return None
else:
raise KeyError Now as things are currently there's no way to get type hints to differentiate between keys, while also allowing the method from types import NoneType
from typing import TypedDict, OrderedIntersection, cast
class Test:
def foo(self) -> int:
return 1
def __getitem__(self, key: str):
if key == 'one':
return "test"
elif key == "two":
return 2
elif key == "three":
return None
else:
raise KeyError
class TestD(TypedDict):
one: str
two: int
three: NoneType
x = cast(OrderedIntersection[Test, TestD], Test()) So far so good. Although, I guess this still feels like a bit of a workaround - really the problem here is not that the result is an intersection between the from types import NoneType
from typing import TypedDict, Unpack
class TestD(TypedDict):
one: str
two: int
three: NoneType
class Test:
def foo(self) -> int:
return 1
def __getitem__(self, key: str) -> Unpack[TestD]:
if key == 'one':
return "test"
elif key == "two":
return 2
elif key == "three":
return None
else:
raise KeyError
x = Test() My point is that I guess that it feels like we're patching a different issue with an intersection, but also I do appreciate this is an issue you want a solution for. It seems to me it's just that the return type of Edit: I've also just remembered that the syntax for Unpack already combines with TypedDict in the context of kwargs - maybe this would be actually quite a small PEP to suggest the syntax above. |
There are open questions about that still. and the actual allowed behavior of Never currently still varies between type checkers. I don't know that we need to solve this right this moment now that we're using an ordered construct, and it won't help replace PEP 705 read only for other reasons (I believe that the closest to consensus there was was that Never may or may not be consistent with other annotations, and is not with any types or values, being another thing that benefits from better terminology) @CarliJoy |
Yeah I agree, if this is currently an unresolved discussion anyway we should try and steer clear of it. |
Following on from from a discussion with @mikeshardmind in #41 I thought it might be worth separating this into a new thread.
This concerns how
TypedDict
might be combined with other classes in the new intersection - I'll start with the non-controversial case:So far so good. Now let's consider what happens if we mix it with another class or Protocol
Now here we reach an issue, there's no way to make this class. A
TypedDict
traditionally cannot be combined with another class - and with good reason! We cannot introduce other methods to aTypedDict
. But this led me to another case:Here the use of
__str__
in theX
protocol does not impinge on the definition ofTest
, as this matches the function signature of a method already found onTypedDict
(dict). So this intersection should be allowed.My conclusion from this is
TypedDict
can only be combined with otherTypedDict
, orProtocol
's that do not expand on the existing methods of dict.The text was updated successfully, but these errors were encountered: