-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
TypedDict: Recognize __getitem__ and __setitem__ access. #2526
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
Conversation
Hm... I'm not crazy about this approach. It seems to be type-checking the argument expression (e.g. 'x' in d['x']) at the point where it's supposed to just be looking for the |
Is the concern that performing the check in the more-widely-used analyze_member_access() might be too general? I can certainly move the call up to check_op_local(), although I believe the semantics will be equivalent. Moving the check up to check_op_local() may make it more difficult to recognize direct invocations like |
Supporting |
3226d1c
to
9f60720
Compare
I've moved Squished and rebased to the tip of master. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Just some minor comments.
from mypy_extensions import TypedDict | ||
TaggedPoint = TypedDict('TaggedPoint', {'type': str, 'x': int, 'y': int}) | ||
p = TaggedPoint(type='2d', x=42, y=1337) | ||
p['x'] = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also try p['x'] = 'y'
(should be an error) and p['type'] = 'a'
(valid).
def typeddict_item_name_must_be_string_literal(self, | ||
typ: TypedDictType, | ||
context: Context): | ||
self.fail('Cannot prove expression is a valid item name. Expected one of {}.'.format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: we tend not to use periods in error messages. A more consistent message would be Cannot prove expression is a valid item name; expected one of [...]
(no dot at the end).
Maybe also truncate the item name list (probably not useful to display dozens of names, for example).
typ: TypedDictType, | ||
item_name: str, | ||
context: Context): | ||
self.fail('\'{}\' is not a valid item name. Expected one of {}.'.format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to above: a more consistent message would be ... is not a valid item name; expected one of [...]
(not dot at the end).
Also consider truncating the list (e.g. ['x', 'y', 'z', 'a', 'b', ...]
) if it's long enough.
@@ -1421,6 +1423,18 @@ def _get_value(self, index: Expression) -> Optional[int]: | |||
return -1 * operand.value | |||
return None | |||
|
|||
def visit_typeddict_index_expr(self, td_type: TypedDictType, index: Expression): | |||
if not isinstance(index, (StrExpr, UnicodeExpr)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add test case for both 'foo'
and u'foo'
key names in Python 2 mode.
9f60720
to
ca7d072
Compare
Got all the feedback integrated except for one item:
When writing that test case, it crashes mypy when run inside the test runner but not when running mypy normally. Here's the problem: If you run
At the line marked HERE, lookup_qualified is called with 'builtins.dict' which fails, returning a None node. That None node crashes the line marked THERE with a null pointer exception. How is it that |
You probably need to add something (e.g. a dummy definition for dict) to
the fixture used by that test, or change the fixture it is using. See how
other tests use `[builtins <file>]`. Yes, it's annoying, but it saves a lot
of time running tests.
|
Here is the test in question:
The preceding behavior suggests that the I will keep investigating... |
Ha! Apparently I need to say |
ca7d072
to
7b12582
Compare
@JukkaL , I've integrated all the requested feedback. Ready for another look. |
Looks good now! Thanks for the updates! |
Partially resolves #2486 . If the approach here looks good I can extend the diff to recognize
__setitem__
as well, which would fully resolve #2486 .