Repository: psf/black
File: src/black/parsing.py (Python)

Code before:
        if sys.version_info >= (3, 8):
            return ast3.parse(src, filename, type_comments=type_comments)
        else:
            return ast3.parse(src, filename)
    else:
        if type_comments:
            # Typed-ast is guaranteed to be used here and automatically tracks type
            # comments separately.
            return ast3.parse(src, filename, feature_version=version[1])
        else:
            return ast.parse(src, filename)


def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
    # TODO: support Python 4+ ;)
    versions = [(3, minor) for minor in range(3, sys.version_info[1] + 1)]

    first_error = ""
    for version in sorted(versions, reverse=True):
        try:
            return parse_single_version(src, version, type_comments=True)
        except SyntaxError as e:
            if not first_error:
                first_error = str(e)

            # Try to parse without type comments
            try:
                return parse_single_version(src, version, type_comments=False)
            except SyntaxError:
                pass

    raise SyntaxError(first_error)


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


def _normalize(lineend: str, value: str) -> str:
    # To normalize, we strip any leading and trailing space from
    # each line...
    stripped: List[str] = [i.strip() for i in value.splitlines()]
    normalized = lineend.join(stripped)
    # ...and remove any blank lines at the beginning and end of
    # the whole string
    return normalized.strip()


def stringify_ast(node: Union[ast.AST, ast3.AST], depth: int = 0) -> Iterator[str]:
    """Simple visitor generating strings to compare ASTs by content."""

    node = fixup_ast_constants(node)

Review comment (performance):
Need to think more about whether we should have a separate loop instead. I *think* that should never affect behavior, just performance.

Code after:
        if sys.version_info >= (3, 8):
            return ast3.parse(src, filename, type_comments=type_comments)
        else:
            return ast3.parse(src, filename)
    else:
        if type_comments:
            # Typed-ast is guaranteed to be used here and automatically tracks type
            # comments separately.
            return ast3.parse(src, filename, feature_version=version[1])
        else:
            return ast.parse(src, filename)


def parse_ast(src: str) -> Union[ast.AST, ast3.AST]:
    # TODO: support Python 4+ ;)
    versions = [(3, minor) for minor in range(3, sys.version_info[1] + 1)]

    first_error = ""
    for version in sorted(versions, reverse=True):
        try:
            return parse_single_version(src, version, type_comments=True)
        except SyntaxError as e:
            if not first_error:
                first_error = str(e)

    # Try to parse without type comments
    for version in sorted(versions, reverse=True):
        try:
            return parse_single_version(src, version, type_comments=False)
        except SyntaxError:
            pass

    raise SyntaxError(first_error)


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


def _normalize(lineend: str, value: str) -> str:
    # To normalize, we strip any leading and trailing space from
    # each line...
    stripped: List[str] = [i.strip() for i in value.splitlines()]
    normalized = lineend.join(stripped)
    # ...and remove any blank lines at the beginning and end of
    # the whole string
    return normalized.strip()


def stringify_ast(node: Union[ast.AST, ast3.AST], depth: int = 0) -> Iterator[str]:
    """Simple visitor generating strings to compare ASTs by content."""