Пример #1
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)
Пример #2
0
class NumberTest(CSTNodeTest):
    @data_provider(
        (
            # Simple number
            (cst.Integer("5"), "5", parse_expression),
            # Negted number
            (
                cst.UnaryOperation(operator=cst.Minus(), expression=cst.Integer("5")),
                "-5",
                parse_expression,
                CodeRange((1, 0), (1, 2)),
            ),
            # In parenthesis
            (
                cst.UnaryOperation(
                    lpar=(cst.LeftParen(),),
                    operator=cst.Minus(),
                    expression=cst.Integer("5"),
                    rpar=(cst.RightParen(),),
                ),
                "(-5)",
                parse_expression,
                CodeRange((1, 1), (1, 3)),
            ),
            (
                cst.UnaryOperation(
                    lpar=(cst.LeftParen(),),
                    operator=cst.Minus(),
                    expression=cst.Integer(
                        "5", lpar=(cst.LeftParen(),), rpar=(cst.RightParen(),)
                    ),
                    rpar=(cst.RightParen(),),
                ),
                "(-(5))",
                parse_expression,
                CodeRange((1, 1), (1, 5)),
            ),
            (
                cst.UnaryOperation(
                    operator=cst.Minus(),
                    expression=cst.UnaryOperation(
                        operator=cst.Minus(), expression=cst.Integer("5")
                    ),
                ),
                "--5",
                parse_expression,
                CodeRange((1, 0), (1, 3)),
            ),
            # multiple nested parenthesis
            (
                cst.Integer(
                    "5",
                    lpar=(cst.LeftParen(), cst.LeftParen()),
                    rpar=(cst.RightParen(), cst.RightParen()),
                ),
                "((5))",
                parse_expression,
                CodeRange((1, 2), (1, 3)),
            ),
            (
                cst.UnaryOperation(
                    lpar=(cst.LeftParen(),),
                    operator=cst.Plus(),
                    expression=cst.Integer(
                        "5",
                        lpar=(cst.LeftParen(), cst.LeftParen()),
                        rpar=(cst.RightParen(), cst.RightParen()),
                    ),
                    rpar=(cst.RightParen(),),
                ),
                "(+((5)))",
                parse_expression,
                CodeRange((1, 1), (1, 7)),
            ),
        )
    )
    def test_valid(
        self,
        node: cst.CSTNode,
        code: str,
        parser: Optional[Callable[[str], cst.CSTNode]],
        position: Optional[CodeRange] = None,
    ) -> None:
        self.validate_node(node, code, parser, expected_position=position)

    @data_provider(
        (
            (
                lambda: cst.Integer("5", lpar=(cst.LeftParen(),)),
                "left paren without right paren",
            ),
            (
                lambda: cst.Integer("5", rpar=(cst.RightParen(),)),
                "right paren without left paren",
            ),
            (
                lambda: cst.Float("5.5", lpar=(cst.LeftParen(),)),
                "left paren without right paren",
            ),
            (
                lambda: cst.Float("5.5", rpar=(cst.RightParen(),)),
                "right paren without left paren",
            ),
            (
                lambda: cst.Imaginary("5i", lpar=(cst.LeftParen(),)),
                "left paren without right paren",
            ),
            (
                lambda: cst.Imaginary("5i", rpar=(cst.RightParen(),)),
                "right paren without left paren",
            ),
        )
    )
    def test_invalid(
        self, get_node: Callable[[], cst.CSTNode], expected_re: str
    ) -> None:
        self.assert_invalid(get_node, expected_re)
