예제 #1
0
파일: transform.py 프로젝트: chvmq/pycln
    def refactor_import_star(self,
                             updated_node: cst.ImportFrom) -> cst.ImportFrom:
        """Add used import aliases to import star.

        :param updated_node: `cst.ImportFrom` node to refactor.
        :returns: refactored node.
        """
        is_multiline = len(self._used_names) > 3
        used_aliases: List[cst.ImportAlias] = []
        for name in self._used_names:

            # Skip any dotted name in order
            # to avoid names collision.
            if "." in name:
                continue

            # Initialy create a single line alias.
            cst_alias = cst.ImportAlias(
                name=cst.Name(name),
                comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
            )

            # Convert the single line alias to multiline
            # if there're more than 3 used names.
            if is_multiline:
                cst_alias = self._multiline_alias(cst_alias)

            used_aliases.append(cst_alias)

        return self._stylize(updated_node, used_aliases, is_multiline)
예제 #2
0
class NonlocalParsingTest(CSTNodeTest):
    @data_provider((
        # Single nonlocal statement
        {
            "node": cst.Nonlocal((cst.NameItem(cst.Name("a")), )),
            "code": "nonlocal a",
        },
        # Multiple entries in nonlocal statement
        {
            "node":
            cst.Nonlocal((
                cst.NameItem(
                    cst.Name("a"),
                    comma=cst.Comma(
                        whitespace_after=cst.SimpleWhitespace(" ")),
                ),
                cst.NameItem(cst.Name("b")),
            )),
            "code":
            "nonlocal a, b",
        },
        # Whitespace rendering test
        {
            "node":
            cst.Nonlocal(
                (
                    cst.NameItem(
                        cst.Name("a"),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace("  "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.NameItem(cst.Name("b")),
                ),
                whitespace_after_nonlocal=cst.SimpleWhitespace("  "),
            ),
            "code":
            "nonlocal  a  ,  b",
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(
            parser=lambda code: ensure_type(parse_statement(code), cst.
                                            SimpleStatementLine).body[0],
            **kwargs,
        )
예제 #3
0
파일: transform.py 프로젝트: chvmq/pycln
 def _multiline_alias(self, alias: cst.ImportAlias) -> cst.ImportAlias:
     # Convert the given `alias` to multiline `alias`.
     return cst.ImportAlias(
         name=alias.name,
         asname=alias.asname,
         comma=cst.Comma(
             whitespace_after=ImportTransformer.
             _multiline_parenthesized_whitespace(self._indentation +
                                                 SPACE4)),
     )
예제 #4
0
 def test_adding_parens(self) -> None:
     node = cst.With(
         (
             cst.WithItem(
                 cst.Call(cst.Name("foo")),
                 comma=cst.Comma(
                     whitespace_after=cst.ParenthesizedWhitespace(), ),
             ),
             cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()),
         ),
         cst.SimpleStatementSuite((cst.Pass(), )),
         lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
         rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
     )
     module = cst.Module([])
     self.assertEqual(
         module.code_for_node(node),
         ("with ( foo(),\n"
          "bar(), ): pass\n")  # noqa
     )
예제 #5
0
 def leave_Call(
     self,
     original_node: cst.Call,
     updated_node: cst.Call,
 ) -> cst.Call:
     if len(updated_node.args) < self.argument_count:
         return updated_node
     else:
         last_arg = updated_node.args[-1]
         return updated_node.with_changes(args=(
             *updated_node.args[:-1],
             last_arg.with_changes(comma=cst.Comma()),
         ), )
예제 #6
0
 def leave_Parameters(
     self,
     original_node: cst.Parameters,
     updated_node: cst.Parameters,
 ) -> cst.Parameters:
     skip = (
         #
         self.parameter_count is None
         or len(updated_node.params) < self.parameter_count
         or (len(updated_node.params) == 1
             and updated_node.params[0].name.value in {"self", "cls"}))
     if skip:
         return updated_node
     else:
         last_param = updated_node.params[-1]
         return updated_node.with_changes(params=(
             *updated_node.params[:-1],
             last_param.with_changes(comma=cst.Comma()),
         ), )
예제 #7
0
class AssertConstructionTest(CSTNodeTest):
    @data_provider((
        # Simple assert
        {
            "node": cst.Assert(cst.Name("True")),
            "code": "assert True",
            "parser": None,
            "expected_position": None,
        },
        # Assert with message
        {
            "node":
            cst.Assert(cst.Name("True"),
                       cst.SimpleString('"Value should be true"')),
            "code":
            'assert True, "Value should be true"',
            "parser":
            None,
            "expected_position":
            None,
        },
        # Whitespace oddities test
        {
            "node":
            cst.Assert(
                cst.Name("True",
                         lpar=(cst.LeftParen(), ),
                         rpar=(cst.RightParen(), )),
                whitespace_after_assert=cst.SimpleWhitespace(""),
            ),
            "code":
            "assert(True)",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 12)),
        },
        # Whitespace rendering test
        {
            "node":
            cst.Assert(
                whitespace_after_assert=cst.SimpleWhitespace("  "),
                test=cst.Name("True"),
                comma=cst.Comma(
                    whitespace_before=cst.SimpleWhitespace("  "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                ),
                msg=cst.SimpleString('"Value should be true"'),
            ),
            "code":
            'assert  True  ,  "Value should be true"',
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 39)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        # Validate whitespace handling
        {
            "get_node": (lambda: cst.Assert(
                cst.Name("True"),
                whitespace_after_assert=cst.SimpleWhitespace(""),
            )),
            "expected_re":
            "Must have at least one space after 'assert'",
        },
        # Validate comma handling
        {
            "get_node":
            (lambda: cst.Assert(test=cst.Name("True"), comma=cst.Comma())),
            "expected_re":
            "Cannot have trailing comma after 'test'",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #8
0
class ClassDefParserTest(CSTNodeTest):
    @data_provider((
        # Simple classdef
        # pyre-fixme[6]: Incompatible parameter type
        {
            "node":
            cst.ClassDef(cst.Name("Foo"),
                         cst.SimpleStatementSuite((cst.Pass(), ))),
            "code":
            "class Foo: pass\n",
        },
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(): pass\n",
        },
        # Positional arguments render test
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                bases=(cst.Arg(cst.Name("obj")), ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(obj): pass\n",
        },
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                bases=(
                    cst.Arg(
                        cst.Name("Bar"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        cst.Name("Baz"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(cst.Name("object")),
                ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(Bar, Baz, object): pass\n",
        },
        # Keyword arguments render test
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                keywords=(cst.Arg(
                    keyword=cst.Name("metaclass"),
                    equal=cst.AssignEqual(),
                    value=cst.Name("Bar"),
                ), ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(metaclass = Bar): pass\n",
        },
        # Iterator expansion render test
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                bases=(cst.Arg(star="*", value=cst.Name("one")), ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(*one): pass\n",
        },
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                bases=(
                    cst.Arg(
                        star="*",
                        value=cst.Name("one"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("two"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(star="*", value=cst.Name("three")),
                ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(*one, *two, *three): pass\n",
        },
        # Dictionary expansion render test
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                keywords=(cst.Arg(star="**", value=cst.Name("one")), ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(**one): pass\n",
        },
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                keywords=(
                    cst.Arg(
                        star="**",
                        value=cst.Name("one"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="**",
                        value=cst.Name("two"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(star="**", value=cst.Name("three")),
                ),
                rpar=cst.RightParen(),
            ),
            "code":
            "class Foo(**one, **two, **three): pass\n",
        },
        # Decorator render tests
        {
            "node":
            cst.ClassDef(
                cst.Name("Foo"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                decorators=(cst.Decorator(cst.Name("foo")), ),
                lpar=cst.LeftParen(),
                rpar=cst.RightParen(),
            ),
            "code":
            "@foo\nclass Foo(): pass\n",
            "expected_position":
            CodeRange((2, 0), (2, 17)),
        },
        {
            "node":
            cst.ClassDef(
                leading_lines=(
                    cst.EmptyLine(),
                    cst.EmptyLine(comment=cst.Comment("# leading comment 1")),
                ),
                decorators=(
                    cst.Decorator(cst.Name("foo"), leading_lines=()),
                    cst.Decorator(
                        cst.Name("bar"),
                        leading_lines=(cst.EmptyLine(
                            comment=cst.Comment("# leading comment 2")), ),
                    ),
                    cst.Decorator(
                        cst.Name("baz"),
                        leading_lines=(cst.EmptyLine(
                            comment=cst.Comment("# leading comment 3")), ),
                    ),
                ),
                lines_after_decorators=(cst.EmptyLine(
                    comment=cst.Comment("# class comment")), ),
                name=cst.Name("Foo"),
                body=cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(),
                rpar=cst.RightParen(),
            ),
            "code":
            "\n# leading comment 1\n@foo\n# leading comment 2\n@bar\n# leading comment 3\n@baz\n# class comment\nclass Foo(): pass\n",
            "expected_position":
            CodeRange((9, 0), (9, 17)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs, parser=parse_statement)
예제 #9
0
class AssertParsingTest(CSTNodeTest):
    @data_provider((
        # Simple assert
        {
            "node": cst.Assert(cst.Name("True")),
            "code": "assert True",
            "parser": _assert_parser,
            "expected_position": None,
        },
        # Assert with message
        {
            "node":
            cst.Assert(
                cst.Name("True"),
                cst.SimpleString('"Value should be true"'),
                comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
            ),
            "code":
            'assert True, "Value should be true"',
            "parser":
            _assert_parser,
            "expected_position":
            None,
        },
        # Whitespace oddities test
        {
            "node":
            cst.Assert(
                cst.Name("True",
                         lpar=(cst.LeftParen(), ),
                         rpar=(cst.RightParen(), )),
                whitespace_after_assert=cst.SimpleWhitespace(""),
            ),
            "code":
            "assert(True)",
            "parser":
            _assert_parser,
            "expected_position":
            None,
        },
        # Whitespace rendering test
        {
            "node":
            cst.Assert(
                whitespace_after_assert=cst.SimpleWhitespace("  "),
                test=cst.Name("True"),
                comma=cst.Comma(
                    whitespace_before=cst.SimpleWhitespace("  "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                ),
                msg=cst.SimpleString('"Value should be true"'),
            ),
            "code":
            'assert  True  ,  "Value should be true"',
            "parser":
            _assert_parser,
            "expected_position":
            None,
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)
예제 #10
0
class LambdaParserTest(CSTNodeTest):
    @data_provider((
        # Simple lambda
        (cst.Lambda(cst.Parameters(), cst.Integer("5")), "lambda: 5"),
        # Test basic positional params
        (
            cst.Lambda(
                cst.Parameters(params=(
                    cst.Param(
                        cst.Name("bar"),
                        star="",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Param(cst.Name("baz"), star=""),
                )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "lambda bar, baz: 5",
        ),
        # Test basic positional default params
        (
            cst.Lambda(
                cst.Parameters(default_params=(
                    cst.Param(
                        cst.Name("bar"),
                        default=cst.SimpleString('"one"'),
                        equal=cst.AssignEqual(),
                        star="",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Param(
                        cst.Name("baz"),
                        default=cst.Integer("5"),
                        equal=cst.AssignEqual(),
                        star="",
                    ),
                )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda bar = "one", baz = 5: 5',
        ),
        # Mixed positional and default params.
        (
            cst.Lambda(
                cst.Parameters(
                    params=(cst.Param(
                        cst.Name("bar"),
                        star="",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ), ),
                    default_params=(cst.Param(
                        cst.Name("baz"),
                        default=cst.Integer("5"),
                        equal=cst.AssignEqual(),
                        star="",
                    ), ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "lambda bar, baz = 5: 5",
        ),
        # Test kwonly params
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.ParamStar(),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(cst.Name("baz"), star=""),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda *, bar = "one", baz: 5',
        ),
        # Mixed params and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(
                            cst.Name("first"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("second"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    star_arg=cst.ParamStar(),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("biz"),
                            default=cst.SimpleString('"two"'),
                            equal=cst.AssignEqual(),
                            star="",
                        ),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda first, second, *, bar = "one", baz, biz = "two": 5',
        ),
        # Mixed default_params and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    default_params=(
                        cst.Param(
                            cst.Name("first"),
                            default=cst.Float("1.0"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("second"),
                            default=cst.Float("1.5"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    star_arg=cst.ParamStar(),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("biz"),
                            default=cst.SimpleString('"two"'),
                            equal=cst.AssignEqual(),
                            star="",
                        ),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda first = 1.0, second = 1.5, *, bar = "one", baz, biz = "two": 5',
        ),
        # Mixed params, default_params, and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(
                            cst.Name("first"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("second"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    default_params=(
                        cst.Param(
                            cst.Name("third"),
                            default=cst.Float("1.0"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("fourth"),
                            default=cst.Float("1.5"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    star_arg=cst.ParamStar(),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("biz"),
                            default=cst.SimpleString('"two"'),
                            equal=cst.AssignEqual(),
                            star="",
                        ),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda first, second, third = 1.0, fourth = 1.5, *, bar = "one", baz, biz = "two": 5',
        ),
        # Test star_arg
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.Param(cst.Name("params"), star="*")),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "lambda *params: 5",
        ),
        # Typed star_arg, include kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.Param(
                        cst.Name("params"),
                        star="*",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("biz"),
                            default=cst.SimpleString('"two"'),
                            equal=cst.AssignEqual(),
                            star="",
                        ),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda *params, bar = "one", baz, biz = "two": 5',
        ),
        # Mixed params default_params, star_arg and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(
                            cst.Name("first"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("second"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    default_params=(
                        cst.Param(
                            cst.Name("third"),
                            default=cst.Float("1.0"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("fourth"),
                            default=cst.Float("1.5"),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    star_arg=cst.Param(
                        cst.Name("params"),
                        star="*",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    kwonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            default=cst.SimpleString('"one"'),
                            equal=cst.AssignEqual(),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("biz"),
                            default=cst.SimpleString('"two"'),
                            equal=cst.AssignEqual(),
                            star="",
                        ),
                    ),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            'lambda first, second, third = 1.0, fourth = 1.5, *params, bar = "one", baz, biz = "two": 5',
        ),
        # Test star_arg and star_kwarg
        (
            cst.Lambda(
                cst.Parameters(
                    star_kwarg=cst.Param(cst.Name("kwparams"), star="**")),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "lambda **kwparams: 5",
        ),
        # Test star_arg and kwarg
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.Param(
                        cst.Name("params"),
                        star="*",
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    star_kwarg=cst.Param(cst.Name("kwparams"), star="**"),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "lambda *params, **kwparams: 5",
        ),
        # Inner whitespace
        (
            cst.Lambda(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                params=cst.Parameters(),
                colon=cst.Colon(
                    whitespace_before=cst.SimpleWhitespace("  "),
                    whitespace_after=cst.SimpleWhitespace(" "),
                ),
                body=cst.Integer("5"),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "( lambda  : 5 )",
        ),
    ))
    def test_valid(self,
                   node: cst.CSTNode,
                   code: str,
                   position: Optional[CodeRange] = None) -> None:
        self.validate_node(node, code, parse_expression, position)
예제 #11
0
class WithTest(CSTNodeTest):
    @data_provider((
        # Simple with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 24)),
        },
        # Simple async with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.7")),
        },
        # Python 3.6 async with block
        {
            "node":
            cst.FunctionDef(
                cst.Name("foo"),
                cst.Parameters(),
                cst.IndentedBlock((cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    asynchronous=cst.Asynchronous(),
                ), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async def foo():\n    async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.6")),
        },
        # Multiple context managers
        {
            "node":
            cst.With(
                (
                    cst.WithItem(cst.Call(cst.Name("foo"))),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            None,
        },
        {
            "node":
            cst.With(
                (
                    cst.WithItem(
                        cst.Call(cst.Name("foo")),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            parse_statement,
        },
        # With block containing variable for context manager.
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(cst.Name("ctx")),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr() as ctx: pass\n",
            "parser":
            parse_statement,
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                ),
            ),
            "code":
            "    with context_mgr(): pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (1, 28)),
        },
        # with an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    with context_mgr():\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nwith context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((2, 0), (2, 24)),
        },
        # Weird spacing rules
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(
                        cst.Name("context_mgr"),
                        lpar=(cst.LeftParen(), ),
                        rpar=(cst.RightParen(), ),
                    )), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "code":
            "with(context_mgr()): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 25)),
        },
        # Whitespace
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(
                        cst.Name("ctx"),
                        whitespace_before_as=cst.SimpleWhitespace("  "),
                        whitespace_after_as=cst.SimpleWhitespace("  "),
                    ),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace("  "),
                whitespace_before_colon=cst.SimpleWhitespace("  "),
            ),
            "code":
            "with  context_mgr()  as  ctx  : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 36)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node":
            lambda: cst.With((),
                             cst.IndentedBlock((cst.SimpleStatementLine(
                                 (cst.Pass(), )), ))),
            "expected_re":
            "A With statement must have at least one WithItem",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("foo")),
                    comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")
                                    ),
                ), ),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
            ),
            "expected_re":
            "The last WithItem in a With cannot have a trailing comma",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after with keyword",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)

    @data_provider((
        {
            "code": "with a, b: pass",
            "parser": parse_statement_as(python_version="3.1"),
            "expect_success": True,
        },
        {
            "code": "with a, b: pass",
            "parser": parse_statement_as(python_version="3.0"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        self.assert_parses(**kwargs)
예제 #12
0
class TryTest(CSTNodeTest):
    @data_provider(
        (
            # Simple try/except block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 12)),
            },
            # Try/except with a class
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("Exception"),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept Exception: pass\n",
                "parser": parse_statement,
            },
            # Try/except with a named class
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("Exception"),
                            name=cst.AsName(cst.Name("exc")),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept Exception as exc: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 29)),
            },
            # Try/except with multiple clauses
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("KeyError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                ),
                "code": "try: pass\n"
                + "except TypeError as e: pass\n"
                + "except KeyError as e: pass\n"
                + "except: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (4, 12)),
            },
            # Simple try/finally block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 13)),
            },
            # Simple try/except/finally block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (3, 13)),
            },
            # Simple try/except/else block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nelse: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (3, 10)),
            },
            # Simple try/except/else block/finally
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nelse: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (4, 13)),
            },
            # Verify whitespace in various locations
            {
                "node": cst.Try(
                    leading_lines=(cst.EmptyLine(comment=cst.Comment("# 1")),),
                    body=cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            leading_lines=(cst.EmptyLine(comment=cst.Comment("# 2")),),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(
                                cst.Name("e"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            whitespace_after_except=cst.SimpleWhitespace("  "),
                            whitespace_before_colon=cst.SimpleWhitespace(" "),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ),
                    orelse=cst.Else(
                        leading_lines=(cst.EmptyLine(comment=cst.Comment("# 3")),),
                        body=cst.SimpleStatementSuite((cst.Pass(),)),
                        whitespace_before_colon=cst.SimpleWhitespace(" "),
                    ),
                    finalbody=cst.Finally(
                        leading_lines=(cst.EmptyLine(comment=cst.Comment("# 4")),),
                        body=cst.SimpleStatementSuite((cst.Pass(),)),
                        whitespace_before_colon=cst.SimpleWhitespace(" "),
                    ),
                    whitespace_before_colon=cst.SimpleWhitespace(" "),
                ),
                "code": "# 1\ntry : pass\n# 2\nexcept  TypeError  as  e : pass\n# 3\nelse : pass\n# 4\nfinally : pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((2, 0), (8, 14)),
            },
            # Please don't write code like this
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("KeyError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\n"
                + "except TypeError as e: pass\n"
                + "except KeyError as e: pass\n"
                + "except: pass\n"
                + "else: pass\n"
                + "finally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (6, 13)),
            },
            # Verify indentation
            {
                "node": DummyIndentedBlock(
                    "    ",
                    cst.Try(
                        cst.SimpleStatementSuite((cst.Pass(),)),
                        handlers=(
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                type=cst.Name("TypeError"),
                                name=cst.AsName(cst.Name("e")),
                            ),
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                type=cst.Name("KeyError"),
                                name=cst.AsName(cst.Name("e")),
                            ),
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                whitespace_after_except=cst.SimpleWhitespace(""),
                            ),
                        ),
                        orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                        finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                    ),
                ),
                "code": "    try: pass\n"
                + "    except TypeError as e: pass\n"
                + "    except KeyError as e: pass\n"
                + "    except: pass\n"
                + "    else: pass\n"
                + "    finally: pass\n",
                "parser": None,
            },
            # Verify indentation in bodies
            {
                "node": DummyIndentedBlock(
                    "    ",
                    cst.Try(
                        cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),)),
                        handlers=(
                            cst.ExceptHandler(
                                cst.IndentedBlock(
                                    (cst.SimpleStatementLine((cst.Pass(),)),)
                                ),
                                whitespace_after_except=cst.SimpleWhitespace(""),
                            ),
                        ),
                        orelse=cst.Else(
                            cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),))
                        ),
                        finalbody=cst.Finally(
                            cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),))
                        ),
                    ),
                ),
                "code": "    try:\n"
                + "        pass\n"
                + "    except:\n"
                + "        pass\n"
                + "    else:\n"
                + "        pass\n"
                + "    finally:\n"
                + "        pass\n",
                "parser": None,
            },
            # No space when using grouping parens
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                            type=cst.Name(
                                "Exception",
                                lpar=(cst.LeftParen(),),
                                rpar=(cst.RightParen(),),
                            ),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept(Exception): pass\n",
                "parser": parse_statement,
            },
            # No space when using tuple
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                            type=cst.Tuple(
                                [
                                    cst.Element(
                                        cst.Name("IOError"),
                                        comma=cst.Comma(
                                            whitespace_after=cst.SimpleWhitespace(" ")
                                        ),
                                    ),
                                    cst.Element(cst.Name("ImportError")),
                                ]
                            ),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept(IOError, ImportError): pass\n",
                "parser": parse_statement,
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": lambda: cst.AsName(cst.Name("")),
                "expected_re": "empty name identifier",
            },
            {
                "get_node": lambda: cst.AsName(
                    cst.Name("bla"), whitespace_after_as=cst.SimpleWhitespace("")
                ),
                "expected_re": "between 'as'",
            },
            {
                "get_node": lambda: cst.AsName(
                    cst.Name("bla"), whitespace_before_as=cst.SimpleWhitespace("")
                ),
                "expected_re": "before 'as'",
            },
            {
                "get_node": lambda: cst.ExceptHandler(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    name=cst.AsName(cst.Name("bla")),
                ),
                "expected_re": "name for an empty type",
            },
            {
                "get_node": lambda: cst.ExceptHandler(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    type=cst.Name("TypeError"),
                    whitespace_after_except=cst.SimpleWhitespace(""),
                ),
                "expected_re": "at least one space after except",
            },
            {
                "get_node": lambda: cst.Try(cst.SimpleStatementSuite((cst.Pass(),))),
                "expected_re": "at least one ExceptHandler or Finally",
            },
            {
                "get_node": lambda: cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "expected_re": "at least one ExceptHandler in order to have an Else",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #13
0
class ImportCreateTest(CSTNodeTest):
    @data_provider(
        (
            # Simple import statement
            {
                "node": cst.Import(names=(cst.ImportAlias(cst.Name("foo")),)),
                "code": "import foo",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            # Comma-separated list of imports
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz"))
                        ),
                    )
                ),
                "code": "import foo.bar, foo.baz",
                "expected_position": CodeRange((1, 0), (1, 23)),
            },
            # Import with an alias
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz",
            },
            # Import with an alias, comma separated
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz")),
                            asname=cst.AsName(cst.Name("bar")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz, foo.baz as bar",
            },
            # Combine for fun and profit
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("insta"), cst.Name("gram"))
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz"))
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"), asname=cst.AsName(cst.Name("ut"))
                        ),
                    )
                ),
                "code": "import foo.bar as baz, insta.gram, foo.baz, unittest as ut",
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(
                                cst.Name("foo"),
                                cst.Name("bar"),
                                dot=cst.Dot(
                                    whitespace_before=cst.SimpleWhitespace(" "),
                                    whitespace_after=cst.SimpleWhitespace(" "),
                                ),
                            ),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "import  foo . bar  as  baz ,  unittest  as  ut",
                "expected_position": CodeRange((1, 0), (1, 46)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": lambda: cst.Import(names=()),
                "expected_re": "at least one ImportAlias",
            },
            {
                "get_node": lambda: cst.Import(names=(cst.ImportAlias(cst.Name("")),)),
                "expected_re": "empty name identifier",
            },
            {
                "get_node": lambda: cst.Import(
                    names=(
                        cst.ImportAlias(cst.Attribute(cst.Name(""), cst.Name("bla"))),
                    )
                ),
                "expected_re": "empty name identifier",
            },
            {
                "get_node": lambda: cst.Import(
                    names=(
                        cst.ImportAlias(cst.Attribute(cst.Name("bla"), cst.Name(""))),
                    )
                ),
                "expected_re": "empty name identifier",
            },
            {
                "get_node": lambda: cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            comma=cst.Comma(),
                        ),
                    )
                ),
                "expected_re": "trailing comma",
            },
            {
                "get_node": lambda: cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    ),
                    whitespace_after_import=cst.SimpleWhitespace(""),
                ),
                "expected_re": "at least one space",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #14
0
class NamedExprTest(CSTNodeTest):
    @data_provider((
        # Simple named expression
        {
            "node": cst.NamedExpr(cst.Name("x"), cst.Float("5.5")),
            "code": "x := 5.5",
            "parser":
            None,  # Walrus operator is illegal as top-level statement
            "expected_position": None,
        },
        # Parenthesized named expression
        {
            "node":
            cst.NamedExpr(
                lpar=(cst.LeftParen(), ),
                target=cst.Name("foo"),
                value=cst.Integer("5"),
                rpar=(cst.RightParen(), ),
            ),
            "code":
            "(foo := 5)",
            "parser":
            _parse_expression_force_38,
            "expected_position":
            CodeRange((1, 1), (1, 9)),
        },
        # Make sure that spacing works
        {
            "node":
            cst.NamedExpr(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                target=cst.Name("foo"),
                whitespace_before_walrus=cst.SimpleWhitespace("  "),
                whitespace_after_walrus=cst.SimpleWhitespace("  "),
                value=cst.Name("bar"),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "code":
            "( foo  :=  bar )",
            "parser":
            _parse_expression_force_38,
            "expected_position":
            CodeRange((1, 2), (1, 14)),
        },
        # Make sure we can use these where allowed in if/while statements
        {
            "node":
            cst.While(
                test=cst.NamedExpr(
                    target=cst.Name(value="x"),
                    value=cst.Call(func=cst.Name(value="some_input")),
                ),
                body=cst.SimpleStatementSuite(body=[cst.Pass()]),
            ),
            "code":
            "while x := some_input(): pass\n",
            "parser":
            _parse_statement_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.If(
                test=cst.NamedExpr(
                    target=cst.Name(value="x"),
                    value=cst.Call(func=cst.Name(value="some_input")),
                ),
                body=cst.SimpleStatementSuite(body=[cst.Pass()]),
            ),
            "code":
            "if x := some_input(): pass\n",
            "parser":
            _parse_statement_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.If(
                test=cst.NamedExpr(
                    target=cst.Name(value="x"),
                    value=cst.Integer(value="1"),
                    whitespace_before_walrus=cst.SimpleWhitespace(""),
                    whitespace_after_walrus=cst.SimpleWhitespace(""),
                ),
                body=cst.SimpleStatementSuite(body=[cst.Pass()]),
            ),
            "code":
            "if x:=1: pass\n",
            "parser":
            _parse_statement_force_38,
            "expected_position":
            None,
        },
        # Function args
        {
            "node":
            cst.Call(
                func=cst.Name(value="f"),
                args=[
                    cst.Arg(value=cst.NamedExpr(
                        target=cst.Name(value="y"),
                        value=cst.Integer(value="1"),
                        whitespace_before_walrus=cst.SimpleWhitespace(""),
                        whitespace_after_walrus=cst.SimpleWhitespace(""),
                    )),
                ],
            ),
            "code":
            "f(y:=1)",
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        # Whitespace handling on args is fragile
        {
            "node":
            cst.Call(
                func=cst.Name(value="f"),
                args=[
                    cst.Arg(
                        value=cst.Name(value="x"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace("  ")),
                    ),
                    cst.Arg(
                        value=cst.NamedExpr(
                            target=cst.Name(value="y"),
                            value=cst.Integer(value="1"),
                            whitespace_before_walrus=cst.SimpleWhitespace(
                                "   "),
                            whitespace_after_walrus=cst.SimpleWhitespace(
                                "    "),
                        ),
                        whitespace_after_arg=cst.SimpleWhitespace("     "),
                    ),
                ],
            ),
            "code":
            "f(x,  y   :=    1     )",
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                func=cst.Name(value="f"),
                args=[
                    cst.Arg(
                        value=cst.NamedExpr(
                            target=cst.Name(value="y"),
                            value=cst.Integer(value="1"),
                            whitespace_before_walrus=cst.SimpleWhitespace(
                                "   "),
                            whitespace_after_walrus=cst.SimpleWhitespace(
                                "    "),
                        ),
                        whitespace_after_arg=cst.SimpleWhitespace("     "),
                    ),
                ],
                whitespace_before_args=cst.SimpleWhitespace("  "),
            ),
            "code":
            "f(  y   :=    1     )",
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node": (lambda: cst.NamedExpr(
                cst.Name("foo"), cst.Name("bar"), lpar=(cst.LeftParen(), ))),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node": (lambda: cst.NamedExpr(
                cst.Name("foo"), cst.Name("bar"), rpar=(cst.RightParen(), ))),
            "expected_re":
            "right paren without left paren",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #15
0
class DictTest(CSTNodeTest):
    @data_provider([
        # zero-element dict
        {
            "node": cst.Dict([]),
            "code": "{}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 2)),
        },
        # one-element dict, sentinel comma value
        {
            "node": cst.Dict([cst.DictElement(cst.Name("k"), cst.Name("v"))]),
            "code": "{k: v}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 6)),
        },
        {
            "node": cst.Dict([cst.StarredDictElement(cst.Name("expanded"))]),
            "code": "{**expanded}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 12)),
        },
        # two-element dict, sentinel comma value
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k1"), cst.Name("v1")),
                cst.DictElement(cst.Name("k2"), cst.Name("v2")),
            ]),
            "code":
            "{k1: v1, k2: v2}",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 16)),
        },
        # custom whitespace between brackets
        {
            "node":
            cst.Dict(
                [cst.DictElement(cst.Name("k"), cst.Name("v"))],
                lbrace=cst.LeftCurlyBrace(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbrace=cst.RightCurlyBrace(
                    whitespace_before=cst.SimpleWhitespace("\t\t")),
            ),
            "code":
            "{\tk: v\t\t}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 9)),
        },
        # with parenthesis
        {
            "node":
            cst.Dict(
                [cst.DictElement(cst.Name("k"), cst.Name("v"))],
                lpar=[cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "code":
            "({k: v})",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 7)),
        },
        # starred element
        {
            "node":
            cst.Dict([
                cst.StarredDictElement(cst.Name("one")),
                cst.StarredDictElement(cst.Name("two")),
            ]),
            "code":
            "{**one, **two}",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 14)),
        },
        # custom comma on DictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k"),
                                cst.Name("v"),
                                comma=cst.Comma())
            ]),
            "code":
            "{k: v,}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 7)),
        },
        # custom comma on StarredDictElement
        {
            "node":
            cst.Dict([
                cst.StarredDictElement(cst.Name("expanded"), comma=cst.Comma())
            ]),
            "code":
            "{**expanded,}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 13)),
        },
        # custom whitespace on DictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(
                    cst.Name("k"),
                    cst.Name("v"),
                    whitespace_before_colon=cst.SimpleWhitespace("\t"),
                    whitespace_after_colon=cst.SimpleWhitespace("\t\t"),
                )
            ]),
            "code":
            "{k\t:\t\tv}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 8)),
        },
        # custom whitespace on StarredDictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k"),
                                cst.Name("v"),
                                comma=cst.Comma()),
                cst.StarredDictElement(
                    cst.Name("expanded"),
                    whitespace_before_value=cst.SimpleWhitespace("  "),
                ),
            ]),
            "code":
            "{k: v,**  expanded}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 19)),
        },
        # missing spaces around dict is always okay
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    cst.Name("b"),
                    cst.Dict([cst.DictElement(cst.Name("k"), cst.Name("v"))]),
                    ifs=[
                        cst.CompIf(
                            cst.Name("c"),
                            whitespace_before=cst.SimpleWhitespace(""),
                        )
                    ],
                    whitespace_after_in=cst.SimpleWhitespace(""),
                ),
            ),
            "parser":
            parse_expression,
            "code":
            "(a for b in{k: v}if c)",
        },
    ])
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider([
        # unbalanced Dict
        {
            "get_node": lambda: cst.Dict([], lpar=[cst.LeftParen()]),
            "expected_re": "left paren without right paren",
        }
    ])
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)

    @data_provider((
        {
            "code": "{**{}}",
            "parser": parse_expression_as(python_version="3.5"),
            "expect_success": True,
        },
        {
            "code": "{**{}}",
            "parser": parse_expression_as(python_version="3.3"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        self.assert_parses(**kwargs)
예제 #16
0
class ListTest(CSTNodeTest):

    # A lot of Element/StarredElement tests are provided by the tests for Tuple, so we
    # we don't need to duplicate them here.
    @data_provider([
        # zero-element list
        {
            "node": cst.List([]),
            "code": "[]",
            "parser": parse_expression
        },
        # one-element list, sentinel comma value
        {
            "node": cst.List([cst.Element(cst.Name("single_element"))]),
            "code": "[single_element]",
            "parser": parse_expression,
        },
        # custom whitespace between brackets
        {
            "node":
            cst.List(
                [cst.Element(cst.Name("single_element"))],
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace("    ")),
            ),
            "code":
            "[\tsingle_element    ]",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange.create((1, 0), (1, 21)),
        },
        # two-element list, sentinel comma value
        {
            "node":
            cst.List(
                [cst.Element(cst.Name("one")),
                 cst.Element(cst.Name("two"))]),
            "code":
            "[one, two]",
            "parser":
            None,
        },
        # with parenthesis
        {
            "node":
            cst.List(
                [cst.Element(cst.Name("one"))],
                lpar=[cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "code":
            "([one])",
            "parser":
            None,
            "expected_position":
            CodeRange.create((1, 1), (1, 6)),
        },
        # starred element
        {
            "node":
            cst.List([
                cst.StarredElement(cst.Name("one")),
                cst.StarredElement(cst.Name("two")),
            ]),
            "code":
            "[*one, *two]",
            "parser":
            None,
            "expected_position":
            CodeRange.create((1, 0), (1, 12)),
        },
        # missing spaces around list, always okay
        {
            "node":
            cst.For(
                target=cst.List([
                    cst.Element(cst.Name("k"), comma=cst.Comma()),
                    cst.Element(cst.Name("v")),
                ]),
                iter=cst.Name("abc"),
                body=cst.SimpleStatementSuite([cst.Pass()]),
                whitespace_after_for=cst.SimpleWhitespace(""),
                whitespace_before_in=cst.SimpleWhitespace(""),
            ),
            "code":
            "for[k,v]in abc: pass\n",
            "parser":
            parse_statement,
        },
    ])
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(((
        lambda: cst.List(
            [cst.Element(cst.Name("mismatched"))],
            lpar=[cst.LeftParen(), cst.LeftParen()],
            rpar=[cst.RightParen()],
        ),
        "unbalanced parens",
    ), ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
예제 #17
0
class CallTest(CSTNodeTest):
    @data_provider((
        # Simple call
        {
            "node": cst.Call(cst.Name("foo")),
            "code": "foo()",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node":
            cst.Call(cst.Name("foo"),
                     whitespace_before_args=cst.SimpleWhitespace(" ")),
            "code":
            "foo( )",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Call with attribute dereference
        {
            "node": cst.Call(cst.Attribute(cst.Name("foo"), cst.Name("bar"))),
            "code": "foo.bar()",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Positional arguments render test
        {
            "node": cst.Call(cst.Name("foo"), (cst.Arg(cst.Integer("1")), )),
            "code": "foo(1)",
            "parser": None,
            "expected_position": None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(cst.Integer("1")),
                    cst.Arg(cst.Integer("2")),
                    cst.Arg(cst.Integer("3")),
                ),
            ),
            "code":
            "foo(1, 2, 3)",
            "parser":
            None,
            "expected_position":
            None,
        },
        # Positional arguments parse test
        {
            "node": cst.Call(cst.Name("foo"),
                             (cst.Arg(value=cst.Integer("1")), )),
            "code": "foo(1)",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (cst.Arg(
                    value=cst.Integer("1"),
                    whitespace_after_arg=cst.SimpleWhitespace(" "),
                ), ),
                whitespace_after_func=cst.SimpleWhitespace(" "),
                whitespace_before_args=cst.SimpleWhitespace(" "),
            ),
            "code":
            "foo ( 1 )",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (cst.Arg(
                    value=cst.Integer("1"),
                    comma=cst.Comma(
                        whitespace_after=cst.SimpleWhitespace(" ")),
                ), ),
                whitespace_after_func=cst.SimpleWhitespace(" "),
                whitespace_before_args=cst.SimpleWhitespace(" "),
            ),
            "code":
            "foo ( 1, )",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(
                        value=cst.Integer("1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        value=cst.Integer("2"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(value=cst.Integer("3")),
                ),
            ),
            "code":
            "foo(1, 2, 3)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Keyword arguments render test
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (cst.Arg(keyword=cst.Name("one"), value=cst.Integer("1")), ),
            ),
            "code":
            "foo(one = 1)",
            "parser":
            None,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(keyword=cst.Name("one"), value=cst.Integer("1")),
                    cst.Arg(keyword=cst.Name("two"), value=cst.Integer("2")),
                    cst.Arg(keyword=cst.Name("three"), value=cst.Integer("3")),
                ),
            ),
            "code":
            "foo(one = 1, two = 2, three = 3)",
            "parser":
            None,
            "expected_position":
            None,
        },
        # Keyword arguments parser test
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (cst.Arg(
                    keyword=cst.Name("one"),
                    equal=cst.AssignEqual(),
                    value=cst.Integer("1"),
                ), ),
            ),
            "code":
            "foo(one = 1)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(
                        keyword=cst.Name("one"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("two"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("2"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("three"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("3"),
                    ),
                ),
            ),
            "code":
            "foo(one = 1, two = 2, three = 3)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Iterator expansion render test
        {
            "node":
            cst.Call(cst.Name("foo"),
                     (cst.Arg(star="*", value=cst.Name("one")), )),
            "code":
            "foo(*one)",
            "parser":
            None,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(star="*", value=cst.Name("one")),
                    cst.Arg(star="*", value=cst.Name("two")),
                    cst.Arg(star="*", value=cst.Name("three")),
                ),
            ),
            "code":
            "foo(*one, *two, *three)",
            "parser":
            None,
            "expected_position":
            None,
        },
        # Iterator expansion parser test
        {
            "node":
            cst.Call(cst.Name("foo"),
                     (cst.Arg(star="*", value=cst.Name("one")), )),
            "code":
            "foo(*one)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(
                        star="*",
                        value=cst.Name("one"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("two"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(star="*", value=cst.Name("three")),
                ),
            ),
            "code":
            "foo(*one, *two, *three)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Dictionary expansion render test
        {
            "node":
            cst.Call(cst.Name("foo"),
                     (cst.Arg(star="**", value=cst.Name("one")), )),
            "code":
            "foo(**one)",
            "parser":
            None,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(star="**", value=cst.Name("one")),
                    cst.Arg(star="**", value=cst.Name("two")),
                    cst.Arg(star="**", value=cst.Name("three")),
                ),
            ),
            "code":
            "foo(**one, **two, **three)",
            "parser":
            None,
            "expected_position":
            None,
        },
        # Dictionary expansion parser test
        {
            "node":
            cst.Call(cst.Name("foo"),
                     (cst.Arg(star="**", value=cst.Name("one")), )),
            "code":
            "foo(**one)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(
                        star="**",
                        value=cst.Name("one"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="**",
                        value=cst.Name("two"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(star="**", value=cst.Name("three")),
                ),
            ),
            "code":
            "foo(**one, **two, **three)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Complicated mingling rules render test
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(value=cst.Name("pos1")),
                    cst.Arg(star="*", value=cst.Name("list1")),
                    cst.Arg(value=cst.Name("pos2")),
                    cst.Arg(value=cst.Name("pos3")),
                    cst.Arg(star="*", value=cst.Name("list2")),
                    cst.Arg(value=cst.Name("pos4")),
                    cst.Arg(star="*", value=cst.Name("list3")),
                    cst.Arg(keyword=cst.Name("kw1"), value=cst.Integer("1")),
                    cst.Arg(star="*", value=cst.Name("list4")),
                    cst.Arg(keyword=cst.Name("kw2"), value=cst.Integer("2")),
                    cst.Arg(star="*", value=cst.Name("list5")),
                    cst.Arg(keyword=cst.Name("kw3"), value=cst.Integer("3")),
                    cst.Arg(star="**", value=cst.Name("dict1")),
                    cst.Arg(keyword=cst.Name("kw4"), value=cst.Integer("4")),
                    cst.Arg(star="**", value=cst.Name("dict2")),
                ),
            ),
            "code":
            "foo(pos1, *list1, pos2, pos3, *list2, pos4, *list3, kw1 = 1, *list4, kw2 = 2, *list5, kw3 = 3, **dict1, kw4 = 4, **dict2)",
            "parser":
            None,
            "expected_position":
            None,
        },
        # Complicated mingling rules parser test
        {
            "node":
            cst.Call(
                cst.Name("foo"),
                (
                    cst.Arg(
                        value=cst.Name("pos1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("list1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        value=cst.Name("pos2"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        value=cst.Name("pos3"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("list2"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        value=cst.Name("pos4"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("list3"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("kw1"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("list4"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("kw2"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("2"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="*",
                        value=cst.Name("list5"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("kw3"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("3"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="**",
                        value=cst.Name("dict1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("kw4"),
                        equal=cst.AssignEqual(),
                        value=cst.Integer("4"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(star="**", value=cst.Name("dict2")),
                ),
            ),
            "code":
            "foo(pos1, *list1, pos2, pos3, *list2, pos4, *list3, kw1 = 1, *list4, kw2 = 2, *list5, kw3 = 3, **dict1, kw4 = 4, **dict2)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Test whitespace
        {
            "node":
            cst.Call(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                func=cst.Name("foo"),
                whitespace_after_func=cst.SimpleWhitespace(" "),
                whitespace_before_args=cst.SimpleWhitespace(" "),
                args=(
                    cst.Arg(
                        keyword=None,
                        value=cst.Name("pos1"),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.Arg(
                        star="*",
                        whitespace_after_star=cst.SimpleWhitespace("  "),
                        keyword=None,
                        value=cst.Name("list1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        keyword=cst.Name("kw1"),
                        equal=cst.AssignEqual(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        value=cst.Integer("1"),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.Arg(
                        star="**",
                        keyword=None,
                        whitespace_after_star=cst.SimpleWhitespace(" "),
                        value=cst.Name("dict1"),
                        whitespace_after_arg=cst.SimpleWhitespace(" "),
                    ),
                ),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "code":
            "( foo ( pos1 ,  *  list1, kw1=1, ** dict1 ) )",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 2), (1, 43)),
        },
        # Test args
        {
            "node":
            cst.Arg(
                star="*",
                whitespace_after_star=cst.SimpleWhitespace("  "),
                keyword=None,
                value=cst.Name("list1"),
                comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
            ),
            "code":
            "*  list1, ",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 8)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        # Basic expression parenthesizing tests.
        {
            "get_node":
            lambda: cst.Call(func=cst.Name("foo"), lpar=(cst.LeftParen(), )),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node":
            lambda: cst.Call(func=cst.Name("foo"), rpar=(cst.RightParen(), )),
            "expected_re":
            "right paren without left paren",
        },
        # Test that we handle keyword stuff correctly.
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                args=(cst.Arg(equal=cst.AssignEqual(),
                              value=cst.SimpleString("'baz'")), ),
            ),
            "expected_re":
            "Must have a keyword when specifying an AssignEqual",
        },
        # Test that we separate *, ** and keyword args correctly
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                args=(cst.Arg(
                    star="*",
                    keyword=cst.Name("bar"),
                    value=cst.SimpleString("'baz'"),
                ), ),
            ),
            "expected_re":
            "Cannot specify a star and a keyword together",
        },
        # Test for expected star inputs only
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                # pyre-ignore: Ignore type on 'star' since we're testing behavior
                # when somebody isn't using a type checker.
                args=(cst.Arg(star="***", value=cst.SimpleString("'baz'")), ),
            ),
            "expected_re":
            r"Must specify either '', '\*' or '\*\*' for star",
        },
        # Test ordering exceptions
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                args=(
                    cst.Arg(star="**", value=cst.Name("bar")),
                    cst.Arg(star="*", value=cst.Name("baz")),
                ),
            ),
            "expected_re":
            "Cannot have iterable argument unpacking after keyword argument unpacking",
        },
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                args=(
                    cst.Arg(star="**", value=cst.Name("bar")),
                    cst.Arg(value=cst.Name("baz")),
                ),
            ),
            "expected_re":
            "Cannot have positional argument after keyword argument unpacking",
        },
        {
            "get_node":
            lambda: cst.Call(
                func=cst.Name("foo"),
                args=(
                    cst.Arg(keyword=cst.Name("arg"),
                            value=cst.SimpleString("'baz'")),
                    cst.Arg(value=cst.SimpleString("'bar'")),
                ),
            ),
            "expected_re":
            "Cannot have positional argument after keyword argument",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #18
0
class ImportFromParseTest(CSTNodeTest):
    @data_provider(
        (
            # Simple from import statement
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"), names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "code": "from foo import bar",
            },
            # From import statement with alias
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                ),
                "code": "from foo import bar as baz",
            },
            # Multiple imports
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(cst.Name("baz")),
                    ),
                ),
                "code": "from foo import bar, baz",
            },
            # Trailing comma
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(cst.Name("baz"), comma=cst.Comma()),
                    ),
                ),
                "code": "from foo import bar, baz,",
            },
            # Star import statement
            {
                "node": cst.ImportFrom(module=cst.Name("foo"), names=cst.ImportStar()),
                "code": "from foo import *",
            },
            # Simple relative import statement
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(),),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .foo import bar",
            },
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from ..foo import bar",
            },
            # Relative only import
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=None,
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .. import bar",
            },
            # Parenthesis
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                    rpar=cst.RightParen(),
                ),
                "code": "from foo import (bar as baz)",
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.ImportFrom(
                    relative=(
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
                    whitespace_after_from=cst.SimpleWhitespace("   "),
                    whitespace_before_import=cst.SimpleWhitespace("  "),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "from   .  . foo  import  ( bar  as  baz ,  unittest  as  ut )",
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(
            parser=lambda code: ensure_type(
                parse_statement(code), cst.SimpleStatementLine
            ).body[0],
            **kwargs,
        )
예제 #19
0
class ImportFromCreateTest(CSTNodeTest):
    @data_provider(
        (
            # Simple from import statement
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"), names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "code": "from foo import bar",
            },
            # From import statement with alias
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                ),
                "code": "from foo import bar as baz",
            },
            # Multiple imports
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(cst.Name("bar")),
                        cst.ImportAlias(cst.Name("baz")),
                    ),
                ),
                "code": "from foo import bar, baz",
            },
            # Trailing comma
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(cst.Name("bar"), comma=cst.Comma()),
                        cst.ImportAlias(cst.Name("baz"), comma=cst.Comma()),
                    ),
                ),
                "code": "from foo import bar,baz,",
                "expected_position": CodeRange((1, 0), (1, 23)),
            },
            # Star import statement
            {
                "node": cst.ImportFrom(module=cst.Name("foo"), names=cst.ImportStar()),
                "code": "from foo import *",
                "expected_position": CodeRange((1, 0), (1, 17)),
            },
            # Simple relative import statement
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(),),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .foo import bar",
            },
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from ..foo import bar",
            },
            # Relative only import
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=None,
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .. import bar",
            },
            # Parenthesis
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                    rpar=cst.RightParen(),
                ),
                "code": "from foo import (bar as baz)",
                "expected_position": CodeRange((1, 0), (1, 28)),
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.ImportFrom(
                    relative=(
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
                    whitespace_after_from=cst.SimpleWhitespace("  "),
                    whitespace_before_import=cst.SimpleWhitespace("  "),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "from   .  . foo  import  ( bar  as  baz ,  unittest  as  ut )",
                "expected_position": CodeRange((1, 0), (1, 61)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": lambda: cst.ImportFrom(
                    module=None, names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "expected_re": "Must have a module specified",
            },
            {
                "get_node": lambda: cst.ImportFrom(module=cst.Name("foo"), names=()),
                "expected_re": "at least one ImportAlias",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    lpar=cst.LeftParen(),
                ),
                "expected_re": "left paren without right paren",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    rpar=cst.RightParen(),
                ),
                "expected_re": "right paren without left paren",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"), names=cst.ImportStar(), lpar=cst.LeftParen()
                ),
                "expected_re": "cannot have parens",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=cst.ImportStar(),
                    rpar=cst.RightParen(),
                ),
                "expected_re": "cannot have parens",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_after_from=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space after from",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_before_import=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space before import",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_after_import=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space after import",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #20
