Skip to content

Commit

Permalink
Fix edge cases in test failures involving padding and TypeVar (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmojaki authored Oct 6, 2024
1 parent 71ea82b commit 0224610
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
19 changes: 19 additions & 0 deletions asttokens/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from ast import Module, expr, AST
from typing import Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast, Any, TYPE_CHECKING

import astroid
from six import iteritems


Expand Down Expand Up @@ -198,6 +199,24 @@ def is_joined_str(node):
return node.__class__.__name__ == 'JoinedStr'


def is_expr_stmt(node):
# type: (AstNode) -> bool
"""Returns whether node is an `Expr` node, which is a statement that is an expression."""
return node.__class__.__name__ == 'Expr'


def is_constant(node):
# type: (AstNode) -> bool
"""Returns whether node is a Constant node."""
return isinstance(node, (ast.Constant, astroid.Const))


def is_ellipsis(node):
# type: (AstNode) -> bool
"""Returns whether node is an Ellipsis node."""
return is_constant(node) and node.value is Ellipsis # type: ignore


def is_starred(node):
# type: (AstNode) -> bool
"""Returns whether node is a starred expression node."""
Expand Down
42 changes: 34 additions & 8 deletions tests/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import astroid

from asttokens import util, supports_tokenless, ASTText
from asttokens.util import is_ellipsis, is_expr_stmt


def get_fixture_path(*path_parts):
Expand Down Expand Up @@ -149,15 +150,40 @@ def check_get_text_tokenless(self, node, test_case, text):
has_lineno = getattr(node, 'lineno', None) is not None
test_case.assertEqual(has_lineno, text_tokenless != '')
if has_lineno:
if (
text != text_tokenless
and text_tokenless.startswith(text)
and text_tokenless[len(text):].strip().startswith('# type: ')
if text != text_tokenless:
if (
text_tokenless.startswith(text)
and test_case.is_astroid_test
):
# astroid positions can include type comments, which we can ignore.
return
test_case.assertEqual(text, text_tokenless)
and (
# astroid positions can include type comments, which we can ignore.
text_tokenless[len(text):].strip().startswith('# type: ')
# astroid+ASTTokens doesn't correctly handle the 3.12+ type variable syntax.
# Since ASTText is preferred for new Python versions, this is not a priority.
or isinstance(node.parent, astroid.TypeVar)
)
):
return

if (
text == text_tokenless.lstrip()
and isinstance(getattr(node, 'body', None), list)
and len(node.body) == 1
and is_expr_stmt(node.body[0])
and is_ellipsis(node.body[0].value)
):
# ASTTokens doesn't include padding for compound statements where the
# body is a single statement starting on the same line where the header ends.
# ASTText does include padding in this case if the header spans multiple lines,
# as does ast.get_source_segment(padded=True).
# This is a minor difference and not worth fixing.
# In practice it arises in test_sys_modules when testing files containing
# function definition stubs like:
# def foo(
# <parameters>
# ): ... # (actual ellipsis)
return

test_case.assertEqual(text, text_tokenless)
else:
# _get_text_positions_tokenless can't work with nodes without lineno.
# Double-check that such nodes are unusual.
Expand Down

0 comments on commit 0224610

Please sign in to comment.