Skip to content

Commit

Permalink
Fix mypyc KeyError on src/black/parsing.py
Browse files Browse the repository at this point in the history
Typing the ast3 / ast27 variables as Any breaks mypyc. More details in
the comment added in this commit.

Many thanks goes to Jelle for helping out, with their insight I was
able to find a workaround.
  • Loading branch information
ichard26 committed Jun 30, 2021
1 parent 6e9e0fb commit acb77f7
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 2 deletions.
3 changes: 3 additions & 0 deletions pyproject.toml
Expand Up @@ -32,3 +32,6 @@ optional-tests = [
"no_python2: run when `python2` extra NOT installed",
"no_blackd: run when `d` extra NOT installed",
]
markers = [
"incompatible_with_mypyc: run when testing mypyc compiled black"
]
19 changes: 17 additions & 2 deletions src/black/parsing.py
Expand Up @@ -5,6 +5,11 @@
import sys
from typing import Any, Iterable, Iterator, List, Set, Tuple, Type, Union

if sys.version_info < (3, 8):
from typing_extensions import Final
else:
from typing import Final

# lib2to3 fork
from blib2to3.pytree import Node, Leaf
from blib2to3 import pygram, pytree
Expand Down Expand Up @@ -134,6 +139,10 @@ def parse_ast(src: str) -> Union[ast.AST, ast3.AST, ast27.AST]:
return ast27.parse(src)


ast3_AST: Final[Type] = ast3.AST
ast27_AST: Final[Type] = ast27.AST


def stringify_ast(
node: Union[ast.AST, ast3.AST, ast27.AST], depth: int = 0
) -> Iterator[str]:
Expand Down Expand Up @@ -173,7 +182,13 @@ def stringify_ast(
elif isinstance(item, (ast.AST, ast3.AST, ast27.AST)):
yield from stringify_ast(item, depth + 2)

elif isinstance(value, (ast.AST, ast3.AST, ast27.AST)):
# Note that we are referencing the typed-ast ASTs via global variables and not
# direct module attribute accesses because that breaks mypyc. It's probably
# something to do with the ast3 / ast27 variables being marked as Any leading
# mypy to think this branch is always taken, leaving the rest of the code
# unanalyzed. Tighting up the types for the typed-ast AST types avoids the
# mypyc crash.
elif isinstance(value, (ast.AST, ast3_AST, ast27_AST)):
yield from stringify_ast(value, depth + 2)

else:
Expand All @@ -192,7 +207,7 @@ def stringify_ast(
# To normalize, we strip any leading and trailing space from
# each line...
stripped = [line.strip() for line in value.splitlines()]
normalized = lineend.join(stripped)
normalized = lineend.join(stripped) # type: ignore[attr-defined]
# ...and remove any blank lines at the beginning and end of
# the whole string
normalized = normalized.strip()
Expand Down

0 comments on commit acb77f7

Please sign in to comment.