0
class ImportParseTest(CSTNodeTest):
    @data_provider(
        (
            # Simple import statement
            {
                "node": cst.Import(names=(cst.ImportAlias(cst.Name("foo")),)),
                "code": "import foo",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            # Comma-separated list of imports
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz"))
                        ),
                    )
                ),
                "code": "import foo.bar, foo.baz",
            },
            # Import with an alias
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz",
            },
            # Import with an alias, comma separated
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz")),
                            asname=cst.AsName(cst.Name("bar")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz, foo.baz as bar",
            },
            # Combine for fun and profit
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("insta"), cst.Name("gram")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"), asname=cst.AsName(cst.Name("ut"))
                        ),
                    )
                ),
                "code": "import foo.bar as baz, insta.gram, foo.baz, unittest as ut",
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(
                                cst.Name("foo"),
                                cst.Name("bar"),
                                dot=cst.Dot(
                                    whitespace_before=cst.SimpleWhitespace(" "),
                                    whitespace_after=cst.SimpleWhitespace(" "),
                                ),
                            ),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "import  foo . bar  as  baz ,  unittest  as  ut",
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(
            parser=lambda code: ensure_type(
                parse_statement(code), cst.SimpleStatementLine
            ).body[0],
            **kwargs,
        )
예제 #21
0
class NonlocalConstructionTest(CSTNodeTest):
    @data_provider((
        # Single nonlocal statement
        {
            "node": cst.Nonlocal((cst.NameItem(cst.Name("a")), )),
            "code": "nonlocal a",
        },
        # Multiple entries in nonlocal statement
        {
            "node":
            cst.Nonlocal(
                (cst.NameItem(cst.Name("a")), cst.NameItem(cst.Name("b")))),
            "code":
            "nonlocal a, b",
            "expected_position":
            CodeRange((1, 0), (1, 13)),
        },
        # Whitespace rendering test
        {
            "node":
            cst.Nonlocal(
                (
                    cst.NameItem(
                        cst.Name("a"),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace("  "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.NameItem(cst.Name("b")),
                ),
                whitespace_after_nonlocal=cst.SimpleWhitespace("  "),
            ),
            "code":
            "nonlocal  a  ,  b",
            "expected_position":
            CodeRange((1, 0), (1, 17)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        # Validate construction
        {
            "get_node": lambda: cst.Nonlocal(()),
            "expected_re":
            "A Nonlocal statement must have at least one NameItem",
        },
        # Validate whitespace handling
        {
            "get_node":
            lambda: cst.Nonlocal(
                (cst.NameItem(cst.Name("a")), ),
                whitespace_after_nonlocal=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after 'nonlocal' keyword",
        },
        # Validate comma handling
        {
            "get_node":
            lambda: cst.Nonlocal(
                (cst.NameItem(cst.Name("a"), comma=cst.Comma()), )),
            "expected_re":
            "The last NameItem in a Nonlocal cannot have a trailing comma",
        },
        # Validate paren handling
        {
            "get_node":
            lambda: cst.Nonlocal((cst.NameItem(
                cst.Name("a",
                         lpar=(cst.LeftParen(), ),
                         rpar=(cst.RightParen(), ))), )),
            "expected_re":
            "Cannot have parens around names in NameItem",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
예제 #22
0
class SubscriptTest(CSTNodeTest):
    @data_provider((
        # Simple subscript expression
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
            ),
            "foo[5]",
            True,
        ),
        # Test creation of subscript with slice/extslice.
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=cst.Integer("2"),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1:2:3]",
            False,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (
                    cst.SubscriptElement(
                        cst.Slice(
                            lower=cst.Integer("1"),
                            upper=cst.Integer("2"),
                            step=cst.Integer("3"),
                        )),
                    cst.SubscriptElement(cst.Index(cst.Integer("5"))),
                ),
            ),
            "foo[1:2:3, 5]",
            False,
            CodeRange((1, 0), (1, 13)),
        ),
        # Test parsing of subscript with slice/extslice.
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        first_colon=cst.Colon(),
                        upper=cst.Integer("2"),
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1:2:3]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (
                    cst.SubscriptElement(
                        cst.Slice(
                            lower=cst.Integer("1"),
                            first_colon=cst.Colon(),
                            upper=cst.Integer("2"),
                            second_colon=cst.Colon(),
                            step=cst.Integer("3"),
                        ),
                        comma=cst.Comma(),
                    ),
                    cst.SubscriptElement(cst.Index(cst.Integer("5"))),
                ),
            ),
            "foo[1:2:3,5]",
            True,
        ),
        # Some more wild slice creations
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"),
                              upper=cst.Integer("2"))), ),
            ),
            "foo[1:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"), upper=None)), ),
            ),
            "foo[1:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=cst.Integer("2"))), ),
            ),
            "foo[:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=None,
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1::3]",
            False,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=None,
                              step=cst.Integer("3"))), ),
            ),
            "foo[::3]",
            False,
            CodeRange((1, 0), (1, 8)),
        ),
        # Some more wild slice parsings
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"),
                              upper=cst.Integer("2"))), ),
            ),
            "foo[1:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"), upper=None)), ),
            ),
            "foo[1:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=cst.Integer("2"))), ),
            ),
            "foo[:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=None,
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1::3]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[::3]",
            True,
        ),
        # Valid list clone operations rendering
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Slice(lower=None, upper=None)), ),
            ),
            "foo[:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=None,
                    )), ),
            ),
            "foo[::]",
            True,
        ),
        # Valid list clone operations parsing
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Slice(lower=None, upper=None)), ),
            ),
            "foo[:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=None,
                    )), ),
            ),
            "foo[::]",
            True,
        ),
        # In parenthesis
        (
            cst.Subscript(
                lpar=(cst.LeftParen(), ),
                value=cst.Name("foo"),
                slice=(cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                rpar=(cst.RightParen(), ),
            ),
            "(foo[5])",
            True,
        ),
        # Verify spacing
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 5 ] )",
            True,
        ),
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        first_colon=cst.Colon(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        upper=cst.Integer("2"),
                        second_colon=cst.Colon(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        step=cst.Integer("3"),
                    )), ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 1 : 2 : 3 ] )",
            True,
        ),
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(
                    cst.SubscriptElement(
                        slice=cst.Slice(
                            lower=cst.Integer("1"),
                            first_colon=cst.Colon(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace(" "),
                            ),
                            upper=cst.Integer("2"),
                            second_colon=cst.Colon(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace(" "),
                            ),
                            step=cst.Integer("3"),
                        ),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.SubscriptElement(slice=cst.Index(cst.Integer("5"))),
                ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 1 : 2 : 3 ,  5 ] )",
            True,
            CodeRange((1, 2), (1, 24)),
        ),
        # Test Index, Slice, SubscriptElement
        (cst.Index(cst.Integer("5")), "5", False, CodeRange((1, 0), (1, 1))),
        (
            cst.Slice(lower=None,
                      upper=None,
                      second_colon=cst.Colon(),
                      step=None),
            "::",
            False,
            CodeRange((1, 0), (1, 2)),
        ),
        (
            cst.SubscriptElement(
                slice=cst.Slice(
                    lower=cst.Integer("1"),
                    first_colon=cst.Colon(
                        whitespace_before=cst.SimpleWhitespace(" "),
                        whitespace_after=cst.SimpleWhitespace(" "),
                    ),
                    upper=cst.Integer("2"),
                    second_colon=cst.Colon(
                        whitespace_before=cst.SimpleWhitespace(" "),
                        whitespace_after=cst.SimpleWhitespace(" "),
                    ),
                    step=cst.Integer("3"),
                ),
                comma=cst.Comma(
                    whitespace_before=cst.SimpleWhitespace(" "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                ),
            ),
            "1 : 2 : 3 ,  ",
            False,
            CodeRange((1, 0), (1, 9)),
        ),
    ))
    def test_valid(
        self,
        node: cst.CSTNode,
        code: str,
        check_parsing: bool,
        position: Optional[CodeRange] = None,
    ) -> None:
        if check_parsing:
            self.validate_node(node,
                               code,
                               parse_expression,
                               expected_position=position)
        else:
            self.validate_node(node, code, expected_position=position)

    @data_provider((
        (
            lambda: cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                lpar=(cst.LeftParen(), ),
            ),
            "left paren without right paren",
        ),
        (
            lambda: cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                rpar=(cst.RightParen(), ),
            ),
            "right paren without left paren",
        ),
        (lambda: cst.Subscript(cst.Name("foo"), ()), "empty SubscriptElement"),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