Пример #3
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)
Пример #4
0
class BinaryOperationTest(CSTNodeTest):
    @data_provider(
        (
            # Simple binary operations
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.Add(),
                                    cst.Float("5.5")),
                "code":
                "foo + 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.Subtract(),
                                    cst.Float("5.5")),
                "code":
                "foo - 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.LeftShift(),
                                    cst.Integer("5")),
                "code":
                "foo << 5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.RightShift(),
                                    cst.Integer("5")),
                "code":
                "foo >> 5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.BitAnd(),
                                    cst.Name("bar")),
                "code":
                "foo & bar",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.BitXor(),
                                    cst.Name("bar")),
                "code":
                "foo ^ bar",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.BitOr(),
                                    cst.Name("bar")),
                "code":
                "foo | bar",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.Multiply(),
                                    cst.Float("5.5")),
                "code":
                "foo * 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.MatrixMultiply(),
                                    cst.Float("5.5")),
                "code":
                "foo @ 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.Divide(),
                                    cst.Float("5.5")),
                "code":
                "foo / 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.Modulo(),
                                    cst.Float("5.5")),
                "code":
                "foo % 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            {
                "node":
                cst.BinaryOperation(cst.Name("foo"), cst.FloorDivide(),
                                    cst.Float("5.5")),
                "code":
                "foo // 5.5",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            # Parenthesized binary operation
            {
                "node":
                cst.BinaryOperation(
                    lpar=(cst.LeftParen(), ),
                    left=cst.Name("foo"),
                    operator=cst.LeftShift(),
                    right=cst.Integer("5"),
                    rpar=(cst.RightParen(), ),
                ),
                "code":
                "(foo << 5)",
                "parser":
                parse_expression,
                "expected_position":
                None,
            },
            # Make sure that spacing works
            {
                "node":
                cst.BinaryOperation(
                    lpar=(cst.LeftParen(
                        whitespace_after=cst.SimpleWhitespace(" ")), ),
                    left=cst.Name("foo"),
                    operator=cst.Multiply(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("  "),
                    ),
                    right=cst.Name("bar"),
                    rpar=(cst.RightParen(
                        whitespace_before=cst.SimpleWhitespace(" ")), ),
                ),
                "code":
                "( foo  *  bar )",
                "parser":
                parse_expression,
                "expected_position":
                CodeRange((1, 2), (1, 13)),
            },
        ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node": (lambda: cst.BinaryOperation(
                cst.Name("foo"),
                cst.Add(),
                cst.Name("bar"),
                lpar=(cst.LeftParen(), ),
            )),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node": (lambda: cst.BinaryOperation(
                cst.Name("foo"),
                cst.Add(),
                cst.Name("bar"),
                rpar=(cst.RightParen(), ),
            )),
            "expected_re":
            "right paren without left paren",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Пример #5
