Skip to content

Commit 125728a

Browse files
authored
Fix parser when using Python 3.9 (#8716)
The structure of the AST for subscripts was changed in python/cpython#9605. This also fixes some systemic issues with the tests under Python 3.9, but not all. Fixes #8627
1 parent f8051b1 commit 125728a

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

mypy/fastparse.py

+21-8
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import ast as ast3
5050
assert 'kind' in ast3.Constant._fields, \
5151
"This 3.8.0 alpha (%s) is too old; 3.8.0a3 required" % sys.version.split()[0]
52+
# TODO: Num, Str, Bytes, NameConstant, Ellipsis are deprecated in 3.8.
53+
# TODO: Index, ExtSlice are deprecated in 3.9.
5254
from ast import (
5355
AST,
5456
Call,
@@ -1503,19 +1505,30 @@ def visit_Bytes(self, n: Bytes) -> Type:
15031505
contents = bytes_to_human_readable_repr(n.s)
15041506
return RawExpressionType(contents, 'builtins.bytes', self.line, column=n.col_offset)
15051507

1506-
# Subscript(expr value, slice slice, expr_context ctx)
1508+
# Subscript(expr value, slice slice, expr_context ctx) # Python 3.8 and before
1509+
# Subscript(expr value, expr slice, expr_context ctx) # Python 3.9 and later
15071510
def visit_Subscript(self, n: ast3.Subscript) -> Type:
1508-
if not isinstance(n.slice, Index):
1509-
self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1))
1510-
return AnyType(TypeOfAny.from_error)
1511+
if sys.version_info >= (3, 9): # Really 3.9a5 or later
1512+
sliceval = n.slice # type: Any
1513+
if (isinstance(sliceval, ast3.Slice) or
1514+
(isinstance(sliceval, ast3.Tuple) and
1515+
any(isinstance(x, ast3.Slice) for x in sliceval.elts))):
1516+
self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1))
1517+
return AnyType(TypeOfAny.from_error)
1518+
else:
1519+
# Python 3.8 or earlier use a different AST structure for subscripts
1520+
if not isinstance(n.slice, Index):
1521+
self.fail(TYPE_COMMENT_SYNTAX_ERROR, self.line, getattr(n, 'col_offset', -1))
1522+
return AnyType(TypeOfAny.from_error)
1523+
sliceval = n.slice.value
15111524

15121525
empty_tuple_index = False
1513-
if isinstance(n.slice.value, ast3.Tuple):
1514-
params = self.translate_expr_list(n.slice.value.elts)
1515-
if len(n.slice.value.elts) == 0:
1526+
if isinstance(sliceval, ast3.Tuple):
1527+
params = self.translate_expr_list(sliceval.elts)
1528+
if len(sliceval.elts) == 0:
15161529
empty_tuple_index = True
15171530
else:
1518-
params = [self.visit(n.slice.value)]
1531+
params = [self.visit(sliceval)]
15191532

15201533
value = self.visit(n.value)
15211534
if isinstance(value, UnboundType) and not value.args:

mypy/test/helpers.py

+4
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,8 @@ def clean_up(a: List[str]) -> List[str]:
233233
remove trailing carriage returns.
234234
"""
235235
res = []
236+
pwd = os.getcwd()
237+
driver = pwd + '/driver.py'
236238
for s in a:
237239
prefix = os.sep
238240
ss = s
@@ -241,6 +243,8 @@ def clean_up(a: List[str]) -> List[str]:
241243
ss = ss.replace(p, '')
242244
# Ignore spaces at end of line.
243245
ss = re.sub(' +$', '', ss)
246+
# Remove pwd from driver.py's path
247+
ss = ss.replace(driver, 'driver.py')
244248
res.append(re.sub('\\r$', '', ss))
245249
return res
246250

mypyc/test-data/run.test

+4-1
Original file line numberDiff line numberDiff line change
@@ -4352,7 +4352,10 @@ import sys
43524352

43534353
# We lie about the version we are running in tests if it is 3.5, so
43544354
# that hits a crash case.
4355-
if sys.version_info[:2] == (3, 8):
4355+
if sys.version_info[:2] == (3, 9):
4356+
def version() -> int:
4357+
return 9
4358+
elif sys.version_info[:2] == (3, 8):
43564359
def version() -> int:
43574360
return 8
43584361
elif sys.version_info[:2] == (3, 7):

0 commit comments

Comments
 (0)