예제 #23
0
class ListTest(CSTNodeTest):

    # A lot of Element/StarredElement tests are provided by the tests for Tuple, so we
    # we don't need to duplicate them here.
    @data_provider([
        # one-element list, sentinel comma value
        {
            "node": cst.Set([cst.Element(cst.Name("single_element"))]),
            "code": "{single_element}",
            "parser": parse_expression,
        },
        # custom whitespace between brackets
        {
            "node":
            cst.Set(
                [cst.Element(cst.Name("single_element"))],
                lbrace=cst.LeftCurlyBrace(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbrace=cst.RightCurlyBrace(
                    whitespace_before=cst.SimpleWhitespace("    ")),
            ),
            "code":
            "{\tsingle_element    }",
            "parser":
            parse_expression,
        },
        # two-element list, sentinel comma value
        {
            "node":
            cst.Set(
                [cst.Element(cst.Name("one")),
                 cst.Element(cst.Name("two"))]),
            "code":
            "{one, two}",
            "parser":
            None,
        },
        # with parenthesis
        {
            "node":
            cst.Set(
                [cst.Element(cst.Name("one"))],
                lpar=[cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "code":
            "({one})",
            "parser":
            None,
        },
        # starred element
        {
            "node":
            cst.Set([
                cst.StarredElement(cst.Name("one")),
                cst.StarredElement(cst.Name("two")),
            ]),
            "code":
            "{*one, *two}",
            "parser":
            None,
        },
        # missing spaces around set, always okay
        {
            "node":
            cst.GeneratorExp(
                cst.Name("elt"),
                cst.CompFor(
                    target=cst.Name("elt"),
                    iter=cst.Set([
                        cst.Element(
                            cst.Name("one"),
                            cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Element(cst.Name("two")),
                    ]),
                    ifs=[
                        cst.CompIf(
                            cst.Name("test"),
                            whitespace_before=cst.SimpleWhitespace(""),
                        )
                    ],
                    whitespace_after_in=cst.SimpleWhitespace(""),
                ),
            ),
            "code":
            "(elt for elt in{one, two}if test)",
            "parser":
            parse_expression,
        },
    ])
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        (
            lambda: cst.Set(
                [cst.Element(cst.Name("mismatched"))],
                lpar=[cst.LeftParen(), cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "unbalanced parens",
        ),
        (lambda: cst.Set([]), "at least one element"),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)

    @data_provider((
        {
            "code": "{*x, 2}",
            "parser": parse_expression_as(python_version="3.5"),
            "expect_success": True,
        },
        {
            "code": "{*x, 2}",
            "parser": parse_expression_as(python_version="3.3"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        if is_native() and not kwargs.get("expect_success", True):
            self.skipTest("parse errors are disabled for native parser")
        self.assert_parses(**kwargs)
예제 #24
0
class AtomTest(CSTNodeTest):
    @data_provider((
        # Simple identifier
        {
            "node": cst.Name("test"),
            "code": "test",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Parenthesized identifier
        {
            "node":
            cst.Name("test",
                     lpar=(cst.LeftParen(), ),
                     rpar=(cst.RightParen(), )),
            "code":
            "(test)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 5)),
        },
        # Decimal integers
        {
            "node": cst.Integer("12345"),
            "code": "12345",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("0000"),
            "code": "0000",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("1_234_567"),
            "code": "1_234_567",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("0_000"),
            "code": "0_000",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Binary integers
        {
            "node": cst.Integer("0b0000"),
            "code": "0b0000",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("0B1011_0100"),
            "code": "0B1011_0100",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Octal integers
        {
            "node": cst.Integer("0o12345"),
            "code": "0o12345",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("0O12_345"),
            "code": "0O12_345",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Hex numbers
        {
            "node": cst.Integer("0x123abc"),
            "code": "0x123abc",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Integer("0X12_3ABC"),
            "code": "0X12_3ABC",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Parenthesized integers
        {
            "node":
            cst.Integer("123",
                        lpar=(cst.LeftParen(), ),
                        rpar=(cst.RightParen(), )),
            "code":
            "(123)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 4)),
        },
        # Non-exponent floats
        {
            "node": cst.Float("12345."),
            "code": "12345.",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("00.00"),
            "code": "00.00",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("12.21"),
            "code": "12.21",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float(".321"),
            "code": ".321",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("1_234_567."),
            "code": "1_234_567.",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("0.000_000"),
            "code": "0.000_000",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Exponent floats
        {
            "node": cst.Float("12345.e10"),
            "code": "12345.e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("00.00e10"),
            "code": "00.00e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("12.21e10"),
            "code": "12.21e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float(".321e10"),
            "code": ".321e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("1_234_567.e10"),
            "code": "1_234_567.e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("0.000_000e10"),
            "code": "0.000_000e10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("1e+10"),
            "code": "1e+10",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Float("1e-10"),
            "code": "1e-10",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Parenthesized floats
        {
            "node":
            cst.Float("123.4",
                      lpar=(cst.LeftParen(), ),
                      rpar=(cst.RightParen(), )),
            "code":
            "(123.4)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 6)),
        },
        # Imaginary numbers
        {
            "node": cst.Imaginary("12345j"),
            "code": "12345j",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Imaginary("1_234_567J"),
            "code": "1_234_567J",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Imaginary("12345.e10j"),
            "code": "12345.e10j",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.Imaginary(".321J"),
            "code": ".321J",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Parenthesized imaginary
        {
            "node":
            cst.Imaginary("123.4j",
                          lpar=(cst.LeftParen(), ),
                          rpar=(cst.RightParen(), )),
            "code":
            "(123.4j)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 7)),
        },
        # Simple elipses
        {
            "node": cst.Ellipsis(),
            "code": "...",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Parenthesized elipses
        {
            "node":
            cst.Ellipsis(lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), )),
            "code":
            "(...)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 4)),
        },
        # Simple strings
        {
            "node": cst.SimpleString('""'),
            "code": '""',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.SimpleString("''"),
            "code": "''",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.SimpleString('"test"'),
            "code": '"test"',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.SimpleString('b"test"'),
            "code": 'b"test"',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.SimpleString('r"test"'),
            "code": 'r"test"',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.SimpleString('"""test"""'),
            "code": '"""test"""',
            "parser": parse_expression,
            "expected_position": None,
        },
        # Validate parens
        {
            "node":
            cst.SimpleString('"test"',
                             lpar=(cst.LeftParen(), ),
                             rpar=(cst.RightParen(), )),
            "code":
            '("test")',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.SimpleString('rb"test"',
                             lpar=(cst.LeftParen(), ),
                             rpar=(cst.RightParen(), )),
            "code":
            '(rb"test")',
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 9)),
        },
        # Test that _safe_to_use_with_word_operator allows no space around quotes
        {
            "node":
            cst.Comparison(
                cst.SimpleString('"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.SimpleString('"abc"'),
                    )
                ],
            ),
            "code":
            '"a"in"abc"',
            "parser":
            parse_expression,
        },
        {
            "node":
            cst.Comparison(
                cst.SimpleString('"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.ConcatenatedString(cst.SimpleString('"a"'),
                                               cst.SimpleString('"bc"')),
                    )
                ],
            ),
            "code":
            '"a"in"a""bc"',
            "parser":
            parse_expression,
        },
        # Parenthesis make no spaces around a prefix okay
        {
            "node":
            cst.Comparison(
                cst.SimpleString('b"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.SimpleString(
                            'b"abc"',
                            lpar=[cst.LeftParen()],
                            rpar=[cst.RightParen()],
                        ),
                    )
                ],
            ),
            "code":
            'b"a"in(b"abc")',
            "parser":
            parse_expression,
        },
        {
            "node":
            cst.Comparison(
                cst.SimpleString('b"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.ConcatenatedString(
                            cst.SimpleString('b"a"'),
                            cst.SimpleString('b"bc"'),
                            lpar=[cst.LeftParen()],
                            rpar=[cst.RightParen()],
                        ),
                    )
                ],
            ),
            "code":
            'b"a"in(b"a"b"bc")',
            "parser":
            parse_expression,
        },
        # Empty formatted strings
        {
            "node": cst.FormattedString(start='f"', parts=(), end='"'),
            "code": 'f""',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.FormattedString(start="f'", parts=(), end="'"),
            "code": "f''",
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.FormattedString(start='f"""', parts=(), end='"""'),
            "code": 'f""""""',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node": cst.FormattedString(start="f'''", parts=(), end="'''"),
            "code": "f''''''",
            "parser": parse_expression,
            "expected_position": None,
        },
        # Non-empty formatted strings
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringText("foo"), )),
            "code": 'f"foo"',
            "parser": parse_expression,
            "expected_position": None,
        },
        {
            "node":
            cst.FormattedString(
                parts=(cst.FormattedStringExpression(cst.Name("foo")), )),
            "code":
            'f"{foo}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(
                cst.FormattedStringText("foo "),
                cst.FormattedStringExpression(cst.Name("bar")),
                cst.FormattedStringText(" baz"),
            )),
            "code":
            'f"foo {bar} baz"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(
                cst.FormattedStringText("foo "),
                cst.FormattedStringExpression(cst.Call(cst.Name("bar"))),
                cst.FormattedStringText(" baz"),
            )),
            "code":
            'f"foo {bar()} baz"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Formatted strings with conversions and format specifiers
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"), conversion="s"), )),
            "code":
            'f"{foo!s}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"), format_spec=()), )),
            "code":
            'f"{foo:}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("today"),
                format_spec=(cst.FormattedStringText("%B %d, %Y"), ),
            ), )),
            "code":
            'f"{today:%B %d, %Y}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                format_spec=(cst.FormattedStringExpression(cst.Name("bar")), ),
            ), )),
            "code":
            'f"{foo:{bar}}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                format_spec=(
                    cst.FormattedStringExpression(cst.Name("bar")),
                    cst.FormattedStringText("."),
                    cst.FormattedStringExpression(cst.Name("baz")),
                ),
            ), )),
            "code":
            'f"{foo:{bar}.{baz}}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                conversion="s",
                format_spec=(cst.FormattedStringExpression(cst.Name("bar")), ),
            ), )),
            "code":
            'f"{foo!s:{bar}}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Test equality expression added in 3.8.
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                equal=cst.AssignEqual(
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after=cst.SimpleWhitespace(""),
                ),
            ), ), ),
            "code":
            'f"{foo=}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                equal=cst.AssignEqual(
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after=cst.SimpleWhitespace(""),
                ),
                conversion="s",
            ), ), ),
            "code":
            'f"{foo=!s}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Name("foo"),
                equal=cst.AssignEqual(
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after=cst.SimpleWhitespace(""),
                ),
                conversion="s",
                format_spec=(cst.FormattedStringExpression(cst.Name("bar")), ),
            ), ), ),
            "code":
            'f"{foo=!s:{bar}}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        # Test that equality support doesn't break existing support
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Comparison(
                    left=cst.Name(value="a", ),
                    comparisons=[
                        cst.ComparisonTarget(
                            operator=cst.Equal(),
                            comparator=cst.Name(value="b", ),
                        ),
                    ],
                ), ), ), ),
            "code":
            'f"{a == b}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Comparison(
                    left=cst.Name(value="a", ),
                    comparisons=[
                        cst.ComparisonTarget(
                            operator=cst.NotEqual(),
                            comparator=cst.Name(value="b", ),
                        ),
                    ],
                ), ), ), ),
            "code":
            'f"{a != b}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.NamedExpr(
                    target=cst.Name(value="a", ),
                    value=cst.Integer(value="5", ),
                    lpar=(cst.LeftParen(), ),
                    rpar=(cst.RightParen(), ),
                ), ), ), ),
            "code":
            'f"{(a := 5)}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(cst.FormattedStringExpression(
                cst.Yield(
                    value=cst.Integer("1"),
                    whitespace_after_yield=cst.SimpleWhitespace(" "),
                ), ), ), ),
            "code":
            'f"{yield 1}"',
            "parser":
            _parse_expression_force_38,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(parts=(
                cst.FormattedStringText("\\N{X Y}"),
                cst.FormattedStringExpression(cst.Name(value="Z"), ),
            ), ),
            "code":
            'f"\\N{X Y}{Z}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.FormattedString(
                parts=(
                    cst.FormattedStringText("\\"),
                    cst.FormattedStringExpression(cst.Name(value="a"), ),
                ),
                start='fr"',
            ),
            "code":
            'fr"\\{a}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Validate parens
        {
            "node":
            cst.FormattedString(
                start='f"',
                parts=(),
                end='"',
                lpar=(cst.LeftParen(), ),
                rpar=(cst.RightParen(), ),
            ),
            "code":
            '(f"")',
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 4)),
        },
        # Generator expression (doesn't make sense, but legal syntax)
        {
            "node":
            cst.FormattedString(
                start='f"',
                parts=[
                    cst.FormattedStringExpression(expression=cst.GeneratorExp(
                        elt=cst.Name(value="x", ),
                        for_in=cst.CompFor(
                            target=cst.Name(value="x", ),
                            iter=cst.Name(value="y", ),
                        ),
                        lpar=[],
                        rpar=[],
                    ), ),
                ],
                end='"',
            ),
            "code":
            'f"{x for x in y}"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Unpacked tuple
        {
            "node":
            cst.FormattedString(
                parts=[
                    cst.FormattedStringExpression(expression=cst.Tuple(
                        elements=[
                            cst.Element(
                                value=cst.Name(value="a", ),
                                comma=cst.Comma(
                                    whitespace_before=cst.SimpleWhitespace(
                                        value="", ),
                                    whitespace_after=cst.SimpleWhitespace(
                                        value=" ", ),
                                ),
                            ),
                            cst.Element(value=cst.Name(value="b", ), ),
                        ],
                        lpar=[],
                        rpar=[],
                    ), ),
                ],
                start="f'",
                end="'",
            ),
            "code":
            "f'{a, b}'",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Conditional expression
        {
            "node":
            cst.FormattedString(
                parts=[
                    cst.FormattedStringExpression(expression=cst.IfExp(
                        test=cst.Name(value="b", ),
                        body=cst.Name(value="a", ),
                        orelse=cst.Name(value="c", ),
                    ), ),
                ],
                start="f'",
                end="'",
            ),
            "code":
            "f'{a if b else c}'",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Concatenated strings
        {
            "node":
            cst.ConcatenatedString(cst.SimpleString('"ab"'),
                                   cst.SimpleString('"c"')),
            "code":
            '"ab""c"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.ConcatenatedString(
                cst.SimpleString('"ab"'),
                cst.ConcatenatedString(cst.SimpleString('"c"'),
                                       cst.SimpleString('"d"')),
            ),
            "code":
            '"ab""c""d"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # mixed SimpleString and FormattedString
        {
            "node":
            cst.ConcatenatedString(
                cst.FormattedString([cst.FormattedStringText("ab")]),
                cst.SimpleString('"c"'),
            ),
            "code":
            'f"ab""c"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.ConcatenatedString(
                cst.SimpleString('"ab"'),
                cst.FormattedString([cst.FormattedStringText("c")]),
            ),
            "code":
            '"ab"f"c"',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Concatenated parenthesized strings
        {
            "node":
            cst.ConcatenatedString(
                lpar=(cst.LeftParen(), ),
                left=cst.SimpleString('"ab"'),
                right=cst.SimpleString('"c"'),
                rpar=(cst.RightParen(), ),
            ),
            "code":
            '("ab""c")',
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Validate spacing
        {
            "node":
            cst.ConcatenatedString(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                left=cst.SimpleString('"ab"'),
                whitespace_between=cst.SimpleWhitespace(" "),
                right=cst.SimpleString('"c"'),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "code":
            '( "ab" "c" )',
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 2), (1, 10)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        # We don't have sentinel nodes for atoms, so we know that 100% of atoms
        # can be parsed identically to their creation.
        self.validate_node(**kwargs)

    @data_provider(({
        "node":
        cst.FormattedStringExpression(
            cst.Name("today"),
            format_spec=(cst.FormattedStringText("%B %d, %Y"), ),
        ),
        "code":
        "{today:%B %d, %Y}",
        "parser":
        None,
        "expected_position":
        CodeRange((1, 0), (1, 17)),
    }, ))
    def test_valid_no_parse(self, **kwargs: Any) -> None:
        # Test some nodes that aren't valid source code by themselves
        self.validate_node(**kwargs)

    @data_provider((
        # Expression wrapping parenthesis rules
        {
            "get_node": (lambda: cst.Name("foo", lpar=(cst.LeftParen(), ))),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node": lambda: cst.Name("foo", rpar=(cst.RightParen(), )),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node": lambda: cst.Ellipsis(lpar=(cst.LeftParen(), )),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node": lambda: cst.Ellipsis(rpar=(cst.RightParen(), )),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node": lambda: cst.Integer("5", lpar=(cst.LeftParen(), )),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node": lambda: cst.Integer("5", rpar=(cst.RightParen(), )),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node": lambda: cst.Float("5.5", lpar=(cst.LeftParen(), )),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node": lambda: cst.Float("5.5", rpar=(cst.RightParen(), )),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node":
            (lambda: cst.Imaginary("5j", lpar=(cst.LeftParen(), ))),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node":
            (lambda: cst.Imaginary("5j", rpar=(cst.RightParen(), ))),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node": (lambda: cst.Integer("5", lpar=(cst.LeftParen(), ))),
            "expected_re": "left paren without right paren",
        },
        {
            "get_node": (lambda: cst.Integer("5", rpar=(cst.RightParen(), ))),
            "expected_re": "right paren without left paren",
        },
        {
            "get_node":
            (lambda: cst.SimpleString("'foo'", lpar=(cst.LeftParen(), ))),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node":
            (lambda: cst.SimpleString("'foo'", rpar=(cst.RightParen(), ))),
            "expected_re":
            "right paren without left paren",
        },
        {
            "get_node":
            (lambda: cst.FormattedString(parts=(), lpar=(cst.LeftParen(), ))),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node":
            (lambda: cst.FormattedString(parts=(), rpar=(cst.RightParen(), ))),
            "expected_re":
            "right paren without left paren",
        },
        {
            "get_node": (lambda: cst.ConcatenatedString(
                cst.SimpleString("'foo'"),
                cst.SimpleString("'foo'"),
                lpar=(cst.LeftParen(), ),
            )),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node": (lambda: cst.ConcatenatedString(
                cst.SimpleString("'foo'"),
                cst.SimpleString("'foo'"),
                rpar=(cst.RightParen(), ),
            )),
            "expected_re":
            "right paren without left paren",
        },
        # Node-specific rules
        {
            "get_node": (lambda: cst.Name("")),
            "expected_re": "empty name identifier",
        },
        {
            "get_node": (lambda: cst.Name(r"\/")),
            "expected_re": "not a valid identifier",
        },
        {
            "get_node": (lambda: cst.Integer("")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("012345")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("012345")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("_12345")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("0b2")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("0o8")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("0xg")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("123.45")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Integer("12345j")),
            "expected_re": "not a valid integer",
        },
        {
            "get_node": (lambda: cst.Float("12.3.45")),
            "expected_re": "not a valid float",
        },
        {
            "get_node": (lambda: cst.Float("12")),
            "expected_re": "not a valid float"
        },
        {
            "get_node": (lambda: cst.Float("12.3j")),
            "expected_re": "not a valid float",
        },
        {
            "get_node": (lambda: cst.Imaginary("_12345j")),
            "expected_re": "not a valid imaginary",
        },
        {
            "get_node": (lambda: cst.Imaginary("0b0j")),
            "expected_re": "not a valid imaginary",
        },
        {
            "get_node": (lambda: cst.Imaginary("0o0j")),
            "expected_re": "not a valid imaginary",
        },
        {
            "get_node": (lambda: cst.Imaginary("0x0j")),
            "expected_re": "not a valid imaginary",
        },
        {
            "get_node": (lambda: cst.SimpleString('wee""')),
            "expected_re": "Invalid string prefix",
        },
        {
            "get_node": (lambda: cst.SimpleString("'")),
            "expected_re": "must have enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString('"')),
            "expected_re": "must have enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString("\"'")),
            "expected_re": "must have matching enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString("")),
            "expected_re": "must have enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString("'bla")),
            "expected_re": "must have matching enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString("f''")),
            "expected_re": "Invalid string prefix",
        },
        {
            "get_node": (lambda: cst.SimpleString("'''bla''")),
            "expected_re": "must have matching enclosing quotes",
        },
        {
            "get_node": (lambda: cst.SimpleString("'''bla\"\"\"")),
            "expected_re": "must have matching enclosing quotes",
        },
        {
            "get_node":
            (lambda: cst.FormattedString(start="'", parts=(), end="'")),
            "expected_re": "Invalid f-string prefix",
        },
        {
            "get_node":
            (lambda: cst.FormattedString(start="f'", parts=(), end='"')),
            "expected_re":
            "must have matching enclosing quotes",
        },
        {
            "get_node": (lambda: cst.ConcatenatedString(
                cst.SimpleString('"ab"',
                                 lpar=(cst.LeftParen(), ),
                                 rpar=(cst.RightParen(), )),
                cst.SimpleString('"c"'),
            )),
            "expected_re":
            "Cannot concatenate parenthesized",
        },
        {
            "get_node": (lambda: cst.ConcatenatedString(
                cst.SimpleString('"ab"'),
                cst.SimpleString('"c"',
                                 lpar=(cst.LeftParen(), ),
                                 rpar=(cst.RightParen(), )),
            )),
            "expected_re":
            "Cannot concatenate parenthesized",
        },
        {
            "get_node": (lambda: cst.ConcatenatedString(
                cst.SimpleString('"ab"'), cst.SimpleString('b"c"'))),
            "expected_re":
            "Cannot concatenate string and bytes",
        },
        # This isn't valid code: `"a" inb"abc"`
        {
            "get_node": (lambda: cst.Comparison(
                cst.SimpleString('"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(whitespace_after=cst.SimpleWhitespace("")),
                        cst.SimpleString('b"abc"'),
                    )
                ],
            )),
            "expected_re":
            "Must have at least one space around comparison operator.",
        },
        # Also not valid: `"a" in b"a"b"bc"`
        {
            "get_node": (lambda: cst.Comparison(
                cst.SimpleString('"a"'),
                [
                    cst.ComparisonTarget(
                        cst.In(whitespace_after=cst.SimpleWhitespace("")),
                        cst.ConcatenatedString(cst.SimpleString('b"a"'),
                                               cst.SimpleString('b"bc"')),
                    )
                ],
            )),
            "expected_re":
            "Must have at least one space around comparison operator.",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)

    @data_provider((
        {
            "code": "u'x'",
            "parser": parse_expression_as(python_version="3.3"),
            "expect_success": True,
        },
        {
            "code": "u'x'",
            "parser": parse_expression_as(python_version="3.1"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        if is_native() and not kwargs.get("expect_success", True):
            self.skipTest("parse errors are disabled for native parser")
        self.assert_parses(**kwargs)
예제 #25
0
class TupleTest(CSTNodeTest):
    @data_provider(
        [
            # zero-element tuple
            {"node": cst.Tuple([]), "code": "()", "parser": parse_expression},
            # one-element tuple, sentinel comma value
            {
                "node": cst.Tuple([cst.Element(cst.Name("single_element"))]),
                "code": "(single_element,)",
                "parser": None,
            },
            {
                "node": cst.Tuple([cst.StarredElement(cst.Name("single_element"))]),
                "code": "(*single_element,)",
                "parser": None,
            },
            # two-element tuple, sentinel comma value
            {
                "node": cst.Tuple(
                    [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))]
                ),
                "code": "(one, two)",
                "parser": None,
            },
            # remove parenthesis
            {
                "node": cst.Tuple(
                    [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))],
                    lpar=[],
                    rpar=[],
                ),
                "code": "one, two",
                "parser": None,
            },
            # add extra parenthesis
            {
                "node": cst.Tuple(
                    [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))],
                    lpar=[cst.LeftParen(), cst.LeftParen()],
                    rpar=[cst.RightParen(), cst.RightParen()],
                ),
                "code": "((one, two))",
                "parser": None,
            },
            # starred element
            {
                "node": cst.Tuple(
                    [
                        cst.StarredElement(cst.Name("one")),
                        cst.StarredElement(cst.Name("two")),
                    ]
                ),
                "code": "(*one, *two)",
                "parser": None,
            },
            # custom comma on Element
            {
                "node": cst.Tuple(
                    [
                        cst.Element(cst.Name("one"), comma=cst.Comma()),
                        cst.Element(cst.Name("two"), comma=cst.Comma()),
                    ]
                ),
                "code": "(one,two,)",
                "parser": parse_expression,
            },
            # custom comma on StarredElement
            {
                "node": cst.Tuple(
                    [
                        cst.StarredElement(cst.Name("one"), comma=cst.Comma()),
                        cst.StarredElement(cst.Name("two"), comma=cst.Comma()),
                    ]
                ),
                "code": "(*one,*two,)",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 1), (1, 11)),
            },
            # custom parenthesis on StarredElement
            {
                "node": cst.Tuple(
                    [
                        cst.StarredElement(
                            cst.Name("abc"),
                            lpar=[cst.LeftParen()],
                            rpar=[cst.RightParen()],
                            comma=cst.Comma(),
                        )
                    ]
                ),
                "code": "((*abc),)",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 1), (1, 8)),
            },
            # custom whitespace on StarredElement
            {
                "node": cst.Tuple(
                    [
                        cst.Element(cst.Name("one"), comma=cst.Comma()),
                        cst.StarredElement(
                            cst.Name("two"),
                            whitespace_before_value=cst.SimpleWhitespace("  "),
                            lpar=[cst.LeftParen()],
                            rpar=[cst.RightParen()],
                        ),
                    ],
                    lpar=[],
                    rpar=[],  # rpar can't own the trailing whitespace if it's not there
                ),
                "code": "one,(*  two)",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 12)),
            },
            # missing spaces around tuple, okay with parenthesis
            {
                "node": cst.For(
                    target=cst.Tuple(
                        [
                            cst.Element(cst.Name("k"), comma=cst.Comma()),
                            cst.Element(cst.Name("v")),
                        ]
                    ),
                    iter=cst.Name("abc"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                ),
                "code": "for(k,v)in abc: pass\n",
                "parser": parse_statement,
            },
            # no spaces around tuple, but using values that are parenthesized
            {
                "node": cst.For(
                    target=cst.Tuple(
                        [
                            cst.Element(
                                cst.Name(
                                    "k", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]
                                ),
                                comma=cst.Comma(),
                            ),
                            cst.Element(
                                cst.Name(
                                    "v", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]
                                )
                            ),
                        ],
                        lpar=[],
                        rpar=[],
                    ),
                    iter=cst.Name("abc"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                ),
                "code": "for(k),(v)in abc: pass\n",
                "parser": parse_statement,
            },
            # starred elements are safe to use without a space before them
            {
                "node": cst.For(
                    target=cst.Tuple(
                        [cst.StarredElement(cst.Name("foo"), comma=cst.Comma())],
                        lpar=[],
                        rpar=[],
                    ),
                    iter=cst.Name("bar"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                ),
                "code": "for*foo, in bar: pass\n",
                "parser": parse_statement,
            },
            # a trailing comma doesn't mess up TrailingWhitespace
            {
                "node": cst.SimpleStatementLine(
                    [
                        cst.Expr(
                            cst.Tuple(
                                [
                                    cst.Element(cst.Name("one"), comma=cst.Comma()),
                                    cst.Element(cst.Name("two"), comma=cst.Comma()),
                                ],
                                lpar=[],
                                rpar=[],
                            )
                        )
                    ],
                    trailing_whitespace=cst.TrailingWhitespace(
                        whitespace=cst.SimpleWhitespace("  "),
                        comment=cst.Comment("# comment"),
                    ),
                ),
                "code": "one,two,  # comment\n",
                "parser": parse_statement,
            },
        ]
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            (
                lambda: cst.Tuple([], lpar=[], rpar=[]),
                "A zero-length tuple must be wrapped in parentheses.",
            ),
            (
                lambda: cst.Tuple(
                    [cst.Element(cst.Name("mismatched"))],
                    lpar=[cst.LeftParen(), cst.LeftParen()],
                    rpar=[cst.RightParen()],
                ),
                "unbalanced parens",
            ),
            (
                lambda: cst.For(
                    target=cst.Tuple([cst.Element(cst.Name("el"))], lpar=[], rpar=[]),
                    iter=cst.Name("it"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                ),
                "Must have at least one space after 'for' keyword.",
            ),
            (
                lambda: cst.For(
                    target=cst.Tuple([cst.Element(cst.Name("el"))], lpar=[], rpar=[]),
                    iter=cst.Name("it"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                ),
                "Must have at least one space before 'in' keyword.",
            ),
            # an additional check for StarredElement, since it's a separate codepath
            (
                lambda: cst.For(
                    target=cst.Tuple(
                        [cst.StarredElement(cst.Name("el"))], lpar=[], rpar=[]
                    ),
                    iter=cst.Name("it"),
                    body=cst.SimpleStatementSuite([cst.Pass()]),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                ),
                "Must have at least one space before 'in' keyword.",
            ),
        )
    )
    def test_invalid(
        self, get_node: Callable[[], cst.CSTNode], expected_re: str
    ) -> None:
        self.assert_invalid(get_node, expected_re)