0
class LambdaCreationTest(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")),
                                       cst.Param(cst.Name("baz")))),
                cst.Integer("5"),
            ),
            "lambda bar, baz: 5",
        ),
        # Test basic positional default params
        (
            cst.Lambda(
                cst.Parameters(default_params=(
                    cst.Param(cst.Name("bar"),
                              default=cst.SimpleString('"one"')),
                    cst.Param(cst.Name("baz"), default=cst.Integer("5")),
                )),
                cst.Integer("5"),
            ),
            'lambda bar = "one", baz = 5: 5',
        ),
        # Mixed positional and default params.
        (
            cst.Lambda(
                cst.Parameters(
                    params=(cst.Param(cst.Name("bar")), ),
                    default_params=(cst.Param(cst.Name("baz"),
                                              default=cst.Integer("5")), ),
                ),
                cst.Integer("5"),
            ),
            "lambda bar, baz = 5: 5",
        ),
        # Test kwonly params
        (
            cst.Lambda(
                cst.Parameters(kwonly_params=(
                    cst.Param(cst.Name("bar"),
                              default=cst.SimpleString('"one"')),
                    cst.Param(cst.Name("baz")),
                )),
                cst.Integer("5"),
            ),
            'lambda *, bar = "one", baz: 5',
        ),
        # Mixed params and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(cst.Name("first")),
                        cst.Param(cst.Name("second")),
                    ),
                    kwonly_params=(
                        cst.Param(cst.Name("bar"),
                                  default=cst.SimpleString('"one"')),
                        cst.Param(cst.Name("baz")),
                        cst.Param(cst.Name("biz"),
                                  default=cst.SimpleString('"two"')),
                    ),
                ),
                cst.Integer("5"),
            ),
            '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")),
                        cst.Param(cst.Name("second"),
                                  default=cst.Float("1.5")),
                    ),
                    kwonly_params=(
                        cst.Param(cst.Name("bar"),
                                  default=cst.SimpleString('"one"')),
                        cst.Param(cst.Name("baz")),
                        cst.Param(cst.Name("biz"),
                                  default=cst.SimpleString('"two"')),
                    ),
                ),
                cst.Integer("5"),
            ),
            '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")),
                        cst.Param(cst.Name("second")),
                    ),
                    default_params=(
                        cst.Param(cst.Name("third"), default=cst.Float("1.0")),
                        cst.Param(cst.Name("fourth"),
                                  default=cst.Float("1.5")),
                    ),
                    kwonly_params=(
                        cst.Param(cst.Name("bar"),
                                  default=cst.SimpleString('"one"')),
                        cst.Param(cst.Name("baz")),
                        cst.Param(cst.Name("biz"),
                                  default=cst.SimpleString('"two"')),
                    ),
                ),
                cst.Integer("5"),
            ),
            'lambda first, second, third = 1.0, fourth = 1.5, *, bar = "one", baz, biz = "two": 5',
            CodeRange((1, 0), (1, 84)),
        ),
        # Test star_arg
        (
            cst.Lambda(
                cst.Parameters(star_arg=cst.Param(cst.Name("params"))),
                cst.Integer("5"),
            ),
            "lambda *params: 5",
        ),
        # Typed star_arg, include kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.Param(cst.Name("params")),
                    kwonly_params=(
                        cst.Param(cst.Name("bar"),
                                  default=cst.SimpleString('"one"')),
                        cst.Param(cst.Name("baz")),
                        cst.Param(cst.Name("biz"),
                                  default=cst.SimpleString('"two"')),
                    ),
                ),
                cst.Integer("5"),
            ),
            '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")),
                        cst.Param(cst.Name("second")),
                    ),
                    default_params=(
                        cst.Param(cst.Name("third"), default=cst.Float("1.0")),
                        cst.Param(cst.Name("fourth"),
                                  default=cst.Float("1.5")),
                    ),
                    star_arg=cst.Param(cst.Name("params")),
                    kwonly_params=(
                        cst.Param(cst.Name("bar"),
                                  default=cst.SimpleString('"one"')),
                        cst.Param(cst.Name("baz")),
                        cst.Param(cst.Name("biz"),
                                  default=cst.SimpleString('"two"')),
                    ),
                ),
                cst.Integer("5"),
            ),
            '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"))),
                cst.Integer("5"),
            ),
            "lambda **kwparams: 5",
        ),
        # Test star_arg and kwarg
        (
            cst.Lambda(
                cst.Parameters(
                    star_arg=cst.Param(cst.Name("params")),
                    star_kwarg=cst.Param(cst.Name("kwparams")),
                ),
                cst.Integer("5"),
            ),
            "lambda *params, **kwparams: 5",
        ),
        # Inner whitespace
        (
            cst.Lambda(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                whitespace_after_lambda=cst.SimpleWhitespace("  "),
                params=cst.Parameters(),
                colon=cst.Colon(whitespace_after=cst.SimpleWhitespace(" ")),
                body=cst.Integer("5"),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "( lambda  : 5 )",
            CodeRange((1, 2), (1, 13)),
        ),
    ))
    def test_valid(self,
                   node: cst.CSTNode,
                   code: str,
                   position: Optional[CodeRange] = None) -> None:
        self.validate_node(node, code, expected_position=position)

    @data_provider((
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(cst.Name("arg")), )),
                cst.Integer("5"),
                lpar=(cst.LeftParen(), ),
            ),
            "left paren without right paren",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(cst.Name("arg")), )),
                cst.Integer("5"),
                rpar=(cst.RightParen(), ),
            ),
            "right paren without left paren",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(cst.Name("arg")), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "at least one space after lambda",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(default_params=(cst.Param(
                    cst.Name("arg"), default=cst.Integer("5")), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "at least one space after lambda",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_arg=cst.Param(cst.Name("arg"))),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "at least one space after lambda",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(kwonly_params=(cst.Param(cst.Name("arg")), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "at least one space after lambda",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_kwarg=cst.Param(cst.Name("arg"))),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "at least one space after lambda",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_kwarg=cst.Param(cst.Name("bar"),
                                                    equal=cst.AssignEqual())),
                cst.Integer("5"),
            ),
            "Must have a default when specifying an AssignEqual.",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_kwarg=cst.Param(cst.Name("bar"),
                                                    star="***")),
                cst.Integer("5"),
            ),
            r"Must specify either '', '\*' or '\*\*' for star.",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(
                    cst.Name("bar"), default=cst.SimpleString('"one"')), )),
                cst.Integer("5"),
            ),
            "Cannot have defaults for params",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(default_params=(cst.Param(cst.Name("bar")), )),
                cst.Integer("5"),
            ),
            "Must have defaults for default_params",
        ),
        (
            lambda: cst.Lambda(cst.Parameters(star_arg=cst.ParamStar()),
                               cst.Integer("5")),
            "Must have at least one kwonly param if ParamStar is used.",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(cst.Name("bar"), star="*"), )
                               ),
                cst.Integer("5"),
            ),
            "Expecting a star prefix of ''",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(default_params=(cst.Param(
                    cst.Name("bar"),
                    default=cst.SimpleString('"one"'),
                    star="*",
                ), )),
                cst.Integer("5"),
            ),
            "Expecting a star prefix of ''",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(kwonly_params=(cst.Param(cst.Name("bar"),
                                                        star="*"), )),
                cst.Integer("5"),
            ),
            "Expecting a star prefix of ''",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_arg=cst.Param(cst.Name("bar"), star="**")),
                cst.Integer("5"),
            ),
            r"Expecting a star prefix of '\*'",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_kwarg=cst.Param(cst.Name("bar"), star="*")
                               ),
                cst.Integer("5"),
            ),
            r"Expecting a star prefix of '\*\*'",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(params=(cst.Param(
                    cst.Name("arg"),
                    annotation=cst.Annotation(cst.Name("str")),
                ), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "Lambda params cannot have type annotations",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(default_params=(cst.Param(
                    cst.Name("arg"),
                    default=cst.Integer("5"),
                    annotation=cst.Annotation(cst.Name("str")),
                ), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "Lambda params cannot have type annotations",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_arg=cst.Param(cst.Name("arg"),
                                                  annotation=cst.Annotation(
                                                      cst.Name("str")))),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "Lambda params cannot have type annotations",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(kwonly_params=(cst.Param(
                    cst.Name("arg"),
                    annotation=cst.Annotation(cst.Name("str")),
                ), )),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "Lambda params cannot have type annotations",
        ),
        (
            lambda: cst.Lambda(
                cst.Parameters(star_kwarg=cst.Param(cst.Name("arg"),
                                                    annotation=cst.Annotation(
                                                        cst.Name("str")))),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(""),
            ),
            "Lambda params cannot have type annotations",
        ),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
Пример #6
0
class SimpleStatementTest(CSTNodeTest):
    @data_provider((
        # a single-element SimpleStatementLine
        # pyre-fixme[6]: Incompatible parameter type
        {
            "node": cst.SimpleStatementLine((cst.Pass(), )),
            "code": "pass\n",
            "parser": parse_statement,
        },
        # a multi-element SimpleStatementLine
        {
            "node":
            cst.SimpleStatementLine(
                (cst.Pass(semicolon=cst.Semicolon()), cst.Continue())),
            "code":
            "pass;continue\n",
            "parser":
            parse_statement,
        },
        # a multi-element SimpleStatementLine with whitespace
        {
            "node":
            cst.SimpleStatementLine((
                cst.Pass(semicolon=cst.Semicolon(
                    whitespace_before=cst.SimpleWhitespace(" "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                )),
                cst.Continue(),
            )),
            "code":
            "pass ;  continue\n",
            "parser":
            parse_statement,
        },
        # A more complicated SimpleStatementLine
        {
            "node":
            cst.SimpleStatementLine((
                cst.Pass(semicolon=cst.Semicolon()),
                cst.Continue(semicolon=cst.Semicolon()),
                cst.Break(),
            )),
            "code":
            "pass;continue;break\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 19)),
        },
        # a multi-element SimpleStatementLine, inferred semicolons
        {
            "node":
            cst.SimpleStatementLine((cst.Pass(), cst.Continue(), cst.Break())),
            "code":
            "pass; continue; break\n",
            "parser":
            None,  # No test for parsing, since we are using sentinels.
        },
        # some expression statements
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Name("None")), )),
            "code": "None\n",
            "parser": parse_statement,
        },
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Name("True")), )),
            "code": "True\n",
            "parser": parse_statement,
        },
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Name("False")), )),
            "code": "False\n",
            "parser": parse_statement,
        },
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Ellipsis()), )),
            "code": "...\n",
            "parser": parse_statement,
        },
        # Test some numbers
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Integer("5")), )),
            "code": "5\n",
            "parser": parse_statement,
        },
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Float("5.5")), )),
            "code": "5.5\n",
            "parser": parse_statement,
        },
        {
            "node": cst.SimpleStatementLine((cst.Expr(cst.Imaginary("5j")), )),
            "code": "5j\n",
            "parser": parse_statement,
        },
        # Test some numbers with parens
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Integer("5",
                            lpar=(cst.LeftParen(), ),
                            rpar=(cst.RightParen(), ))), )),
            "code":
            "(5)\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 3)),
        },
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Float("5.5",
                          lpar=(cst.LeftParen(), ),
                          rpar=(cst.RightParen(), ))), )),
            "code":
            "(5.5)\n",
            "parser":
            parse_statement,
        },
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Imaginary("5j",
                              lpar=(cst.LeftParen(), ),
                              rpar=(cst.RightParen(), ))), )),
            "code":
            "(5j)\n",
            "parser":
            parse_statement,
        },
        # Test some strings
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(cst.SimpleString('"abc"')), )),
            "code":
            '"abc"\n',
            "parser":
            parse_statement,
        },
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.ConcatenatedString(cst.SimpleString('"abc"'),
                                       cst.SimpleString('"def"'))), )),
            "code":
            '"abc""def"\n',
            "parser":
            parse_statement,
        },
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.ConcatenatedString(
                    left=cst.SimpleString('"abc"'),
                    whitespace_between=cst.SimpleWhitespace(" "),
                    right=cst.ConcatenatedString(
                        left=cst.SimpleString('"def"'),
                        whitespace_between=cst.SimpleWhitespace(" "),
                        right=cst.SimpleString('"ghi"'),
                    ),
                )), )),
            "code":
            '"abc" "def" "ghi"\n',
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 17)),
        },
        # Test parenthesis rules
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Ellipsis(lpar=(cst.LeftParen(), ),
                             rpar=(cst.RightParen(), ))), )),
            "code":
            "(...)\n",
            "parser":
            parse_statement,
        },
        # Test parenthesis with whitespace ownership
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Ellipsis(
                    lpar=(cst.LeftParen(
                        whitespace_after=cst.SimpleWhitespace(" ")), ),
                    rpar=(cst.RightParen(
                        whitespace_before=cst.SimpleWhitespace(" ")), ),
                )), )),
            "code":
            "( ... )\n",
            "parser":
            parse_statement,
        },
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Ellipsis(
                    lpar=(
                        cst.LeftParen(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                        cst.LeftParen(
                            whitespace_after=cst.SimpleWhitespace("  ")),
                        cst.LeftParen(
                            whitespace_after=cst.SimpleWhitespace("   ")),
                    ),
                    rpar=(
                        cst.RightParen(
                            whitespace_before=cst.SimpleWhitespace("   ")),
                        cst.RightParen(
                            whitespace_before=cst.SimpleWhitespace("  ")),
                        cst.RightParen(
                            whitespace_before=cst.SimpleWhitespace(" ")),
                    ),
                )), )),
            "code":
            "( (  (   ...   )  ) )\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 21)),
        },
        # Test parenthesis rules with expressions
        {
            "node":
            cst.SimpleStatementLine((cst.Expr(
                cst.Ellipsis(
                    lpar=(cst.LeftParen(
                        whitespace_after=cst.ParenthesizedWhitespace(
                            first_line=cst.TrailingWhitespace(),
                            empty_lines=(cst.EmptyLine(
                                comment=cst.Comment("# Wow, a comment!")), ),
                            indent=True,
                            last_line=cst.SimpleWhitespace("    "),
                        )), ),
                    rpar=(cst.RightParen(
                        whitespace_before=cst.ParenthesizedWhitespace(
                            first_line=cst.TrailingWhitespace(),
                            empty_lines=(),
                            indent=True,
                            last_line=cst.SimpleWhitespace(""),
                        )), ),
                )), )),
            "code":
            "(\n# Wow, a comment!\n    ...\n)\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (4, 1)),
        },
        # test trailing whitespace
        {
            "node":
            cst.SimpleStatementLine(
                (cst.Pass(), ),
                trailing_whitespace=cst.TrailingWhitespace(
                    whitespace=cst.SimpleWhitespace("  "),
                    comment=cst.Comment("# trailing comment"),
                ),
            ),
            "code":
            "pass  # trailing comment\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 4)),
        },
        # test leading comment
        {
            "node":
            cst.SimpleStatementLine(
                (cst.Pass(), ),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# comment")), ),
            ),
            "code":
            "# comment\npass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((2, 0), (2, 4)),
        },
        # test indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.SimpleStatementLine(
                    (cst.Pass(), ),
                    leading_lines=(cst.EmptyLine(
                        comment=cst.Comment("# comment")), ),
                ),
            ),
            "code":
            "    # comment\n    pass\n",
            "expected_position":
            CodeRange.create((2, 4), (2, 8)),
        },
        # test suite variant
        {
            "node": cst.SimpleStatementSuite((cst.Pass(), )),
            "code": " pass\n",
            "expected_position": CodeRange.create((1, 1), (1, 5)),
        },
        {
            "node":
            cst.SimpleStatementSuite(
                (cst.Pass(), ), leading_whitespace=cst.SimpleWhitespace("")),
            "code":
            "pass\n",
            "expected_position":
            CodeRange.create((1, 0), (1, 4)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)
Пример #7
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,
        },
        # 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)),
        },
        # 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)
Пример #8
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",
        },
        {
            "get_node":
            lambda: cst.Import(names=[
                cst.ImportAlias(name=cst.Attribute(value=cst.Float(value="0."),
                                                   attr=cst.Name(value="A")))
            ]),
            "expected_re":
            "imported name must be a valid qualified name.",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Пример #9
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)