8000 Allow assignments to multiple targets from union types by ilevkivskyi · Pull Request #4067 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Allow assignments to multiple targets from union types #4067

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

Merged
merged 11 commits into from
Oct 11, 2017
Prev Previous commit
Don't infer partial types inside unions
  • Loading branch information
Ivan Levkivskyi committed Oct 11, 2017
commit 950b8f11fa11abe6bdee468b9b848d3d5854e8da
6 changes: 5 additions & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ class TypeChecker(NodeVisitor[None], CheckerPluginInterface):
# Used for collecting inferred attribute types so that they can be checked
# for consistency.
inferred_attribute_types = None # type: Optional[Dict[Var, Type]]
# Don't infer partial None types if we are processing assignment from Union
no_partial_types = False # type: bool

# The set of all dependencies (suppressed or not) that this module accesses, either
# directly or indirectly.
Expand Down Expand Up @@ -1651,6 +1653,7 @@ def check_multi_assignment_from_union(self, lvalues: List[Expression], rvalue: E
inferred types for first assignments, 'assignments' contains the narrowed types
for binder.
"""
self.no_partial_types = True
transposed = tuple([] for _ in
self.flatten_lvalues(lvalues)) # type: Tuple[List[Type], ...]
# Notify binder that we want to defer bindings and instead collect types.
Expand Down Expand Up @@ -1680,6 +1683,7 @@ def check_multi_assignment_from_union(self, lvalues: List[Expression], rvalue: E
self.set_inferred_type(inferred, lv, union)
else:
self.store_type(lv, union)
self.no_partial_types = False

def flatten_lvalues(self, lvalues: List[Expression]) -> List[Expression]:
res = [] # type: List[Expression]
Expand Down Expand Up @@ -1864,7 +1868,7 @@ def infer_variable_type(self, name: Var, lvalue: Lvalue,
"""Infer the type of initialized variables from initializer type."""
if isinstance(init_type, DeletedType):
self.msg.deleted_as_rvalue(init_type, context)
elif not is_valid_inferred_type(init_type):
elif not is_valid_inferred_type(init_type) and not self.no_partial_types:
# We cannot use the type of the initialization expression for full type
# inference (it's not specific enough), but we might be able to give
# partial type which will be made more specific later. A partial type
Expand Down
61 changes: 61 additions & 0 deletions test-data/unit/check-unions.test
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,67 @@ reveal_type(z) # E: Revealed type is 'Union[builtins.int, __main__.A, builtins.s
[builtins fixtures/tuple.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNone]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))

for y in x: pass # E: Iterable expected \
# E: Item "None" of "Optional[List[Tuple[str, str]]]" has no attribute "__iter__"
if x:
for s, t in x:
reveal_type(s) # E: Revealed type is 'builtins.str'
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNone2]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
x = None
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))

for y in x: pass # E: Iterable expected \
# E: Item "None" of "Optional[List[Tuple[str, str]]]" has no attribute "__iter__"
if x:
for s, t in x:
reveal_type(s) # E: Revealed type is 'builtins.str'
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNoneBinder]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

x: object
a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, (None, None))
# FIXME: fix narrow_declared_type for narrowed Optional types.
reveal_type(x) # E: Revealed type is 'builtins.list[Tuple[builtins.str, builtins.str]]'

for y in x: pass
[builtins fixtures/dict.pyi]
[out]

[case testUnpackUnionNoCrashOnPartialNoneList]
# flags: --strict-optional
from typing import Dict, Tuple, List, Any

a: Any
d: Dict[str, Tuple[List[Tuple[str, str]], str]]
x, _ = d.get(a, ([], []))
reveal_type(x) # E: Revealed type is 'Union[builtins.list[Tuple[builtins.str, builtins.str]], builtins.list[<nothing>]]'

for y in x: pass
[builtins fixtures/dict.pyi]
[out]

[case testLongUnionFormatting]
from typing import Any, Generic, TypeVar, Union

Expand Down
0