Skip to content

Commit bd6af1c

Browse files
authored
Fix missing builtin aliases on Python 2 (and other versions) (#6441)
Some builtin aliases (like `typing.ChainMap`) are not available on some Python versions, or in some fixtures. However, if while they were first looked up while target namespace was incomplete, we put a `PlaceholderNode` in `typing`. This PR either doesn't put or removes this placeholder node if we didn't find the target after the target namespace is complete. I didn't find a way to test this (since we don't have incremental `pythoneval` tests), but I double-checked this fixes the crash with actual Python 2 stubs.
1 parent ee1df17 commit bd6af1c

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

mypy/newsemanal/semanal.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
IntExpr, FloatExpr, UnicodeExpr, TempNode, OverloadPart,
7272
PlaceholderNode, COVARIANT, CONTRAVARIANT, INVARIANT,
7373
nongen_builtins, get_member_expr_fullname, REVEAL_TYPE,
74-
REVEAL_LOCALS, is_final_node, TypedDictExpr
74+
REVEAL_LOCALS, is_final_node, TypedDictExpr, type_aliases_target_versions
7575
)
7676
from mypy.tvar_scope import TypeVarScope
7777
from mypy.typevars import fill_typevars
@@ -3840,6 +3840,9 @@ def add_builtin_aliases(self, tree: MypyFile) -> None:
38403840
"""
38413841
assert tree.fullname() == 'typing'
38423842
for alias, target_name in type_aliases.items():
3843+
if type_aliases_target_versions[alias] > self.options.python_version:
3844+
# This alias is not available on this Python version.
3845+
continue
38433846
name = alias.split('.')[-1]
38443847
if name in tree.names and not isinstance(tree.names[name].node, PlaceholderNode):
38453848
continue
@@ -3863,7 +3866,10 @@ def add_builtin_aliases(self, tree: MypyFile) -> None:
38633866
self.mark_incomplete(name, tree)
38643867
else:
38653868
# Test fixtures may be missing some builtin classes, which is okay.
3866-
pass
3869+
# Kill the placeholder if there is one.
3870+
if name in tree.names:
3871+
assert isinstance(tree.names[name].node, PlaceholderNode)
3872+
del tree.names[name]
38673873

38683874
def lookup_fully_qualified(self, name: str) -> SymbolTableNode:
38693875
"""Lookup a fully qualified name.

mypy/nodes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ def get_column(self) -> int:
111111
'typing.Deque': 'collections.deque',
112112
} # type: Final
113113

114+
# This keeps track of the oldest supported Python version where the corresponding
115+
# alias _target_ is available.
116+
type_aliases_target_versions = {
117+
'typing.List': (2, 7),
118+
'typing.Dict': (2, 7),
119+
'typing.Set': (2, 7),
120+
'typing.FrozenSet': (2, 7),
121+
'typing.ChainMap': (3, 3),
122+
'typing.Counter': (2, 7),
123+
'typing.DefaultDict': (2, 7),
124+
'typing.Deque': (2, 7),
125+
} # type: Final
126+
114127
reverse_builtin_aliases = {
115128
'builtins.list': 'typing.List',
116129
'builtins.dict': 'typing.Dict',

0 commit comments

Comments
 (0)