예제 #26
0
class WithTest(CSTNodeTest):
    maxDiff: int = 2000

    @data_provider((
        # Simple with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 24)),
        },
        # Simple async with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.7")),
        },
        # Python 3.6 async with block
        {
            "node":
            cst.FunctionDef(
                cst.Name("foo"),
                cst.Parameters(),
                cst.IndentedBlock((cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    asynchronous=cst.Asynchronous(),
                ), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async def foo():\n    async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.6")),
        },
        # Multiple context managers
        {
            "node":
            cst.With(
                (
                    cst.WithItem(cst.Call(cst.Name("foo"))),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            None,
        },
        {
            "node":
            cst.With(
                (
                    cst.WithItem(
                        cst.Call(cst.Name("foo")),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            parse_statement,
        },
        # With block containing variable for context manager.
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(cst.Name("ctx")),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr() as ctx: pass\n",
            "parser":
            parse_statement,
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                ),
            ),
            "code":
            "    with context_mgr(): pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (1, 28)),
        },
        # with an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    with context_mgr():\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nwith context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((2, 0), (2, 24)),
        },
        # Whitespace
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(
                        cst.Name("ctx"),
                        whitespace_before_as=cst.SimpleWhitespace("  "),
                        whitespace_after_as=cst.SimpleWhitespace("  "),
                    ),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace("  "),
                whitespace_before_colon=cst.SimpleWhitespace("  "),
            ),
            "code":
            "with  context_mgr()  as  ctx  : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 36)),
        },
        # Weird spacing rules, that parse differently depending on whether
        # we are using a grammar that included parenthesized with statements.
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(
                        cst.Name("context_mgr"),
                        lpar=() if is_native() else (cst.LeftParen(), ),
                        rpar=() if is_native() else (cst.RightParen(), ),
                    )), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=(cst.LeftParen()
                      if is_native() else MaybeSentinel.DEFAULT),
                rpar=(cst.RightParen()
                      if is_native() else MaybeSentinel.DEFAULT),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "code":
            "with(context_mgr()): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 25)),
        },
        # Multi-line parenthesized with.
        {
            "node":
            cst.With(
                (
                    cst.WithItem(
                        cst.Call(cst.Name("foo")),
                        comma=cst.
                        Comma(whitespace_after=cst.ParenthesizedWhitespace(
                            first_line=cst.TrailingWhitespace(
                                whitespace=cst.SimpleWhitespace(value="", ),
                                comment=None,
                                newline=cst.Newline(value=None, ),
                            ),
                            empty_lines=[],
                            indent=True,
                            last_line=cst.SimpleWhitespace(value="       ", ),
                        )),
                    ),
                    cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
                rpar=cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")),
            ),
            "code": ("with ( foo(),\n"
                     "       bar(), ): pass\n"),  # noqa
            "parser":
            parse_statement if is_native() else None,
            "expected_position":
            CodeRange((1, 0), (2, 21)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node":
            lambda: cst.With((),
                             cst.IndentedBlock((cst.SimpleStatementLine(
                                 (cst.Pass(), )), ))),
            "expected_re":
            "A With statement must have at least one WithItem",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("foo")),
                    comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")
                                    ),
                ), ),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
            ),
            "expected_re":
            "The last WithItem in an unparenthesized With cannot " +
            "have a trailing comma.",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after with keyword",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
                lpar=cst.LeftParen(),
            ),
            "expected_re":
            "Do not mix concrete LeftParen/RightParen with " + "MaybeSentinel",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
                rpar=cst.RightParen(),
            ),
            "expected_re":
            "Do not mix concrete LeftParen/RightParen with " + "MaybeSentinel",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)

    @data_provider((
        {
            "code": "with a, b: pass",
            "parser": parse_statement_as(python_version="3.1"),
            "expect_success": True,
        },
        {
            "code": "with a, b: pass",
            "parser": parse_statement_as(python_version="3.0"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        if is_native() and not kwargs.get("expect_success", True):
            self.skipTest("parse errors are disabled for native parser")
        self.assert_parses(**kwargs)

    def test_adding_parens(self) -> None:
        node = cst.With(
            (
                cst.WithItem(
                    cst.Call(cst.Name("foo")),
                    comma=cst.Comma(
                        whitespace_after=cst.ParenthesizedWhitespace(), ),
                ),
                cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()),
            ),
            cst.SimpleStatementSuite((cst.Pass(), )),
            lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
            rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
        )
        module = cst.Module([])
        self.assertEqual(
            module.code_for_node(node),
            ("with ( foo(),\n"
             "bar(), ): pass\n")  # noqa
        )
예제 #27
0
def import_to_node_multi(imp: SortableImport,
                         module: cst.Module) -> cst.BaseStatement:
    body: List[cst.BaseSmallStatement] = []
    names: List[cst.ImportAlias] = []
    prev: Optional[cst.ImportAlias] = None
    following: List[str] = []
    lpar_lines: List[cst.EmptyLine] = []
    lpar_inline: cst.TrailingWhitespace = cst.TrailingWhitespace()

    item_count = len(imp.items)
    for idx, item in enumerate(imp.items):
        name = name_to_node(item.name)
        asname = cst.AsName(
            name=cst.Name(item.asname)) if item.asname else None

        # Leading comments actually have to be trailing comments on the previous node.
        # That means putting them on the lpar node for the first item
        if item.comments.before:
            lines = [
                cst.EmptyLine(
                    indent=True,
                    comment=cst.Comment(c),
                    whitespace=cst.SimpleWhitespace(module.default_indent),
                ) for c in item.comments.before
            ]
            if prev is None:
                lpar_lines.extend(lines)
            else:
                prev.comma.whitespace_after.empty_lines.extend(
                    lines)  # type: ignore

        # all items except the last needs whitespace to indent the *next* line/item
        indent = idx != (len(imp.items) - 1)

        first_line = cst.TrailingWhitespace()
        inline = COMMENT_INDENT.join(item.comments.inline)
        if inline:
            first_line = cst.TrailingWhitespace(
                whitespace=cst.SimpleWhitespace(COMMENT_INDENT),
                comment=cst.Comment(inline),
            )

        if idx == item_count - 1:
            following = item.comments.following + imp.comments.final
        else:
            following = item.comments.following

        after = cst.ParenthesizedWhitespace(
            indent=True,
            first_line=first_line,
            empty_lines=[
                cst.EmptyLine(
                    indent=True,
                    comment=cst.Comment(c),
                    whitespace=cst.SimpleWhitespace(module.default_indent),
                ) for c in following
            ],
            last_line=cst.SimpleWhitespace(
                module.default_indent if indent else ""),
        )

        node = cst.ImportAlias(
            name=name,
            asname=asname,
            comma=cst.Comma(whitespace_after=after),
        )
        names.append(node)
        prev = node

    # from foo import (
    #     bar
    # )
    if imp.stem:
        stem, ndots = split_relative(imp.stem)
        if not stem:
            module_name = None
        else:
            module_name = name_to_node(stem)
        relative = (cst.Dot(), ) * ndots

        # inline comment following lparen
        if imp.comments.first_inline:
            inline = COMMENT_INDENT.join(imp.comments.first_inline)
            lpar_inline = cst.TrailingWhitespace(
                whitespace=cst.SimpleWhitespace(COMMENT_INDENT),
                comment=cst.Comment(inline),
            )

        body = [
            cst.ImportFrom(
                module=module_name,
                names=names,
                relative=relative,
                lpar=cst.LeftParen(
                    whitespace_after=cst.ParenthesizedWhitespace(
                        indent=True,
                        first_line=lpar_inline,
                        empty_lines=lpar_lines,
                        last_line=cst.SimpleWhitespace(module.default_indent),
                    ), ),
                rpar=cst.RightParen(),
            )
        ]

    # import foo
    else:
        raise ValueError("can't render basic imports on multiple lines")

    # comment lines above import
    leading_lines = [
        cst.EmptyLine(indent=True, comment=cst.Comment(line))
        if line.startswith("#") else cst.EmptyLine(indent=False)
        for line in imp.comments.before
    ]

    # inline comments following import/rparen
    if imp.comments.last_inline:
        inline = COMMENT_INDENT.join(imp.comments.last_inline)
        trailing = cst.TrailingWhitespace(
            whitespace=cst.SimpleWhitespace(COMMENT_INDENT),
            comment=cst.Comment(inline))
    else:
        trailing = cst.TrailingWhitespace()

    return cst.SimpleStatementLine(
        body=body,
        leading_lines=leading_lines,
        trailing_whitespace=trailing,
    )
예제 #28
0
class MatchTest(CSTNodeTest):
    @data_provider(
        (
            # Values and singletons
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchSingleton(cst.Name("None")),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchValue(cst.SimpleString('"foo"')),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": "match x:\n"
                + "    case None: pass\n"
                + '    case "foo": pass\n',
                "parser": parser,
            },
            # Parenthesized value
            {
                "node": cst.Match(
                    subject=cst.Name(
                        value="x",
                    ),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchAs(
                                pattern=cst.MatchValue(
                                    value=cst.Integer(
                                        value="1",
                                        lpar=[
                                            cst.LeftParen(),
                                        ],
                                        rpar=[
                                            cst.RightParen(),
                                        ],
                                    ),
                                ),
                                name=cst.Name(
                                    value="z",
                                ),
                                whitespace_before_as=cst.SimpleWhitespace(" "),
                                whitespace_after_as=cst.SimpleWhitespace(" "),
                            ),
                            body=cst.SimpleStatementSuite([cst.Pass()]),
                        ),
                    ],
                ),
                "code": "match x:\n    case (1) as z: pass\n",
                "parser": parser,
            },
            # List patterns
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(  # empty list
                            pattern=cst.MatchList(
                                [],
                                lbracket=cst.LeftSquareBracket(),
                                rbracket=cst.RightSquareBracket(),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single element list
                            pattern=cst.MatchList(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None"))
                                    )
                                ],
                                lbracket=cst.LeftSquareBracket(),
                                rbracket=cst.RightSquareBracket(),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single element list with trailing comma
                            pattern=cst.MatchList(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    )
                                ],
                                lbracket=cst.LeftSquareBracket(),
                                rbracket=cst.RightSquareBracket(),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": (
                    "match x:\n"
                    + "    case []: pass\n"
                    + "    case [None]: pass\n"
                    + "    case [None,]: pass\n"
                ),
                "parser": parser,
            },
            # Tuple patterns
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(  # empty tuple
                            pattern=cst.MatchTuple(
                                [],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # two element tuple
                            pattern=cst.MatchTuple(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    ),
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                    ),
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single element tuple with trailing comma
                            pattern=cst.MatchTuple(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # two element tuple
                            pattern=cst.MatchTuple(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    ),
                                    cst.MatchStar(
                                        comma=cst.Comma(),
                                    ),
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                    ),
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": (
                    "match x:\n"
                    + "    case (): pass\n"
                    + "    case (None,None): pass\n"
                    + "    case (None,): pass\n"
                    + "    case (None,*_,None): pass\n"
                ),
                "parser": parser,
            },
            # Mapping patterns
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(  # empty mapping
                            pattern=cst.MatchMapping(
                                [],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # two element mapping
                            pattern=cst.MatchMapping(
                                [
                                    cst.MatchMappingElement(
                                        key=cst.SimpleString('"a"'),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    ),
                                    cst.MatchMappingElement(
                                        key=cst.SimpleString('"b"'),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                    ),
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single element mapping with trailing comma
                            pattern=cst.MatchMapping(
                                [
                                    cst.MatchMappingElement(
                                        key=cst.SimpleString('"a"'),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # rest
                            pattern=cst.MatchMapping(
                                rest=cst.Name("rest"),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": (
                    "match x:\n"
                    + "    case {}: pass\n"
                    + '    case {"a": None,"b": None}: pass\n'
                    + '    case {"a": None,}: pass\n'
                    + "    case {**rest}: pass\n"
                ),
                "parser": parser,
            },
            # Class patterns
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(  # empty class
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single pattern class
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                                patterns=[
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None"))
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single pattern class with trailing comma
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                                patterns=[
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single keyword pattern class
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                                kwds=[
                                    cst.MatchKeywordElement(
                                        key=cst.Name("foo"),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # single keyword pattern class with trailing comma
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                                kwds=[
                                    cst.MatchKeywordElement(
                                        key=cst.Name("foo"),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    )
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(  # now all at once
                            pattern=cst.MatchClass(
                                cls=cst.Attribute(cst.Name("a"), cst.Name("b")),
                                patterns=[
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    ),
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.Comma(),
                                    ),
                                ],
                                kwds=[
                                    cst.MatchKeywordElement(
                                        key=cst.Name("foo"),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    ),
                                    cst.MatchKeywordElement(
                                        key=cst.Name("bar"),
                                        pattern=cst.MatchSingleton(cst.Name("None")),
                                        comma=cst.Comma(),
                                    ),
                                ],
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": (
                    "match x:\n"
                    + "    case a.b(): pass\n"
                    + "    case a.b(None): pass\n"
                    + "    case a.b(None,): pass\n"
                    + "    case a.b(foo=None): pass\n"
                    + "    case a.b(foo=None,): pass\n"
                    + "    case a.b(None,None,foo=None,bar=None,): pass\n"
                ),
                "parser": parser,
            },
            # as pattern
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchAs(),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchAs(name=cst.Name("foo")),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchAs(
                                pattern=cst.MatchSingleton(cst.Name("None")),
                                name=cst.Name("bar"),
                                whitespace_before_as=cst.SimpleWhitespace(" "),
                                whitespace_after_as=cst.SimpleWhitespace(" "),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": "match x:\n"
                + "    case _: pass\n"
                + "    case foo: pass\n"
                + "    case None as bar: pass\n",
                "parser": parser,
            },
            # or pattern
            {
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchOr(
                                [
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                        cst.BitOr(),
                                    ),
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("False")),
                                        cst.BitOr(),
                                    ),
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("True"))
                                    ),
                                ]
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        )
                    ],
                ),
                "code": "match x:\n    case None | False | True: pass\n",
                "parser": parser,
            },
            {  # exercise sentinels
                "node": cst.Match(
                    subject=cst.Name("x"),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchList(
                                [cst.MatchStar(), cst.MatchStar()],
                                lbracket=None,
                                rbracket=None,
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchTuple(
                                [
                                    cst.MatchSequenceElement(
                                        cst.MatchSingleton(cst.Name("None"))
                                    )
                                ]
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchAs(
                                pattern=cst.MatchTuple(
                                    [
                                        cst.MatchSequenceElement(
                                            cst.MatchSingleton(cst.Name("None"))
                                        )
                                    ]
                                ),
                                name=cst.Name("bar"),
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                        cst.MatchCase(
                            pattern=cst.MatchOr(
                                [
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("None")),
                                    ),
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("False")),
                                    ),
                                    cst.MatchOrElement(
                                        cst.MatchSingleton(cst.Name("True"))
                                    ),
                                ]
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ],
                ),
                "code": "match x:\n"
                + "    case *_, *_: pass\n"
                + "    case (None,): pass\n"
                + "    case (None,) as bar: pass\n"
                + "    case None | False | True: pass\n",
                "parser": None,
            },
            # Match without whitespace between keyword and the expr
            {
                "node": cst.Match(
                    subject=cst.Name(
                        "x", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]
                    ),
                    cases=[
                        cst.MatchCase(
                            pattern=cst.MatchSingleton(
                                cst.Name(
                                    "None",
                                    lpar=[cst.LeftParen()],
                                    rpar=[cst.RightParen()],
                                )
                            ),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_case=cst.SimpleWhitespace(
                                value="",
                            ),
                        ),
                    ],
                    whitespace_after_match=cst.SimpleWhitespace(
                        value="",
                    ),
                ),
                "code": "match(x):\n    case(None): pass\n",
                "parser": parser,
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)