Repository navigation
Add support for additional TypedDict methods - #6011
Conversation
Update related tests.
Follow-up to #6011 (this must be merged after it).
ilevkivskyi
left a comment
There was a problem hiding this comment.
Looks great! I have a bunch of small comments.
| if (isinstance(ctx.type, TypedDictType) | ||
| and len(ctx.arg_types) >= 1 | ||
| and len(ctx.arg_types[0]) == 1): | ||
| if isinstance(ctx.args[0][0], StrExpr): |
There was a problem hiding this comment.
At some point we should also start using "constant folding", not in this PR however.
| arg_type = arg_type.as_anonymous() | ||
| arg_type = arg_type.copy_modified(required_keys=set()) | ||
| return signature.copy_modified(arg_types=[arg_type]) | ||
| return signature |
There was a problem hiding this comment.
Maybe add a TODO somewhere for .update(x=1, y=2)? Or is this tracked in an issue?
| fallback = (self.api.named_type_or_none('typing.Mapping', | ||
| [self.api.named_type('__builtins__.str'), | ||
| self.api.named_type('__builtins__.object')]) | ||
| fallback = (self.api.named_type_or_none('mypy_extensions._TypedDict', []) |
There was a problem hiding this comment.
I would fail soon here if we can't find mypy_extensions._TypedDict. There is some logic than may cause a crash/fail that will be harder to debug.
| at runtime. | ||
|
|
||
| If a TypedDict is named, its fallback will be an Instance of the named type | ||
| (ex: "Point") whose TypeInfo has a typeddict_type that is anonymous. |
There was a problem hiding this comment.
Maybe mention this is similar to how named tuples work and/or add some motivation for such complex structure?
| #!/usr/bin/env python3 | ||
| from os import system | ||
| from sys import argv, exit, platform, executable, version_info | ||
| from sys import argv, exit, platform, executable, version_info, stdout |
|
|
||
| reveal_type(a.copy()) # E: Revealed type is 'TypedDict('__main__.A', {'x': builtins.int, 'y': builtins.list[builtins.int]})' | ||
| a.has_key() # E: "A" has no attribute "has_key" | ||
| a.clear() # E: "A" has no attribute "clear" |
There was a problem hiding this comment.
Another possible TODO is to give a better error message here.
| A = TypedDict('A', {'x': int}) | ||
| a = A(x=1) | ||
| reveal_type(a.copy()) # E: Revealed type is 'TypedDict('__main__.A', {'x': builtins.int})' | ||
| reveal_type(a.has_key()) # E: Revealed type is 'builtins.bool' |
There was a problem hiding this comment.
Argument is missing here.
Also we can probably infer Literal[True/False] here and for 's' in SomeTypedDict @Michael0x2a you might want to add this to your "wishlist" for literal types.
There was a problem hiding this comment.
This wouldn't be safe due to structural subtyping and casts. Users may use a total TypedDict type when some keys are actually missing, and we don't want to break such code even though it's questionable.
|
|
||
| reveal_type(a.pop('x')) # E: Revealed type is 'builtins.int' | ||
| reveal_type(a.pop('y', [])) # E: Revealed type is 'builtins.list[builtins.int]' | ||
| reveal_type(a.pop('x', '')) # E: Revealed type is 'Union[builtins.int, builtins.str]' |
There was a problem hiding this comment.
Maybe add a line here for non-Instance default value (maybe TupleType) just in case?
This adds support for these methods through additional plugin hooks:
popsetdefaultupdate(positional argument only)__delitem__These methods also work and don't need plugin support:
copyhas_key(Python 2 only)viewitems(Python 2 only)viewkeys(Python 2 only)viewvalues(Python 2 only)The base signatures for all of these methods are defined in
mypy_extensions._TypedDict, which is a stub-only classonly used internally by mypy. It becomes the new fallback
type of all TypedDicts.
Fixes #3843. Fixes #3550.
There's some possible follow-up work that I'm leaving to other PRs,
such as optimizing hook lookup through dictionaries in the default
plugin and documenting the supported methods.