Example #1
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,
        },
        # 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)

    @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:
        self.assert_parses(**kwargs)
Example #2
0
class SimpleCompTest(CSTNodeTest):
    @data_provider([
        # simple GeneratorExp
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c"))),
            "code":
            "(a for b in c)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 13)),
        },
        # simple ListComp
        {
            "node":
            cst.ListComp(cst.Name("a"),
                         cst.CompFor(target=cst.Name("b"),
                                     iter=cst.Name("c"))),
            "code":
            "[a for b in c]",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 14)),
        },
        # simple SetComp
        {
            "node":
            cst.SetComp(cst.Name("a"),
                        cst.CompFor(target=cst.Name("b"), iter=cst.Name("c"))),
            "code":
            "{a for b in c}",
            "parser":
            parse_expression,
        },
        # async GeneratorExp
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    asynchronous=cst.Asynchronous(),
                ),
            ),
            "code":
            "(a async for b in c)",
            "parser":
            lambda code: parse_expression(
                code, config=PartialParserConfig(python_version="3.7")),
        },
        # Python 3.6 async GeneratorExp
        {
            "node":
            cst.FunctionDef(
                cst.Name("foo"),
                cst.Parameters(),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Expr(
                    cst.GeneratorExp(
                        cst.Name("a"),
                        cst.CompFor(
                            target=cst.Name("b"),
                            iter=cst.Name("c"),
                            asynchronous=cst.Asynchronous(),
                        ),
                    )), )), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async def foo():\n    (a async for b in c)\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.6")),
        },
        # a generator doesn't have to own it's own parenthesis
        {
            "node":
            cst.Call(
                cst.Name("func"),
                [
                    cst.Arg(
                        cst.GeneratorExp(
                            cst.Name("a"),
                            cst.CompFor(target=cst.Name("b"),
                                        iter=cst.Name("c")),
                            lpar=[],
                            rpar=[],
                        ))
                ],
            ),
            "code":
            "func(a for b in c)",
            "parser":
            parse_expression,
        },
        # add a few 'if' clauses
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    ifs=[
                        cst.CompIf(cst.Name("d")),
                        cst.CompIf(cst.Name("e")),
                        cst.CompIf(cst.Name("f")),
                    ],
                ),
            ),
            "code":
            "(a for b in c if d if e if f)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 28)),
        },
        # nested/inner for-in clause
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    inner_for_in=cst.CompFor(target=cst.Name("d"),
                                             iter=cst.Name("e")),
                ),
            ),
            "code":
            "(a for b in c for d in e)",
            "parser":
            parse_expression,
        },
        # nested/inner for-in clause with an 'if' clause
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    ifs=[cst.CompIf(cst.Name("d"))],
                    inner_for_in=cst.CompFor(target=cst.Name("e"),
                                             iter=cst.Name("f")),
                ),
            ),
            "code":
            "(a for b in c if d for e in f)",
            "parser":
            parse_expression,
        },
        # custom whitespace
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    ifs=[
                        cst.CompIf(
                            cst.Name("d"),
                            whitespace_before=cst.SimpleWhitespace("\t"),
                            whitespace_before_test=cst.SimpleWhitespace(
                                "\t\t"),
                        )
                    ],
                    whitespace_before=cst.SimpleWhitespace("  "),
                    whitespace_after_for=cst.SimpleWhitespace("   "),
                    whitespace_before_in=cst.SimpleWhitespace("    "),
                    whitespace_after_in=cst.SimpleWhitespace("     "),
                ),
                lpar=[
                    cst.LeftParen(whitespace_after=cst.SimpleWhitespace("\f"))
                ],
                rpar=[
                    cst.RightParen(
                        whitespace_before=cst.SimpleWhitespace("\f\f"))
                ],
            ),
            "code":
            "(\fa  for   b    in     c\tif\t\td\f\f)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 2), (1, 30)),
        },
        # custom whitespace around ListComp's brackets
        {
            "node":
            cst.ListComp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace("\t\t")),
                lpar=[
                    cst.LeftParen(whitespace_after=cst.SimpleWhitespace("\f"))
                ],
                rpar=[
                    cst.RightParen(
                        whitespace_before=cst.SimpleWhitespace("\f\f"))
                ],
            ),
            "code":
            "(\f[\ta for b in c\t\t]\f\f)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 2), (1, 19)),
        },
        # custom whitespace around SetComp's braces
        {
            "node":
            cst.SetComp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                lbrace=cst.LeftCurlyBrace(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbrace=cst.RightCurlyBrace(
                    whitespace_before=cst.SimpleWhitespace("\t\t")),
                lpar=[
                    cst.LeftParen(whitespace_after=cst.SimpleWhitespace("\f"))
                ],
                rpar=[
                    cst.RightParen(
                        whitespace_before=cst.SimpleWhitespace("\f\f"))
                ],
            ),
            "code":
            "(\f{\ta for b in c\t\t}\f\f)",
            "parser":
            parse_expression,
        },
        # no whitespace between elements
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]),
                cst.CompFor(
                    target=cst.Name("b",
                                    lpar=[cst.LeftParen()],
                                    rpar=[cst.RightParen()]),
                    iter=cst.Name("c",
                                  lpar=[cst.LeftParen()],
                                  rpar=[cst.RightParen()]),
                    ifs=[
                        cst.CompIf(
                            cst.Name("d",
                                     lpar=[cst.LeftParen()],
                                     rpar=[cst.RightParen()]),
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_before_test=cst.SimpleWhitespace(""),
                        )
                    ],
                    inner_for_in=cst.CompFor(
                        target=cst.Name("e",
                                        lpar=[cst.LeftParen()],
                                        rpar=[cst.RightParen()]),
                        iter=cst.Name("f",
                                      lpar=[cst.LeftParen()],
                                      rpar=[cst.RightParen()]),
                        whitespace_before=cst.SimpleWhitespace(""),
                        whitespace_after_for=cst.SimpleWhitespace(""),
                        whitespace_before_in=cst.SimpleWhitespace(""),
                        whitespace_after_in=cst.SimpleWhitespace(""),
                    ),
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                    whitespace_after_in=cst.SimpleWhitespace(""),
                ),
                lpar=[cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "code":
            "((a)for(b)in(c)if(d)for(e)in(f))",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 31)),
        },
        # no whitespace before/after GeneratorExp is valid
        {
            "node":
            cst.Comparison(
                cst.GeneratorExp(
                    cst.Name("a"),
                    cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                ),
                [
                    cst.ComparisonTarget(
                        cst.Is(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.GeneratorExp(
                            cst.Name("d"),
                            cst.CompFor(target=cst.Name("e"),
                                        iter=cst.Name("f")),
                        ),
                    )
                ],
            ),
            "code":
            "(a for b in c)is(d for e in f)",
            "parser":
            parse_expression,
        },
        # no whitespace before/after ListComp is valid
        {
            "node":
            cst.Comparison(
                cst.ListComp(
                    cst.Name("a"),
                    cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                ),
                [
                    cst.ComparisonTarget(
                        cst.Is(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.ListComp(
                            cst.Name("d"),
                            cst.CompFor(target=cst.Name("e"),
                                        iter=cst.Name("f")),
                        ),
                    )
                ],
            ),
            "code":
            "[a for b in c]is[d for e in f]",
            "parser":
            parse_expression,
        },
        # no whitespace before/after SetComp is valid
        {
            "node":
            cst.Comparison(
                cst.SetComp(
                    cst.Name("a"),
                    cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                ),
                [
                    cst.ComparisonTarget(
                        cst.Is(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        cst.SetComp(
                            cst.Name("d"),
                            cst.CompFor(target=cst.Name("e"),
                                        iter=cst.Name("f")),
                        ),
                    )
                ],
            ),
            "code":
            "{a for b in c}is{d for e in f}",
            "parser":
            parse_expression,
        },
    ])
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                lpar=[cst.LeftParen(), cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "unbalanced parens",
        ),
        (
            lambda: cst.ListComp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                lpar=[cst.LeftParen(), cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "unbalanced parens",
        ),
        (
            lambda: cst.SetComp(
                cst.Name("a"),
                cst.CompFor(target=cst.Name("b"), iter=cst.Name("c")),
                lpar=[cst.LeftParen(), cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "unbalanced parens",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    whitespace_before=cst.SimpleWhitespace(""),
                ),
            ),
            "Must have at least one space before 'for' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    asynchronous=cst.Asynchronous(),
                    whitespace_before=cst.SimpleWhitespace(""),
                ),
            ),
            "Must have at least one space before 'async' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    whitespace_after_for=cst.SimpleWhitespace(""),
                ),
            ),
            "Must have at least one space after 'for' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    whitespace_before_in=cst.SimpleWhitespace(""),
                ),
            ),
            "Must have at least one space before 'in' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    whitespace_after_in=cst.SimpleWhitespace(""),
                ),
            ),
            "Must have at least one space after 'in' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    ifs=[
                        cst.CompIf(
                            cst.Name("d"),
                            whitespace_before=cst.SimpleWhitespace(""),
                        )
                    ],
                ),
            ),
            "Must have at least one space before 'if' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    ifs=[
                        cst.CompIf(
                            cst.Name("d"),
                            whitespace_before_test=cst.SimpleWhitespace(""),
                        )
                    ],
                ),
            ),
            "Must have at least one space after 'if' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    inner_for_in=cst.CompFor(
                        target=cst.Name("d"),
                        iter=cst.Name("e"),
                        whitespace_before=cst.SimpleWhitespace(""),
                    ),
                ),
            ),
            "Must have at least one space before 'for' keyword.",
        ),
        (
            lambda: cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    target=cst.Name("b"),
                    iter=cst.Name("c"),
                    inner_for_in=cst.CompFor(
                        target=cst.Name("d"),
                        iter=cst.Name("e"),
                        asynchronous=cst.Asynchronous(),
                        whitespace_before=cst.SimpleWhitespace(""),
                    ),
                ),
            ),
            "Must have at least one space before 'async' keyword.",
        ),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
Example #3
0
class UnaryOperationTest(CSTNodeTest):
    @data_provider((
        # Simple unary operations
        (cst.UnaryOperation(cst.Plus(), cst.Name("foo")), "+foo"),
        (cst.UnaryOperation(cst.Minus(), cst.Name("foo")), "-foo"),
        (cst.UnaryOperation(cst.BitInvert(), cst.Name("foo")), "~foo"),
        (cst.UnaryOperation(cst.Not(), cst.Name("foo")), "not foo"),
        # Parenthesized unary operation
        (
            cst.UnaryOperation(
                lpar=(cst.LeftParen(), ),
                operator=cst.Not(),
                expression=cst.Name("foo"),
                rpar=(cst.RightParen(), ),
            ),
            "(not foo)",
            CodeRange.create((1, 1), (1, 8)),
        ),
        (
            cst.UnaryOperation(
                operator=cst.Not(whitespace_after=cst.SimpleWhitespace("")),
                expression=cst.Name("foo",
                                    lpar=(cst.LeftParen(), ),
                                    rpar=(cst.RightParen(), )),
            ),
            "not(foo)",
            CodeRange.create((1, 0), (1, 8)),
        ),
        # Make sure that spacing works
        (
            cst.UnaryOperation(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                operator=cst.Not(whitespace_after=cst.SimpleWhitespace("  ")),
                expression=cst.Name("foo"),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "( not  foo )",
            CodeRange.create((1, 2), (1, 10)),
        ),
    ))
    def test_valid(self,
                   node: cst.CSTNode,
                   code: str,
                   position: Optional[CodeRange] = None) -> None:
        self.validate_node(node,
                           code,
                           parse_expression,
                           expected_position=position)

    @data_provider((
        (
            lambda: cst.UnaryOperation(
                cst.Plus(), cst.Name("foo"), lpar=(cst.LeftParen(), )),
            "left paren without right paren",
        ),
        (
            lambda: cst.UnaryOperation(
                cst.Plus(), cst.Name("foo"), rpar=(cst.RightParen(), )),
            "right paren without left paren",
        ),
        (
            lambda: cst.UnaryOperation(
                operator=cst.Not(whitespace_after=cst.SimpleWhitespace("")),
                expression=cst.Name("foo"),
            ),
            "at least one space after not operator",
        ),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
Example #4
0
class WhitespaceParserTest(UnitTest):
    @data_provider(
        {
            "simple_whitespace_empty": {
                "parser": parse_simple_whitespace,
                "config": Config(
                    lines=["not whitespace\n", " another line\n"], default_newline="\n"
                ),
                "start_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": cst.SimpleWhitespace(""),
            },
            "simple_whitespace_start_of_line": {
                "parser": parse_simple_whitespace,
                "config": Config(
                    lines=["\t  <-- There's some whitespace there\n"],
                    default_newline="\n",
                ),
                "start_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=1, column=3, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": cst.SimpleWhitespace("\t  "),
            },
            "simple_whitespace_end_of_line": {
                "parser": parse_simple_whitespace,
                "config": Config(lines=["prefix   "], default_newline="\n"),
                "start_state": State(
                    line=1, column=6, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=1, column=9, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": cst.SimpleWhitespace("   "),
            },
            "simple_whitespace_line_continuation": {
                "parser": parse_simple_whitespace,
                "config": Config(
                    lines=["prefix \\\n", "    \\\n", "    # suffix\n"],
                    default_newline="\n",
                ),
                "start_state": State(
                    line=1, column=6, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=3, column=4, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": cst.SimpleWhitespace(" \\\n    \\\n    "),
            },
            "empty_lines_empty_list": {
                "parser": parse_empty_lines,
                "config": Config(
                    lines=["this is not an empty line"], default_newline="\n"
                ),
                "start_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": [],
            },
            "empty_lines_single_line": {
                "parser": parse_empty_lines,
                "config": Config(
                    lines=["    # comment\n", "this is not an empty line\n"],
                    default_newline="\n",
                ),
                "start_state": State(
                    line=1, column=0, absolute_indent="    ", is_parenthesized=False
                ),
                "end_state": State(
                    line=2, column=0, absolute_indent="    ", is_parenthesized=False
                ),
                "expected_node": [
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=cst.Comment("# comment"),
                        newline=cst.Newline(),
                    )
                ],
            },
            "empty_lines_multiple": {
                "parser": parse_empty_lines,
                "config": Config(
                    lines=[
                        "\n",
                        "    \n",
                        "     # comment with indent and whitespace\n",
                        "# comment without indent\n",
                        "  # comment with no indent but some whitespace\n",
                    ],
                    default_newline="\n",
                ),
                "start_state": State(
                    line=1, column=0, absolute_indent="    ", is_parenthesized=False
                ),
                "end_state": State(
                    line=5, column=47, absolute_indent="    ", is_parenthesized=False
                ),
                "expected_node": [
                    cst.EmptyLine(
                        indent=False,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=None,
                        newline=cst.Newline(),
                    ),
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=None,
                        newline=cst.Newline(),
                    ),
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(" "),
                        comment=cst.Comment("# comment with indent and whitespace"),
                        newline=cst.Newline(),
                    ),
                    cst.EmptyLine(
                        indent=False,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=cst.Comment("# comment without indent"),
                        newline=cst.Newline(),
                    ),
                    cst.EmptyLine(
                        indent=False,
                        whitespace=cst.SimpleWhitespace("  "),
                        comment=cst.Comment(
                            "# comment with no indent but some whitespace"
                        ),
                        newline=cst.Newline(),
                    ),
                ],
            },
            "empty_lines_non_default_newline": {
                "parser": parse_empty_lines,
                "config": Config(lines=["\n", "\r\n", "\r"], default_newline="\n"),
                "start_state": State(
                    line=1, column=0, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=3, column=1, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": [
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=None,
                        newline=cst.Newline(None),  # default newline
                    ),
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=None,
                        newline=cst.Newline("\r\n"),  # non-default
                    ),
                    cst.EmptyLine(
                        indent=True,
                        whitespace=cst.SimpleWhitespace(""),
                        comment=None,
                        newline=cst.Newline("\r"),  # non-default
                    ),
                ],
            },
            "trailing_whitespace": {
                "parser": parse_trailing_whitespace,
                "config": Config(
                    lines=["some code  # comment\n"], default_newline="\n"
                ),
                "start_state": State(
                    line=1, column=9, absolute_indent="", is_parenthesized=False
                ),
                "end_state": State(
                    line=1, column=21, absolute_indent="", is_parenthesized=False
                ),
                "expected_node": cst.TrailingWhitespace(
                    whitespace=cst.SimpleWhitespace("  "),
                    comment=cst.Comment("# comment"),
                    newline=cst.Newline(),
                ),
            },
        }
    )
    def test_parsers(
        self,
        parser: Callable[[Config, State], _T],
        config: Config,
        start_state: State,
        end_state: State,
        expected_node: _T,
    ) -> None:
        # Uses internal `deep_equals` function instead of `CSTNode.deep_equals`, because
        # we need to compare sequences of nodes, and this is the easiest way. :/
        parsed_node = parser(config, start_state)
        self.assertTrue(
            deep_equals(parsed_node, expected_node),
            msg=f"\n{parsed_node!r}\nis not deeply equal to \n{expected_node!r}",
        )
        self.assertEqual(start_state, end_state)
Example #5
0
class CallTest(CSTNodeTest):
    @data_provider(
        (
            # Simple call
            {
                "node": cst.Call(cst.Name("foo")),
                "code": "foo()",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"), whitespace_before_args=cst.SimpleWhitespace(" ")
                ),
                "code": "foo( )",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Call with attribute dereference
            {
                "node": cst.Call(cst.Attribute(cst.Name("foo"), cst.Name("bar"))),
                "code": "foo.bar()",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Positional arguments render test
            {
                "node": cst.Call(cst.Name("foo"), (cst.Arg(cst.Integer("1")),)),
                "code": "foo(1)",
                "parser": None,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(cst.Integer("1")),
                        cst.Arg(cst.Integer("2")),
                        cst.Arg(cst.Integer("3")),
                    ),
                ),
                "code": "foo(1, 2, 3)",
                "parser": None,
                "expected_position": None,
            },
            # Positional arguments parse test
            {
                "node": cst.Call(cst.Name("foo"), (cst.Arg(value=cst.Integer("1")),)),
                "code": "foo(1)",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            value=cst.Integer("1"),
                            whitespace_after_arg=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    whitespace_after_func=cst.SimpleWhitespace(" "),
                    whitespace_before_args=cst.SimpleWhitespace(" "),
                ),
                "code": "foo ( 1 )",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            value=cst.Integer("1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    whitespace_after_func=cst.SimpleWhitespace(" "),
                    whitespace_before_args=cst.SimpleWhitespace(" "),
                ),
                "code": "foo ( 1, )",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            value=cst.Integer("1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            value=cst.Integer("2"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(value=cst.Integer("3")),
                    ),
                ),
                "code": "foo(1, 2, 3)",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Keyword arguments render test
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (cst.Arg(keyword=cst.Name("one"), value=cst.Integer("1")),),
                ),
                "code": "foo(one = 1)",
                "parser": None,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(keyword=cst.Name("one"), value=cst.Integer("1")),
                        cst.Arg(keyword=cst.Name("two"), value=cst.Integer("2")),
                        cst.Arg(keyword=cst.Name("three"), value=cst.Integer("3")),
                    ),
                ),
                "code": "foo(one = 1, two = 2, three = 3)",
                "parser": None,
                "expected_position": None,
            },
            # Keyword arguments parser test
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            keyword=cst.Name("one"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("1"),
                        ),
                    ),
                ),
                "code": "foo(one = 1)",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            keyword=cst.Name("one"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("two"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("2"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("three"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("3"),
                        ),
                    ),
                ),
                "code": "foo(one = 1, two = 2, three = 3)",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Iterator expansion render test
            {
                "node": cst.Call(
                    cst.Name("foo"), (cst.Arg(star="*", value=cst.Name("one")),)
                ),
                "code": "foo(*one)",
                "parser": None,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(star="*", value=cst.Name("one")),
                        cst.Arg(star="*", value=cst.Name("two")),
                        cst.Arg(star="*", value=cst.Name("three")),
                    ),
                ),
                "code": "foo(*one, *two, *three)",
                "parser": None,
                "expected_position": None,
            },
            # Iterator expansion parser test
            {
                "node": cst.Call(
                    cst.Name("foo"), (cst.Arg(star="*", value=cst.Name("one")),)
                ),
                "code": "foo(*one)",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            star="*",
                            value=cst.Name("one"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("two"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(star="*", value=cst.Name("three")),
                    ),
                ),
                "code": "foo(*one, *two, *three)",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Dictionary expansion render test
            {
                "node": cst.Call(
                    cst.Name("foo"), (cst.Arg(star="**", value=cst.Name("one")),)
                ),
                "code": "foo(**one)",
                "parser": None,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(star="**", value=cst.Name("one")),
                        cst.Arg(star="**", value=cst.Name("two")),
                        cst.Arg(star="**", value=cst.Name("three")),
                    ),
                ),
                "code": "foo(**one, **two, **three)",
                "parser": None,
                "expected_position": None,
            },
            # Dictionary expansion parser test
            {
                "node": cst.Call(
                    cst.Name("foo"), (cst.Arg(star="**", value=cst.Name("one")),)
                ),
                "code": "foo(**one)",
                "parser": parse_expression,
                "expected_position": None,
            },
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            star="**",
                            value=cst.Name("one"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="**",
                            value=cst.Name("two"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(star="**", value=cst.Name("three")),
                    ),
                ),
                "code": "foo(**one, **two, **three)",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Complicated mingling rules render test
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(value=cst.Name("pos1")),
                        cst.Arg(star="*", value=cst.Name("list1")),
                        cst.Arg(value=cst.Name("pos2")),
                        cst.Arg(value=cst.Name("pos3")),
                        cst.Arg(star="*", value=cst.Name("list2")),
                        cst.Arg(value=cst.Name("pos4")),
                        cst.Arg(star="*", value=cst.Name("list3")),
                        cst.Arg(keyword=cst.Name("kw1"), value=cst.Integer("1")),
                        cst.Arg(star="*", value=cst.Name("list4")),
                        cst.Arg(keyword=cst.Name("kw2"), value=cst.Integer("2")),
                        cst.Arg(star="*", value=cst.Name("list5")),
                        cst.Arg(keyword=cst.Name("kw3"), value=cst.Integer("3")),
                        cst.Arg(star="**", value=cst.Name("dict1")),
                        cst.Arg(keyword=cst.Name("kw4"), value=cst.Integer("4")),
                        cst.Arg(star="**", value=cst.Name("dict2")),
                    ),
                ),
                "code": "foo(pos1, *list1, pos2, pos3, *list2, pos4, *list3, kw1 = 1, *list4, kw2 = 2, *list5, kw3 = 3, **dict1, kw4 = 4, **dict2)",
                "parser": None,
                "expected_position": None,
            },
            # Complicated mingling rules parser test
            {
                "node": cst.Call(
                    cst.Name("foo"),
                    (
                        cst.Arg(
                            value=cst.Name("pos1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("list1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            value=cst.Name("pos2"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            value=cst.Name("pos3"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("list2"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            value=cst.Name("pos4"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("list3"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("kw1"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("list4"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("kw2"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("2"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="*",
                            value=cst.Name("list5"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("kw3"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("3"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="**",
                            value=cst.Name("dict1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("kw4"),
                            equal=cst.AssignEqual(),
                            value=cst.Integer("4"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(star="**", value=cst.Name("dict2")),
                    ),
                ),
                "code": "foo(pos1, *list1, pos2, pos3, *list2, pos4, *list3, kw1 = 1, *list4, kw2 = 2, *list5, kw3 = 3, **dict1, kw4 = 4, **dict2)",
                "parser": parse_expression,
                "expected_position": None,
            },
            # Test whitespace
            {
                "node": cst.Call(
                    lpar=(cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),),
                    func=cst.Name("foo"),
                    whitespace_after_func=cst.SimpleWhitespace(" "),
                    whitespace_before_args=cst.SimpleWhitespace(" "),
                    args=(
                        cst.Arg(
                            keyword=None,
                            value=cst.Name("pos1"),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.Arg(
                            star="*",
                            whitespace_after_star=cst.SimpleWhitespace("  "),
                            keyword=None,
                            value=cst.Name("list1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            keyword=cst.Name("kw1"),
                            equal=cst.AssignEqual(
                                whitespace_before=cst.SimpleWhitespace(""),
                                whitespace_after=cst.SimpleWhitespace(""),
                            ),
                            value=cst.Integer("1"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Arg(
                            star="**",
                            keyword=None,
                            whitespace_after_star=cst.SimpleWhitespace(" "),
                            value=cst.Name("dict1"),
                            whitespace_after_arg=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    rpar=(cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),),
                ),
                "code": "( foo ( pos1 ,  *  list1, kw1=1, ** dict1 ) )",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 2), (1, 43)),
            },
            # Test args
            {
                "node": cst.Arg(
                    star="*",
                    whitespace_after_star=cst.SimpleWhitespace("  "),
                    keyword=None,
                    value=cst.Name("list1"),
                    comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                ),
                "code": "*  list1, ",
                "parser": None,
                "expected_position": CodeRange((1, 0), (1, 8)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            # Basic expression parenthesizing tests.
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"), lpar=(cst.LeftParen(),)
                ),
                "expected_re": "left paren without right paren",
            },
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"), rpar=(cst.RightParen(),)
                ),
                "expected_re": "right paren without left paren",
            },
            # Test that we handle keyword stuff correctly.
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    args=(
                        cst.Arg(
                            equal=cst.AssignEqual(), value=cst.SimpleString("'baz'")
                        ),
                    ),
                ),
                "expected_re": "Must have a keyword when specifying an AssignEqual",
            },
            # Test that we separate *, ** and keyword args correctly
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    args=(
                        cst.Arg(
                            star="*",
                            keyword=cst.Name("bar"),
                            value=cst.SimpleString("'baz'"),
                        ),
                    ),
                ),
                "expected_re": "Cannot specify a star and a keyword together",
            },
            # Test for expected star inputs only
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    # pyre-ignore: Ignore type on 'star' since we're testing behavior
                    # when somebody isn't using a type checker.
                    args=(cst.Arg(star="***", value=cst.SimpleString("'baz'")),),
                ),
                "expected_re": r"Must specify either '', '\*' or '\*\*' for star",
            },
            # Test ordering exceptions
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    args=(
                        cst.Arg(star="**", value=cst.Name("bar")),
                        cst.Arg(star="*", value=cst.Name("baz")),
                    ),
                ),
                "expected_re": "Cannot have iterable argument unpacking after keyword argument unpacking",
            },
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    args=(
                        cst.Arg(star="**", value=cst.Name("bar")),
                        cst.Arg(value=cst.Name("baz")),
                    ),
                ),
                "expected_re": "Cannot have positional argument after keyword argument unpacking",
            },
            {
                "get_node": lambda: cst.Call(
                    func=cst.Name("foo"),
                    args=(
                        cst.Arg(
                            keyword=cst.Name("arg"), value=cst.SimpleString("'baz'")
                        ),
                        cst.Arg(value=cst.SimpleString("'bar'")),
                    ),
                ),
                "expected_re": "Cannot have positional argument after keyword argument",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #6
0
class TryTest(CSTNodeTest):
    @data_provider(
        (
            # Simple try/except block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 12)),
            },
            # Try/except with a class
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("Exception"),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept Exception: pass\n",
                "parser": parse_statement,
            },
            # Try/except with a named class
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("Exception"),
                            name=cst.AsName(cst.Name("exc")),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept Exception as exc: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 29)),
            },
            # Try/except with multiple clauses
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("KeyError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                ),
                "code": "try: pass\n"
                + "except TypeError as e: pass\n"
                + "except KeyError as e: pass\n"
                + "except: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (4, 12)),
            },
            # Simple try/finally block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (2, 13)),
            },
            # Simple try/except/finally block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (3, 13)),
            },
            # Simple try/except/else block
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nelse: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (3, 10)),
            },
            # Simple try/except/else block/finally
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\nexcept: pass\nelse: pass\nfinally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (4, 13)),
            },
            # Verify whitespace in various locations
            {
                "node": cst.Try(
                    leading_lines=(cst.EmptyLine(comment=cst.Comment("# 1")),),
                    body=cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            leading_lines=(cst.EmptyLine(comment=cst.Comment("# 2")),),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(
                                cst.Name("e"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            whitespace_after_except=cst.SimpleWhitespace("  "),
                            whitespace_before_colon=cst.SimpleWhitespace(" "),
                            body=cst.SimpleStatementSuite((cst.Pass(),)),
                        ),
                    ),
                    orelse=cst.Else(
                        leading_lines=(cst.EmptyLine(comment=cst.Comment("# 3")),),
                        body=cst.SimpleStatementSuite((cst.Pass(),)),
                        whitespace_before_colon=cst.SimpleWhitespace(" "),
                    ),
                    finalbody=cst.Finally(
                        leading_lines=(cst.EmptyLine(comment=cst.Comment("# 4")),),
                        body=cst.SimpleStatementSuite((cst.Pass(),)),
                        whitespace_before_colon=cst.SimpleWhitespace(" "),
                    ),
                    whitespace_before_colon=cst.SimpleWhitespace(" "),
                ),
                "code": "# 1\ntry : pass\n# 2\nexcept  TypeError  as  e : pass\n# 3\nelse : pass\n# 4\nfinally : pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((2, 0), (8, 14)),
            },
            # Please don't write code like this
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("TypeError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            type=cst.Name("KeyError"),
                            name=cst.AsName(cst.Name("e")),
                        ),
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                        ),
                    ),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "code": "try: pass\n"
                + "except TypeError as e: pass\n"
                + "except KeyError as e: pass\n"
                + "except: pass\n"
                + "else: pass\n"
                + "finally: pass\n",
                "parser": parse_statement,
                "expected_position": CodeRange((1, 0), (6, 13)),
            },
            # Verify indentation
            {
                "node": DummyIndentedBlock(
                    "    ",
                    cst.Try(
                        cst.SimpleStatementSuite((cst.Pass(),)),
                        handlers=(
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                type=cst.Name("TypeError"),
                                name=cst.AsName(cst.Name("e")),
                            ),
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                type=cst.Name("KeyError"),
                                name=cst.AsName(cst.Name("e")),
                            ),
                            cst.ExceptHandler(
                                cst.SimpleStatementSuite((cst.Pass(),)),
                                whitespace_after_except=cst.SimpleWhitespace(""),
                            ),
                        ),
                        orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                        finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                    ),
                ),
                "code": "    try: pass\n"
                + "    except TypeError as e: pass\n"
                + "    except KeyError as e: pass\n"
                + "    except: pass\n"
                + "    else: pass\n"
                + "    finally: pass\n",
                "parser": None,
            },
            # Verify indentation in bodies
            {
                "node": DummyIndentedBlock(
                    "    ",
                    cst.Try(
                        cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),)),
                        handlers=(
                            cst.ExceptHandler(
                                cst.IndentedBlock(
                                    (cst.SimpleStatementLine((cst.Pass(),)),)
                                ),
                                whitespace_after_except=cst.SimpleWhitespace(""),
                            ),
                        ),
                        orelse=cst.Else(
                            cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),))
                        ),
                        finalbody=cst.Finally(
                            cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),))
                        ),
                    ),
                ),
                "code": "    try:\n"
                + "        pass\n"
                + "    except:\n"
                + "        pass\n"
                + "    else:\n"
                + "        pass\n"
                + "    finally:\n"
                + "        pass\n",
                "parser": None,
            },
            # No space when using grouping parens
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                            type=cst.Name(
                                "Exception",
                                lpar=(cst.LeftParen(),),
                                rpar=(cst.RightParen(),),
                            ),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept(Exception): pass\n",
                "parser": parse_statement,
            },
            # No space when using tuple
            {
                "node": cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    handlers=(
                        cst.ExceptHandler(
                            cst.SimpleStatementSuite((cst.Pass(),)),
                            whitespace_after_except=cst.SimpleWhitespace(""),
                            type=cst.Tuple(
                                [
                                    cst.Element(
                                        cst.Name("IOError"),
                                        comma=cst.Comma(
                                            whitespace_after=cst.SimpleWhitespace(" ")
                                        ),
                                    ),
                                    cst.Element(cst.Name("ImportError")),
                                ]
                            ),
                        ),
                    ),
                ),
                "code": "try: pass\nexcept(IOError, ImportError): pass\n",
                "parser": parse_statement,
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": lambda: cst.AsName(cst.Name("")),
                "expected_re": "empty name identifier",
            },
            {
                "get_node": lambda: cst.AsName(
                    cst.Name("bla"), whitespace_after_as=cst.SimpleWhitespace("")
                ),
                "expected_re": "between 'as'",
            },
            {
                "get_node": lambda: cst.AsName(
                    cst.Name("bla"), whitespace_before_as=cst.SimpleWhitespace("")
                ),
                "expected_re": "before 'as'",
            },
            {
                "get_node": lambda: cst.ExceptHandler(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    name=cst.AsName(cst.Name("bla")),
                ),
                "expected_re": "name for an empty type",
            },
            {
                "get_node": lambda: cst.ExceptHandler(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    type=cst.Name("TypeError"),
                    whitespace_after_except=cst.SimpleWhitespace(""),
                ),
                "expected_re": "at least one space after except",
            },
            {
                "get_node": lambda: cst.Try(cst.SimpleStatementSuite((cst.Pass(),))),
                "expected_re": "at least one ExceptHandler or Finally",
            },
            {
                "get_node": lambda: cst.Try(
                    cst.SimpleStatementSuite((cst.Pass(),)),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))),
                    finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))),
                ),
                "expected_re": "at least one ExceptHandler in order to have an Else",
            },
            {
                "get_node": lambda: cst.Try(
                    body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                    handlers=(
                        cst.ExceptHandler(
                            body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                        ),
                        cst.ExceptHandler(
                            body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                        ),
                    ),
                ),
                "expected_re": "The bare except: handler must be the last one.",
            },
            {
                "get_node": lambda: cst.Try(
                    body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                    handlers=(
                        cst.ExceptHandler(
                            body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                        ),
                        cst.ExceptHandler(
                            body=cst.SimpleStatementSuite(body=[cst.Pass()]),
                            type=cst.Name("Exception"),
                        ),
                    ),
                ),
                "expected_re": "The bare except: handler must be the last one.",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #7
0
class ReturnParseTest(CSTNodeTest):
    @data_provider(
        (
            {
                "node": cst.SimpleStatementLine(
                    [cst.Return(whitespace_after_return=cst.SimpleWhitespace(""))]
                ),
                "code": "return\n",
                "parser": parse_statement,
            },
            {
                "node": cst.SimpleStatementLine(
                    [
                        cst.Return(
                            cst.Name("abc"),
                            whitespace_after_return=cst.SimpleWhitespace(" "),
                        )
                    ]
                ),
                "code": "return abc\n",
                "parser": parse_statement,
            },
            {
                "node": cst.SimpleStatementLine(
                    [
                        cst.Return(
                            cst.Name("abc"),
                            whitespace_after_return=cst.SimpleWhitespace("   "),
                        )
                    ]
                ),
                "code": "return   abc\n",
                "parser": parse_statement,
            },
            {
                "node": cst.SimpleStatementLine(
                    [
                        cst.Return(
                            cst.Name(
                                "abc", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]
                            ),
                            whitespace_after_return=cst.SimpleWhitespace(""),
                        )
                    ]
                ),
                "code": "return(abc)\n",
                "parser": parse_statement,
            },
            {
                "node": cst.SimpleStatementLine(
                    [
                        cst.Return(
                            cst.Name("abc"),
                            whitespace_after_return=cst.SimpleWhitespace(" "),
                            semicolon=cst.Semicolon(),
                        )
                    ]
                ),
                "code": "return abc;\n",
                "parser": parse_statement,
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)
Example #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",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #9
0
class ImportParseTest(CSTNodeTest):
    @data_provider(
        (
            # Simple import statement
            {
                "node": cst.Import(names=(cst.ImportAlias(cst.Name("foo")),)),
                "code": "import foo",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar"))
                        ),
                    )
                ),
                "code": "import foo.bar",
            },
            # Comma-separated list of imports
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz"))
                        ),
                    )
                ),
                "code": "import foo.bar, foo.baz",
            },
            # Import with an alias
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz",
            },
            # Import with an alias, comma separated
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz")),
                            asname=cst.AsName(cst.Name("bar")),
                        ),
                    )
                ),
                "code": "import foo.bar as baz, foo.baz as bar",
            },
            # Combine for fun and profit
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                            asname=cst.AsName(cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("insta"), cst.Name("gram")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Attribute(cst.Name("foo"), cst.Name("baz")),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"), asname=cst.AsName(cst.Name("ut"))
                        ),
                    )
                ),
                "code": "import foo.bar as baz, insta.gram, foo.baz, unittest as ut",
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.Import(
                    names=(
                        cst.ImportAlias(
                            cst.Attribute(
                                cst.Name("foo"),
                                cst.Name("bar"),
                                dot=cst.Dot(
                                    whitespace_before=cst.SimpleWhitespace(" "),
                                    whitespace_after=cst.SimpleWhitespace(" "),
                                ),
                            ),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "import  foo . bar  as  baz ,  unittest  as  ut",
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(
            parser=lambda code: ensure_type(
                parse_statement(code), cst.SimpleStatementLine
            ).body[0],
            **kwargs,
        )
Example #10
0
class BooleanOperationTest(CSTNodeTest):
    @data_provider((
        # Simple boolean operations
        {
            "node":
            cst.BooleanOperation(cst.Name("foo"), cst.And(), cst.Name("bar")),
            "code":
            "foo and bar",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.BooleanOperation(cst.Name("foo"), cst.Or(), cst.Name("bar")),
            "code":
            "foo or bar",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        # Parenthesized boolean operation
        {
            "node":
            cst.BooleanOperation(
                lpar=(cst.LeftParen(), ),
                left=cst.Name("foo"),
                operator=cst.Or(),
                right=cst.Name("bar"),
                rpar=(cst.RightParen(), ),
            ),
            "code":
            "(foo or bar)",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
        {
            "node":
            cst.BooleanOperation(
                left=cst.Name("foo",
                              lpar=(cst.LeftParen(), ),
                              rpar=(cst.RightParen(), )),
                operator=cst.Or(
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after=cst.SimpleWhitespace(""),
                ),
                right=cst.Name("bar",
                               lpar=(cst.LeftParen(), ),
                               rpar=(cst.RightParen(), )),
            ),
            "code":
            "(foo)or(bar)",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 12)),
        },
        # Make sure that spacing works
        {
            "node":
            cst.BooleanOperation(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                left=cst.Name("foo"),
                operator=cst.And(
                    whitespace_before=cst.SimpleWhitespace("  "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                ),
                right=cst.Name("bar"),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "code":
            "( foo  and  bar )",
            "parser":
            parse_expression,
            "expected_position":
            None,
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node":
            lambda: cst.BooleanOperation(cst.Name("foo"),
                                         cst.And(),
                                         cst.Name("bar"),
                                         lpar=(cst.LeftParen(), )),
            "expected_re":
            "left paren without right paren",
        },
        {
            "get_node":
            lambda: cst.BooleanOperation(
                cst.Name("foo"),
                cst.And(),
                cst.Name("bar"),
                rpar=(cst.RightParen(), ),
            ),
            "expected_re":
            "right paren without left paren",
        },
        {
            "get_node":
            lambda: cst.BooleanOperation(
                left=cst.Name("foo"),
                operator=cst.Or(
                    whitespace_before=cst.SimpleWhitespace(""),
                    whitespace_after=cst.SimpleWhitespace(""),
                ),
                right=cst.Name("bar"),
            ),
            "expected_re":
            "at least one space around boolean operator",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #11
0
class AttributeTest(CSTNodeTest):
    @data_provider(
        (
            # Simple attribute access
            {
                "node": cst.Attribute(cst.Name("foo"), cst.Name("bar")),
                "code": "foo.bar",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 7)),
            },
            # Parenthesized attribute access
            {
                "node": cst.Attribute(
                    lpar=(cst.LeftParen(),),
                    value=cst.Name("foo"),
                    attr=cst.Name("bar"),
                    rpar=(cst.RightParen(),),
                ),
                "code": "(foo.bar)",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 1), (1, 8)),
            },
            # Make sure that spacing works
            {
                "node": cst.Attribute(
                    lpar=(cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),),
                    value=cst.Name("foo"),
                    dot=cst.Dot(
                        whitespace_before=cst.SimpleWhitespace(" "),
                        whitespace_after=cst.SimpleWhitespace(" "),
                    ),
                    attr=cst.Name("bar"),
                    rpar=(cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),),
                ),
                "code": "( foo . bar )",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 2), (1, 11)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": (
                    lambda: cst.Attribute(
                        cst.Name("foo"), cst.Name("bar"), lpar=(cst.LeftParen(),)
                    )
                ),
                "expected_re": "left paren without right paren",
            },
            {
                "get_node": (
                    lambda: cst.Attribute(
                        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)
Example #12
0
class ListTest(CSTNodeTest):

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

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

    @data_provider((
        {
            "code": "{*x, 2}",
            "parser": parse_expression_as(python_version="3.5"),
            "expect_success": True,
        },
        {
            "code": "{*x, 2}",
            "parser": parse_expression_as(python_version="3.3"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        self.assert_parses(**kwargs)
Example #13
0
class ForTest(CSTNodeTest):
    @data_provider((
        # Simple for block
        {
            "node":
            cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "for target in iter(): pass\n",
            "parser":
            parse_statement,
        },
        # Simple async for block
        {
            "node":
            cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async for target in iter(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.7")),
        },
        # Python 3.6 async for block
        {
            "node":
            cst.FunctionDef(
                cst.Name("foo"),
                cst.Parameters(),
                cst.IndentedBlock((cst.For(
                    cst.Name("target"),
                    cst.Call(cst.Name("iter")),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    asynchronous=cst.Asynchronous(),
                ), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async def foo():\n    async for target in iter(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.6")),
        },
        # For block with else
        {
            "node":
            cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))),
            ),
            "code":
            "for target in iter(): pass\nelse: pass\n",
            "parser":
            parse_statement,
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.For(
                    cst.Name("target"),
                    cst.Call(cst.Name("iter")),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                ),
            ),
            "code":
            "    for target in iter(): pass\n",
            "parser":
            None,
        },
        # for an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.For(
                    cst.Name("target"),
                    cst.Call(cst.Name("iter")),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    for target in iter():\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
                cst.Else(
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                    leading_lines=(cst.EmptyLine(
                        comment=cst.Comment("# else comment")), ),
                ),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nfor target in iter():\n    pass\n# else comment\nelse:\n    pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((2, 0), (6, 8)),
        },
        # Weird spacing rules
        {
            "node":
            cst.For(
                cst.Name("target",
                         lpar=(cst.LeftParen(), ),
                         rpar=(cst.RightParen(), )),
                cst.Call(
                    cst.Name("iter"),
                    lpar=(cst.LeftParen(), ),
                    rpar=(cst.RightParen(), ),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_for=cst.SimpleWhitespace(""),
                whitespace_before_in=cst.SimpleWhitespace(""),
                whitespace_after_in=cst.SimpleWhitespace(""),
            ),
            "code":
            "for(target)in(iter()): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 27)),
        },
        # Whitespace
        {
            "node":
            cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_for=cst.SimpleWhitespace("  "),
                whitespace_before_in=cst.SimpleWhitespace("  "),
                whitespace_after_in=cst.SimpleWhitespace("  "),
                whitespace_before_colon=cst.SimpleWhitespace("  "),
            ),
            "code":
            "for  target  in  iter()  : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 31)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node":
            lambda: cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_for=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after 'for' keyword",
        },
        {
            "get_node":
            lambda: cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_before_in=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space before 'in' keyword",
        },
        {
            "get_node":
            lambda: cst.For(
                cst.Name("target"),
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_in=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after 'in' keyword",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #14
0
class IfTest(CSTNodeTest):
    @data_provider((
        # Simple if without elif or else
        # pyre-fixme[6]: Incompatible parameter type
        {
            "node":
            cst.If(cst.Name("conditional"),
                   cst.SimpleStatementSuite((cst.Pass(), ))),
            "code":
            "if conditional: pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 20)),
        },
        # else clause
        {
            "node":
            cst.If(
                cst.Name("conditional"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))),
            ),
            "code":
            "if conditional: pass\nelse: pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (2, 10)),
        },
        # elif clause
        {
            "node":
            cst.If(
                cst.Name("conditional"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                orelse=cst.If(
                    cst.Name("other_conditional"),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))),
                ),
            ),
            "code":
            "if conditional: pass\nelif other_conditional: pass\nelse: pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (3, 10)),
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.If(
                    cst.Name("conditional"),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))),
                ),
            ),
            "code":
            "    if conditional: pass\n    else: pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange.create((1, 4), (2, 14)),
        },
        # with an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.If(
                    cst.Name("conditional"),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    if conditional:\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange.create((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.If(
                cst.Name("conditional"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nif conditional: pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((2, 0), (2, 20)),
        },
        # whitespace before/after test and else
        {
            "node":
            cst.If(
                cst.Name("conditional"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_before_test=cst.SimpleWhitespace("   "),
                whitespace_after_test=cst.SimpleWhitespace("  "),
                orelse=cst.Else(
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    whitespace_before_colon=cst.SimpleWhitespace(" "),
                ),
            ),
            "code":
            "if   conditional  : pass\nelse : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (2, 11)),
        },
        # empty lines between if/elif/else clauses, not captured by the suite.
        {
            "node":
            cst.If(
                cst.Name("test_a"),
                cst.SimpleStatementSuite((cst.Pass(), )),
                orelse=cst.If(
                    cst.Name("test_b"),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    leading_lines=(cst.EmptyLine(), ),
                    orelse=cst.Else(
                        cst.SimpleStatementSuite((cst.Pass(), )),
                        leading_lines=(cst.EmptyLine(), ),
                    ),
                ),
            ),
            "code":
            "if test_a: pass\n\nelif test_b: pass\n\nelse: pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (5, 10)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)
Example #15
0
class WhileTest(CSTNodeTest):
    @data_provider((
        # Simple while block
        {
            "node":
            cst.While(cst.Call(cst.Name("iter")),
                      cst.SimpleStatementSuite((cst.Pass(), ))),
            "code":
            "while iter(): pass\n",
            "parser":
            parse_statement,
        },
        # While block with else
        {
            "node":
            cst.While(
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))),
            ),
            "code":
            "while iter(): pass\nelse: pass\n",
            "parser":
            parse_statement,
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.While(
                    cst.Call(cst.Name("iter")),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                ),
            ),
            "code":
            "    while iter(): pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (1, 22)),
        },
        # while an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.While(
                    cst.Call(cst.Name("iter")),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    while iter():\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.While(
                cst.Call(cst.Name("iter")),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nwhile iter():\n    pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((2, 0), (3, 8)),
        },
        {
            "node":
            cst.While(
                cst.Call(cst.Name("iter")),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
                cst.Else(
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                    leading_lines=(cst.EmptyLine(
                        comment=cst.Comment("# else comment")), ),
                ),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nwhile iter():\n    pass\n# else comment\nelse:\n    pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((2, 0), (6, 8)),
        },
        # Weird spacing rules
        {
            "node":
            cst.While(
                cst.Call(
                    cst.Name("iter"),
                    lpar=(cst.LeftParen(), ),
                    rpar=(cst.RightParen(), ),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_while=cst.SimpleWhitespace(""),
            ),
            "code":
            "while(iter()): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 19)),
        },
        # Whitespace
        {
            "node":
            cst.While(
                cst.Call(cst.Name("iter")),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_while=cst.SimpleWhitespace("  "),
                whitespace_before_colon=cst.SimpleWhitespace("  "),
            ),
            "code":
            "while  iter()  : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 21)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(({
        "get_node":
        lambda: cst.While(
            cst.Call(cst.Name("iter")),
            cst.SimpleStatementSuite((cst.Pass(), )),
            whitespace_after_while=cst.SimpleWhitespace(""),
        ),
        "expected_re":
        "Must have at least one space after 'while' keyword",
    }, ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #16
0
class ImportFromCreateTest(CSTNodeTest):
    @data_provider(
        (
            # Simple from import statement
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"), names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "code": "from foo import bar",
            },
            # From import statement with alias
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                ),
                "code": "from foo import bar as baz",
            },
            # Multiple imports
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(cst.Name("bar")),
                        cst.ImportAlias(cst.Name("baz")),
                    ),
                ),
                "code": "from foo import bar, baz",
            },
            # Trailing comma
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(cst.Name("bar"), comma=cst.Comma()),
                        cst.ImportAlias(cst.Name("baz"), comma=cst.Comma()),
                    ),
                ),
                "code": "from foo import bar,baz,",
                "expected_position": CodeRange((1, 0), (1, 23)),
            },
            # Star import statement
            {
                "node": cst.ImportFrom(module=cst.Name("foo"), names=cst.ImportStar()),
                "code": "from foo import *",
                "expected_position": CodeRange((1, 0), (1, 17)),
            },
            # Simple relative import statement
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(),),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .foo import bar",
            },
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from ..foo import bar",
            },
            # Relative only import
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=None,
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .. import bar",
            },
            # Parenthesis
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                    rpar=cst.RightParen(),
                ),
                "code": "from foo import (bar as baz)",
                "expected_position": CodeRange((1, 0), (1, 28)),
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.ImportFrom(
                    relative=(
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
                    whitespace_after_from=cst.SimpleWhitespace("  "),
                    whitespace_before_import=cst.SimpleWhitespace("  "),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "from   .  . foo  import  ( bar  as  baz ,  unittest  as  ut )",
                "expected_position": CodeRange((1, 0), (1, 61)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        (
            {
                "get_node": lambda: cst.ImportFrom(
                    module=None, names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "expected_re": "Must have a module specified",
            },
            {
                "get_node": lambda: cst.ImportFrom(module=cst.Name("foo"), names=()),
                "expected_re": "at least one ImportAlias",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    lpar=cst.LeftParen(),
                ),
                "expected_re": "left paren without right paren",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    rpar=cst.RightParen(),
                ),
                "expected_re": "right paren without left paren",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"), names=cst.ImportStar(), lpar=cst.LeftParen()
                ),
                "expected_re": "cannot have parens",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=cst.ImportStar(),
                    rpar=cst.RightParen(),
                ),
                "expected_re": "cannot have parens",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_after_from=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space after from",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_before_import=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space before import",
            },
            {
                "get_node": lambda: cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                    whitespace_after_import=cst.SimpleWhitespace(""),
                ),
                "expected_re": "one space after import",
            },
        )
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #17
0
 def _string_visit(
     self, original_node: cst.SimpleString,
     updated_node: cst.SimpleString
 ) -> cst.BaseParenthesizableWhitespace:
     return cst.SimpleWhitespace("")
Example #18
0
class ImportFromParseTest(CSTNodeTest):
    @data_provider(
        (
            # Simple from import statement
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"), names=(cst.ImportAlias(cst.Name("bar")),)
                ),
                "code": "from foo import bar",
            },
            # From import statement with alias
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                ),
                "code": "from foo import bar as baz",
            },
            # Multiple imports
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(cst.Name("baz")),
                    ),
                ),
                "code": "from foo import bar, baz",
            },
            # Trailing comma
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.ImportAlias(cst.Name("baz"), comma=cst.Comma()),
                    ),
                ),
                "code": "from foo import bar, baz,",
            },
            # Star import statement
            {
                "node": cst.ImportFrom(module=cst.Name("foo"), names=cst.ImportStar()),
                "code": "from foo import *",
            },
            # Simple relative import statement
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(),),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .foo import bar",
            },
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=cst.Name("foo"),
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from ..foo import bar",
            },
            # Relative only import
            {
                "node": cst.ImportFrom(
                    relative=(cst.Dot(), cst.Dot()),
                    module=None,
                    names=(cst.ImportAlias(cst.Name("bar")),),
                ),
                "code": "from .. import bar",
            },
            # Parenthesis
            {
                "node": cst.ImportFrom(
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"), asname=cst.AsName(cst.Name("baz"))
                        ),
                    ),
                    rpar=cst.RightParen(),
                ),
                "code": "from foo import (bar as baz)",
            },
            # Verify whitespace works everywhere.
            {
                "node": cst.ImportFrom(
                    relative=(
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                        cst.Dot(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                    ),
                    module=cst.Name("foo"),
                    lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")),
                    names=(
                        cst.ImportAlias(
                            cst.Name("bar"),
                            asname=cst.AsName(
                                cst.Name("baz"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                            comma=cst.Comma(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace("  "),
                            ),
                        ),
                        cst.ImportAlias(
                            cst.Name("unittest"),
                            asname=cst.AsName(
                                cst.Name("ut"),
                                whitespace_before_as=cst.SimpleWhitespace("  "),
                                whitespace_after_as=cst.SimpleWhitespace("  "),
                            ),
                        ),
                    ),
                    rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")),
                    whitespace_after_from=cst.SimpleWhitespace("   "),
                    whitespace_before_import=cst.SimpleWhitespace("  "),
                    whitespace_after_import=cst.SimpleWhitespace("  "),
                ),
                "code": "from   .  . foo  import  ( bar  as  baz ,  unittest  as  ut )",
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(
            parser=lambda code: ensure_type(
                parse_statement(code), cst.SimpleStatementLine
            ).body[0],
            **kwargs,
        )
Example #19
0
class ComparisonTest(CSTNodeTest):
    @data_provider((
        # Simple comparison statements
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.LessThan(), cst.Integer("5")), ),
            ),
            "foo < 5",
        ),
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.NotEqual(), cst.Integer("5")), ),
            ),
            "foo != 5",
        ),
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.Is(), cst.Name("True")), )),
            "foo is True",
        ),
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.IsNot(), cst.Name("False")), ),
            ),
            "foo is not False",
        ),
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.In(), cst.Name("bar")), )),
            "foo in bar",
        ),
        (
            cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.NotIn(), cst.Name("bar")), ),
            ),
            "foo not in bar",
        ),
        # Comparison with parens
        (
            cst.Comparison(
                lpar=(cst.LeftParen(), ),
                left=cst.Name("foo"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.NotIn(), comparator=cst.Name("bar")), ),
                rpar=(cst.RightParen(), ),
            ),
            "(foo not in bar)",
        ),
        (
            cst.Comparison(
                left=cst.Name("a",
                              lpar=(cst.LeftParen(), ),
                              rpar=(cst.RightParen(), )),
                comparisons=(
                    cst.ComparisonTarget(
                        operator=cst.Is(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        comparator=cst.Name("b",
                                            lpar=(cst.LeftParen(), ),
                                            rpar=(cst.RightParen(), )),
                    ),
                    cst.ComparisonTarget(
                        operator=cst.Is(
                            whitespace_before=cst.SimpleWhitespace(""),
                            whitespace_after=cst.SimpleWhitespace(""),
                        ),
                        comparator=cst.Name("c",
                                            lpar=(cst.LeftParen(), ),
                                            rpar=(cst.RightParen(), )),
                    ),
                ),
            ),
            "(a)is(b)is(c)",
        ),
        # Valid expressions that look like they shouldn't parse
        (
            cst.Comparison(
                left=cst.Integer("5"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.NotIn(
                        whitespace_before=cst.SimpleWhitespace("")),
                    comparator=cst.Name("bar"),
                ), ),
            ),
            "5not in bar",
        ),
        # Validate that spacing works properly
        (
            cst.Comparison(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                left=cst.Name("foo"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.NotIn(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_between=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("  "),
                    ),
                    comparator=cst.Name("bar"),
                ), ),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
            ),
            "( foo  not  in  bar )",
        ),
        # Do some complex nodes
        (
            cst.Comparison(
                left=cst.Name("baz"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.Equal(),
                    comparator=cst.Comparison(
                        lpar=(cst.LeftParen(), ),
                        left=cst.Name("foo"),
                        comparisons=(cst.ComparisonTarget(
                            operator=cst.NotIn(),
                            comparator=cst.Name("bar")), ),
                        rpar=(cst.RightParen(), ),
                    ),
                ), ),
            ),
            "baz == (foo not in bar)",
            CodeRange((1, 0), (1, 23)),
        ),
        (
            cst.Comparison(
                left=cst.Name("a"),
                comparisons=(
                    cst.ComparisonTarget(operator=cst.GreaterThan(),
                                         comparator=cst.Name("b")),
                    cst.ComparisonTarget(operator=cst.GreaterThan(),
                                         comparator=cst.Name("c")),
                ),
            ),
            "a > b > c",
            CodeRange((1, 0), (1, 9)),
        ),
        # Is safe to use with word operators if it's leading/trailing children are
        (
            cst.IfExp(
                body=cst.Comparison(
                    left=cst.Name("a"),
                    comparisons=(cst.ComparisonTarget(
                        operator=cst.GreaterThan(),
                        comparator=cst.Name(
                            "b",
                            lpar=(cst.LeftParen(), ),
                            rpar=(cst.RightParen(), ),
                        ),
                    ), ),
                ),
                test=cst.Comparison(
                    left=cst.Name("c",
                                  lpar=(cst.LeftParen(), ),
                                  rpar=(cst.RightParen(), )),
                    comparisons=(cst.ComparisonTarget(
                        operator=cst.GreaterThan(),
                        comparator=cst.Name("d")), ),
                ),
                orelse=cst.Name("e"),
                whitespace_before_if=cst.SimpleWhitespace(""),
                whitespace_after_if=cst.SimpleWhitespace(""),
            ),
            "a > (b)if(c) > d else e",
        ),
        # is safe to use with word operators if entirely surrounded in parenthesis
        (
            cst.IfExp(
                body=cst.Name("a"),
                test=cst.Comparison(
                    left=cst.Name("b"),
                    comparisons=(cst.ComparisonTarget(
                        operator=cst.GreaterThan(),
                        comparator=cst.Name("c")), ),
                    lpar=(cst.LeftParen(), ),
                    rpar=(cst.RightParen(), ),
                ),
                orelse=cst.Name("d"),
                whitespace_after_if=cst.SimpleWhitespace(""),
                whitespace_before_else=cst.SimpleWhitespace(""),
            ),
            "a if(b > c)else d",
        ),
    ))
    def test_valid(self,
                   node: cst.CSTNode,
                   code: str,
                   position: Optional[CodeRange] = None) -> None:
        self.validate_node(node,
                           code,
                           parse_expression,
                           expected_position=position)

    @data_provider((
        (
            lambda: cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.LessThan(), cst.Integer("5")), ),
                lpar=(cst.LeftParen(), ),
            ),
            "left paren without right paren",
        ),
        (
            lambda: cst.Comparison(
                cst.Name("foo"),
                (cst.ComparisonTarget(cst.LessThan(), cst.Integer("5")), ),
                rpar=(cst.RightParen(), ),
            ),
            "right paren without left paren",
        ),
        (
            lambda: cst.Comparison(cst.Name("foo"), ()),
            "at least one ComparisonTarget",
        ),
        (
            lambda: cst.Comparison(
                left=cst.Name("foo"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.NotIn(whitespace_before=cst.SimpleWhitespace(
                        "")),
                    comparator=cst.Name("bar"),
                ), ),
            ),
            "at least one space around comparison operator",
        ),
        (
            lambda: cst.Comparison(
                left=cst.Name("foo"),
                comparisons=(cst.ComparisonTarget(
                    operator=cst.NotIn(whitespace_after=cst.SimpleWhitespace(
                        "")),
                    comparator=cst.Name("bar"),
                ), ),
            ),
            "at least one space around comparison operator",
        ),
        # multi-target comparisons
        (
            lambda: cst.Comparison(
                left=cst.Name("a"),
                comparisons=(
                    cst.ComparisonTarget(operator=cst.Is(),
                                         comparator=cst.Name("b")),
                    cst.ComparisonTarget(
                        operator=cst.Is(whitespace_before=cst.SimpleWhitespace(
                            "")),
                        comparator=cst.Name("c"),
                    ),
                ),
            ),
            "at least one space around comparison operator",
        ),
        (
            lambda: cst.Comparison(
                left=cst.Name("a"),
                comparisons=(
                    cst.ComparisonTarget(operator=cst.Is(),
                                         comparator=cst.Name("b")),
                    cst.ComparisonTarget(
                        operator=cst.Is(whitespace_after=cst.SimpleWhitespace(
                            "")),
                        comparator=cst.Name("c"),
                    ),
                ),
            ),
            "at least one space around comparison operator",
        ),
        # whitespace around the comparision itself
        # a ifb > c else d
        (
            lambda: cst.IfExp(
                body=cst.Name("a"),
                test=cst.Comparison(
                    left=cst.Name("b"),
                    comparisons=(cst.
                                 ComparisonTarget(operator=cst.GreaterThan(),
                                                  comparator=cst.Name("c")), ),
                ),
                orelse=cst.Name("d"),
                whitespace_after_if=cst.SimpleWhitespace(""),
            ),
            "Must have at least one space after 'if' keyword.",
        ),
        # a if b > celse d
        (
            lambda: cst.IfExp(
                body=cst.Name("a"),
                test=cst.Comparison(
                    left=cst.Name("b"),
                    comparisons=(cst.
                                 ComparisonTarget(operator=cst.GreaterThan(),
                                                  comparator=cst.Name("c")), ),
                ),
                orelse=cst.Name("d"),
                whitespace_before_else=cst.SimpleWhitespace(""),
            ),
            "Must have at least one space before 'else' keyword.",
        ),
    ))
    def test_invalid(self, get_node: Callable[[], cst.CSTNode],
                     expected_re: str) -> None:
        self.assert_invalid(get_node, expected_re)
Example #20
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)
Example #21
0
class SmallStatementTest(CSTNodeTest):
    @data_provider(
        (
            # pyre-fixme[6]: Incompatible parameter type
            {"node": cst.Pass(), "code": "pass"},
            {"node": cst.Pass(semicolon=cst.Semicolon()), "code": "pass;"},
            {
                "node": cst.Pass(
                    semicolon=cst.Semicolon(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("    "),
                    )
                ),
                "code": "pass  ;    ",
                "expected_position": CodeRange.create((1, 0), (1, 4)),
            },
            {"node": cst.Continue(), "code": "continue"},
            {"node": cst.Continue(semicolon=cst.Semicolon()), "code": "continue;"},
            {
                "node": cst.Continue(
                    semicolon=cst.Semicolon(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("    "),
                    )
                ),
                "code": "continue  ;    ",
                "expected_position": CodeRange.create((1, 0), (1, 8)),
            },
            {"node": cst.Break(), "code": "break"},
            {"node": cst.Break(semicolon=cst.Semicolon()), "code": "break;"},
            {
                "node": cst.Break(
                    semicolon=cst.Semicolon(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("    "),
                    )
                ),
                "code": "break  ;    ",
                "expected_position": CodeRange.create((1, 0), (1, 5)),
            },
            {
                "node": cst.Expr(
                    cst.BinaryOperation(cst.Name("x"), cst.Add(), cst.Name("y"))
                ),
                "code": "x + y",
            },
            {
                "node": cst.Expr(
                    cst.BinaryOperation(cst.Name("x"), cst.Add(), cst.Name("y")),
                    semicolon=cst.Semicolon(),
                ),
                "code": "x + y;",
            },
            {
                "node": cst.Expr(
                    cst.BinaryOperation(cst.Name("x"), cst.Add(), cst.Name("y")),
                    semicolon=cst.Semicolon(
                        whitespace_before=cst.SimpleWhitespace("  "),
                        whitespace_after=cst.SimpleWhitespace("    "),
                    ),
                ),
                "code": "x + y  ;    ",
                "expected_position": CodeRange.create((1, 0), (1, 5)),
            },
        )
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)
Example #22
0
class LambdaCreationTest(CSTNodeTest):
    @data_provider((
        # Simple lambda
        (cst.Lambda(cst.Parameters(), cst.Integer("5")), "lambda: 5"),
        # Test basic positional only params
        {
            "node":
            cst.Lambda(
                cst.Parameters(posonly_params=(
                    cst.Param(cst.Name("bar")),
                    cst.Param(cst.Name("baz")),
                )),
                cst.Integer("5"),
            ),
            "code":
            "lambda bar, baz, /: 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(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")),
                    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 params and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    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 and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(cst.Name("first")),
                        cst.Param(cst.Name("second")),
                        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, star_arg and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    params=(
                        cst.Param(cst.Name("first")),
                        cst.Param(cst.Name("second")),
                        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(posonly_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(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(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.Param(cst.Name("bar")),
                )),
                cst.Integer("5"),
            ),
            "Cannot have param without defaults following a param with defaults.",
        ),
        (
            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(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(posonly_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(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(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)
Example #23
0
class DelTest(CSTNodeTest):
    @data_provider((
        {
            "node": cst.SimpleStatementLine([cst.Del(cst.Name("abc"))]),
            "code": "del abc\n",
            "parser": parse_statement,
            "expected_position": CodeRange.create((1, 0), (1, 7)),
        },
        {
            "node":
            cst.SimpleStatementLine([
                cst.Del(
                    cst.Name("abc"),
                    whitespace_after_del=cst.SimpleWhitespace("   "),
                )
            ]),
            "code":
            "del   abc\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 9)),
        },
        {
            "node":
            cst.SimpleStatementLine([
                cst.Del(
                    cst.Name("abc",
                             lpar=[cst.LeftParen()],
                             rpar=[cst.RightParen()]),
                    whitespace_after_del=cst.SimpleWhitespace(""),
                )
            ]),
            "code":
            "del(abc)\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 8)),
        },
        {
            "node":
            cst.SimpleStatementLine(
                [cst.Del(cst.Name("abc"), semicolon=cst.Semicolon())]),
            "code":
            "del abc;\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange.create((1, 0), (1, 7)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(({
        "get_node":
        lambda: cst.Del(cst.Name("abc"),
                        whitespace_after_del=cst.SimpleWhitespace("")),
        "expected_re":
        "Must have at least one space after 'del'.",
    }, ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #24
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(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(" ")),
                    ),
                    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 params and kwonly_params
        (
            cst.Lambda(
                cst.Parameters(
                    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 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(" ")),
                        ),
                        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, 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(" ")),
                        ),
                        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)

    @data_provider((
        # Test basic positional only params
        {
            "node":
            cst.Lambda(
                cst.Parameters(
                    posonly_params=(
                        cst.Param(
                            cst.Name("bar"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                        cst.Param(
                            cst.Name("baz"),
                            star="",
                            comma=cst.Comma(
                                whitespace_after=cst.SimpleWhitespace(" ")),
                        ),
                    ),
                    posonly_ind=cst.ParamSlash(),
                ),
                cst.Integer("5"),
                whitespace_after_lambda=cst.SimpleWhitespace(" "),
            ),
            "code":
            "lambda bar, baz, /: 5",
        }, ))
    def test_valid_38(self,
                      node: cst.CSTNode,
                      code: str,
                      position: Optional[CodeRange] = None) -> None:
        self.validate_node(node, code, _parse_expression_force_38, position)
Example #25
0
 def leave_ParenthesizedWhitespace(
     self,
     original_node: cst.ParenthesizedWhitespace,
     updated_node: cst.ParenthesizedWhitespace,
 ) -> cst.SimpleWhitespace:
     return cst.SimpleWhitespace(" ")
Example #26
0
class WithTest(CSTNodeTest):
    @data_provider((
        # Simple with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 24)),
        },
        # Simple async with block
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.7")),
        },
        # Python 3.6 async with block
        {
            "node":
            cst.FunctionDef(
                cst.Name("foo"),
                cst.Parameters(),
                cst.IndentedBlock((cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                    asynchronous=cst.Asynchronous(),
                ), )),
                asynchronous=cst.Asynchronous(),
            ),
            "code":
            "async def foo():\n    async with context_mgr(): pass\n",
            "parser":
            lambda code: parse_statement(
                code, config=PartialParserConfig(python_version="3.6")),
        },
        # Multiple context managers
        {
            "node":
            cst.With(
                (
                    cst.WithItem(cst.Call(cst.Name("foo"))),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            None,
        },
        {
            "node":
            cst.With(
                (
                    cst.WithItem(
                        cst.Call(cst.Name("foo")),
                        comma=cst.Comma(
                            whitespace_after=cst.SimpleWhitespace(" ")),
                    ),
                    cst.WithItem(cst.Call(cst.Name("bar"))),
                ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with foo(), bar(): pass\n",
            "parser":
            parse_statement,
        },
        # With block containing variable for context manager.
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(cst.Name("ctx")),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
            ),
            "code":
            "with context_mgr() as ctx: pass\n",
            "parser":
            parse_statement,
        },
        # indentation
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.SimpleStatementSuite((cst.Pass(), )),
                ),
            ),
            "code":
            "    with context_mgr(): pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (1, 28)),
        },
        # with an indented body
        {
            "node":
            DummyIndentedBlock(
                "    ",
                cst.With(
                    (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                    cst.IndentedBlock((cst.SimpleStatementLine(
                        (cst.Pass(), )), )),
                ),
            ),
            "code":
            "    with context_mgr():\n        pass\n",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 4), (2, 12)),
        },
        # leading_lines
        {
            "node":
            cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                leading_lines=(cst.EmptyLine(
                    comment=cst.Comment("# leading comment")), ),
            ),
            "code":
            "# leading comment\nwith context_mgr(): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((2, 0), (2, 24)),
        },
        # Weird spacing rules
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(
                        cst.Name("context_mgr"),
                        lpar=(cst.LeftParen(), ),
                        rpar=(cst.RightParen(), ),
                    )), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "code":
            "with(context_mgr()): pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 25)),
        },
        # Whitespace
        {
            "node":
            cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("context_mgr")),
                    cst.AsName(
                        cst.Name("ctx"),
                        whitespace_before_as=cst.SimpleWhitespace("  "),
                        whitespace_after_as=cst.SimpleWhitespace("  "),
                    ),
                ), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace("  "),
                whitespace_before_colon=cst.SimpleWhitespace("  "),
            ),
            "code":
            "with  context_mgr()  as  ctx  : pass\n",
            "parser":
            parse_statement,
            "expected_position":
            CodeRange((1, 0), (1, 36)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        {
            "get_node":
            lambda: cst.With((),
                             cst.IndentedBlock((cst.SimpleStatementLine(
                                 (cst.Pass(), )), ))),
            "expected_re":
            "A With statement must have at least one WithItem",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(
                    cst.Call(cst.Name("foo")),
                    comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ")
                                    ),
                ), ),
                cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )),
            ),
            "expected_re":
            "The last WithItem in a With cannot have a trailing comma",
        },
        {
            "get_node":
            lambda: cst.With(
                (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ),
                cst.SimpleStatementSuite((cst.Pass(), )),
                whitespace_after_with=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after with keyword",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #27
0
class NonlocalConstructionTest(CSTNodeTest):
    @data_provider((
        # Single nonlocal statement
        {
            "node": cst.Nonlocal((cst.NameItem(cst.Name("a")), )),
            "code": "nonlocal a",
        },
        # Multiple entries in nonlocal statement
        {
            "node":
            cst.Nonlocal(
                (cst.NameItem(cst.Name("a")), cst.NameItem(cst.Name("b")))),
            "code":
            "nonlocal a, b",
            "expected_position":
            CodeRange((1, 0), (1, 13)),
        },
        # Whitespace rendering test
        {
            "node":
            cst.Nonlocal(
                (
                    cst.NameItem(
                        cst.Name("a"),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace("  "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.NameItem(cst.Name("b")),
                ),
                whitespace_after_nonlocal=cst.SimpleWhitespace("  "),
            ),
            "code":
            "nonlocal  a  ,  b",
            "expected_position":
            CodeRange((1, 0), (1, 17)),
        },
    ))
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider((
        # Validate construction
        {
            "get_node": lambda: cst.Nonlocal(()),
            "expected_re":
            "A Nonlocal statement must have at least one NameItem",
        },
        # Validate whitespace handling
        {
            "get_node":
            lambda: cst.Nonlocal(
                (cst.NameItem(cst.Name("a")), ),
                whitespace_after_nonlocal=cst.SimpleWhitespace(""),
            ),
            "expected_re":
            "Must have at least one space after 'nonlocal' keyword",
        },
        # Validate comma handling
        {
            "get_node":
            lambda: cst.Nonlocal(
                (cst.NameItem(cst.Name("a"), comma=cst.Comma()), )),
            "expected_re":
            "The last NameItem in a Nonlocal cannot have a trailing comma",
        },
        # Validate paren handling
        {
            "get_node":
            lambda: cst.Nonlocal((cst.NameItem(
                cst.Name("a",
                         lpar=(cst.LeftParen(), ),
                         rpar=(cst.RightParen(), ))), )),
            "expected_re":
            "Cannot have parens around names in NameItem",
        },
    ))
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #28
0
class DictTest(CSTNodeTest):
    @data_provider([
        # zero-element dict
        {
            "node": cst.Dict([]),
            "code": "{}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 2)),
        },
        # one-element dict, sentinel comma value
        {
            "node": cst.Dict([cst.DictElement(cst.Name("k"), cst.Name("v"))]),
            "code": "{k: v}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 6)),
        },
        {
            "node": cst.Dict([cst.StarredDictElement(cst.Name("expanded"))]),
            "code": "{**expanded}",
            "parser": parse_expression,
            "expected_position": CodeRange((1, 0), (1, 12)),
        },
        # two-element dict, sentinel comma value
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k1"), cst.Name("v1")),
                cst.DictElement(cst.Name("k2"), cst.Name("v2")),
            ]),
            "code":
            "{k1: v1, k2: v2}",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 16)),
        },
        # custom whitespace between brackets
        {
            "node":
            cst.Dict(
                [cst.DictElement(cst.Name("k"), cst.Name("v"))],
                lbrace=cst.LeftCurlyBrace(
                    whitespace_after=cst.SimpleWhitespace("\t")),
                rbrace=cst.RightCurlyBrace(
                    whitespace_before=cst.SimpleWhitespace("\t\t")),
            ),
            "code":
            "{\tk: v\t\t}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 9)),
        },
        # with parenthesis
        {
            "node":
            cst.Dict(
                [cst.DictElement(cst.Name("k"), cst.Name("v"))],
                lpar=[cst.LeftParen()],
                rpar=[cst.RightParen()],
            ),
            "code":
            "({k: v})",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 1), (1, 7)),
        },
        # starred element
        {
            "node":
            cst.Dict([
                cst.StarredDictElement(cst.Name("one")),
                cst.StarredDictElement(cst.Name("two")),
            ]),
            "code":
            "{**one, **two}",
            "parser":
            None,
            "expected_position":
            CodeRange((1, 0), (1, 14)),
        },
        # custom comma on DictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k"),
                                cst.Name("v"),
                                comma=cst.Comma())
            ]),
            "code":
            "{k: v,}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 7)),
        },
        # custom comma on StarredDictElement
        {
            "node":
            cst.Dict([
                cst.StarredDictElement(cst.Name("expanded"), comma=cst.Comma())
            ]),
            "code":
            "{**expanded,}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 13)),
        },
        # custom whitespace on DictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(
                    cst.Name("k"),
                    cst.Name("v"),
                    whitespace_before_colon=cst.SimpleWhitespace("\t"),
                    whitespace_after_colon=cst.SimpleWhitespace("\t\t"),
                )
            ]),
            "code":
            "{k\t:\t\tv}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 8)),
        },
        # custom whitespace on StarredDictElement
        {
            "node":
            cst.Dict([
                cst.DictElement(cst.Name("k"),
                                cst.Name("v"),
                                comma=cst.Comma()),
                cst.StarredDictElement(
                    cst.Name("expanded"),
                    whitespace_before_value=cst.SimpleWhitespace("  "),
                ),
            ]),
            "code":
            "{k: v,**  expanded}",
            "parser":
            parse_expression,
            "expected_position":
            CodeRange((1, 0), (1, 19)),
        },
        # missing spaces around dict is always okay
        {
            "node":
            cst.GeneratorExp(
                cst.Name("a"),
                cst.CompFor(
                    cst.Name("b"),
                    cst.Dict([cst.DictElement(cst.Name("k"), cst.Name("v"))]),
                    ifs=[
                        cst.CompIf(
                            cst.Name("c"),
                            whitespace_before=cst.SimpleWhitespace(""),
                        )
                    ],
                    whitespace_after_in=cst.SimpleWhitespace(""),
                ),
            ),
            "parser":
            parse_expression,
            "code":
            "(a for b in{k: v}if c)",
        },
    ])
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

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

    @data_provider((
        {
            "code": "{**{}}",
            "parser": parse_expression_as(python_version="3.5"),
            "expect_success": True,
        },
        {
            "code": "{**{}}",
            "parser": parse_expression_as(python_version="3.3"),
            "expect_success": False,
        },
    ))
    def test_versions(self, **kwargs: Any) -> None:
        if is_native() and not kwargs.get("expect_success", True):
            self.skipTest("parse errors are disabled for native parser")
        self.assert_parses(**kwargs)
Example #29
0
class DictCompTest(CSTNodeTest):
    @data_provider(
        [
            # simple DictComp
            {
                "node": cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(target=cst.Name("a"), iter=cst.Name("b")),
                ),
                "code": "{k: v for a in b}",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 17)),
            },
            # custom whitespace around colon
            {
                "node": cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(target=cst.Name("a"), iter=cst.Name("b")),
                    whitespace_before_colon=cst.SimpleWhitespace("\t"),
                    whitespace_after_colon=cst.SimpleWhitespace("\t\t"),
                ),
                "code": "{k\t:\t\tv for a in b}",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 19)),
            },
            # custom whitespace inside braces
            {
                "node": cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(target=cst.Name("a"), iter=cst.Name("b")),
                    lbrace=cst.LeftCurlyBrace(
                        whitespace_after=cst.SimpleWhitespace("\t")
                    ),
                    rbrace=cst.RightCurlyBrace(
                        whitespace_before=cst.SimpleWhitespace("\t\t")
                    ),
                ),
                "code": "{\tk: v for a in b\t\t}",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 20)),
            },
            # parenthesis
            {
                "node": cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(target=cst.Name("a"), iter=cst.Name("b")),
                    lpar=[cst.LeftParen()],
                    rpar=[cst.RightParen()],
                ),
                "code": "({k: v for a in b})",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 1), (1, 18)),
            },
            # missing spaces around DictComp is always okay
            {
                "node": cst.DictComp(
                    cst.Name("a"),
                    cst.Name("b"),
                    cst.CompFor(
                        target=cst.Name("c"),
                        iter=cst.DictComp(
                            cst.Name("d"),
                            cst.Name("e"),
                            cst.CompFor(target=cst.Name("f"), iter=cst.Name("g")),
                        ),
                        ifs=[
                            cst.CompIf(
                                cst.Name("h"),
                                whitespace_before=cst.SimpleWhitespace(""),
                            )
                        ],
                        whitespace_after_in=cst.SimpleWhitespace(""),
                    ),
                ),
                "code": "{a: b for c in{d: e for f in g}if h}",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 36)),
            },
            # no whitespace before `for` clause
            {
                "node": cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v", lpar=[cst.LeftParen()], rpar=[cst.RightParen()]),
                    cst.CompFor(
                        target=cst.Name("a"),
                        iter=cst.Name("b"),
                        whitespace_before=cst.SimpleWhitespace(""),
                    ),
                ),
                "code": "{k: (v)for a in b}",
                "parser": parse_expression,
                "expected_position": CodeRange((1, 0), (1, 18)),
            },
        ]
    )
    def test_valid(self, **kwargs: Any) -> None:
        self.validate_node(**kwargs)

    @data_provider(
        [
            # unbalanced DictComp
            {
                "get_node": lambda: cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(target=cst.Name("a"), iter=cst.Name("b")),
                    lpar=[cst.LeftParen()],
                ),
                "expected_re": "left paren without right paren",
            },
            # invalid whitespace before for/async
            {
                "get_node": lambda: cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(
                        target=cst.Name("a"),
                        iter=cst.Name("b"),
                        whitespace_before=cst.SimpleWhitespace(""),
                    ),
                ),
                "expected_re": "Must have at least one space before 'for' keyword.",
            },
            {
                "get_node": lambda: cst.DictComp(
                    cst.Name("k"),
                    cst.Name("v"),
                    cst.CompFor(
                        target=cst.Name("a"),
                        iter=cst.Name("b"),
                        asynchronous=cst.Asynchronous(),
                        whitespace_before=cst.SimpleWhitespace(""),
                    ),
                ),
                "expected_re": "Must have at least one space before 'async' keyword.",
            },
        ]
    )
    def test_invalid(self, **kwargs: Any) -> None:
        self.assert_invalid(**kwargs)
Example #30
0
class SubscriptTest(CSTNodeTest):
    @data_provider((
        # Simple subscript expression
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
            ),
            "foo[5]",
            True,
        ),
        # Test creation of subscript with slice/extslice.
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=cst.Integer("2"),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1:2:3]",
            False,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (
                    cst.SubscriptElement(
                        cst.Slice(
                            lower=cst.Integer("1"),
                            upper=cst.Integer("2"),
                            step=cst.Integer("3"),
                        )),
                    cst.SubscriptElement(cst.Index(cst.Integer("5"))),
                ),
            ),
            "foo[1:2:3, 5]",
            False,
            CodeRange((1, 0), (1, 13)),
        ),
        # Test parsing of subscript with slice/extslice.
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        first_colon=cst.Colon(),
                        upper=cst.Integer("2"),
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1:2:3]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (
                    cst.SubscriptElement(
                        cst.Slice(
                            lower=cst.Integer("1"),
                            first_colon=cst.Colon(),
                            upper=cst.Integer("2"),
                            second_colon=cst.Colon(),
                            step=cst.Integer("3"),
                        ),
                        comma=cst.Comma(),
                    ),
                    cst.SubscriptElement(cst.Index(cst.Integer("5"))),
                ),
            ),
            "foo[1:2:3,5]",
            True,
        ),
        # Some more wild slice creations
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"),
                              upper=cst.Integer("2"))), ),
            ),
            "foo[1:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"), upper=None)), ),
            ),
            "foo[1:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=cst.Integer("2"))), ),
            ),
            "foo[:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=None,
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1::3]",
            False,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=None,
                              step=cst.Integer("3"))), ),
            ),
            "foo[::3]",
            False,
            CodeRange((1, 0), (1, 8)),
        ),
        # Some more wild slice parsings
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"),
                              upper=cst.Integer("2"))), ),
            ),
            "foo[1:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=cst.Integer("1"), upper=None)), ),
            ),
            "foo[1:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(lower=None, upper=cst.Integer("2"))), ),
            ),
            "foo[:2]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        upper=None,
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[1::3]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=cst.Integer("3"),
                    )), ),
            ),
            "foo[::3]",
            True,
        ),
        # Valid list clone operations rendering
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Slice(lower=None, upper=None)), ),
            ),
            "foo[:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=None,
                    )), ),
            ),
            "foo[::]",
            True,
        ),
        # Valid list clone operations parsing
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(cst.Slice(lower=None, upper=None)), ),
            ),
            "foo[:]",
            True,
        ),
        (
            cst.Subscript(
                cst.Name("foo"),
                (cst.SubscriptElement(
                    cst.Slice(
                        lower=None,
                        upper=None,
                        second_colon=cst.Colon(),
                        step=None,
                    )), ),
            ),
            "foo[::]",
            True,
        ),
        # In parenthesis
        (
            cst.Subscript(
                lpar=(cst.LeftParen(), ),
                value=cst.Name("foo"),
                slice=(cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                rpar=(cst.RightParen(), ),
            ),
            "(foo[5])",
            True,
        ),
        # Verify spacing
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(cst.SubscriptElement(cst.Index(cst.Integer("5"))), ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 5 ] )",
            True,
        ),
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(cst.SubscriptElement(
                    cst.Slice(
                        lower=cst.Integer("1"),
                        first_colon=cst.Colon(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        upper=cst.Integer("2"),
                        second_colon=cst.Colon(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace(" "),
                        ),
                        step=cst.Integer("3"),
                    )), ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 1 : 2 : 3 ] )",
            True,
        ),
        (
            cst.Subscript(
                lpar=(cst.LeftParen(
                    whitespace_after=cst.SimpleWhitespace(" ")), ),
                value=cst.Name("foo"),
                lbracket=cst.LeftSquareBracket(
                    whitespace_after=cst.SimpleWhitespace(" ")),
                slice=(
                    cst.SubscriptElement(
                        slice=cst.Slice(
                            lower=cst.Integer("1"),
                            first_colon=cst.Colon(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace(" "),
                            ),
                            upper=cst.Integer("2"),
                            second_colon=cst.Colon(
                                whitespace_before=cst.SimpleWhitespace(" "),
                                whitespace_after=cst.SimpleWhitespace(" "),
                            ),
                            step=cst.Integer("3"),
                        ),
                        comma=cst.Comma(
                            whitespace_before=cst.SimpleWhitespace(" "),
                            whitespace_after=cst.SimpleWhitespace("  "),
                        ),
                    ),
                    cst.SubscriptElement(slice=cst.Index(cst.Integer("5"))),
                ),
                rbracket=cst.RightSquareBracket(
                    whitespace_before=cst.SimpleWhitespace(" ")),
                rpar=(cst.RightParen(
                    whitespace_before=cst.SimpleWhitespace(" ")), ),
                whitespace_after_value=cst.SimpleWhitespace(" "),
            ),
            "( foo [ 1 : 2 : 3 ,  5 ] )",
            True,
            CodeRange((1, 2), (1, 24)),
        ),
        # Test Index, Slice, SubscriptElement
        (cst.Index(cst.Integer("5")), "5", False, CodeRange((1, 0), (1, 1))),
        (
            cst.Slice(lower=None,
                      upper=None,
                      second_colon=cst.Colon(),
                      step=None),
            "::",
            False,
            CodeRange((1, 0), (1, 2)),
        ),
        (
            cst.SubscriptElement(
                slice=cst.Slice(
                    lower=cst.Integer("1"),
                    first_colon=cst.Colon(
                        whitespace_before=cst.SimpleWhitespace(" "),
                        whitespace_after=cst.SimpleWhitespace(" "),
                    ),
                    upper=cst.Integer("2"),
                    second_colon=cst.Colon(
                        whitespace_before=cst.SimpleWhitespace(" "),
                        whitespace_after=cst.SimpleWhitespace(" "),
                    ),
                    step=cst.Integer("3"),
                ),
                comma=cst.Comma(
                    whitespace_before=cst.SimpleWhitespace(" "),
                    whitespace_after=cst.SimpleWhitespace("  "),
                ),
            ),
            "1 : 2 : 3 ,  ",
            False,
            CodeRange((1, 0), (1, 9)),
        ),
    ))
    def test_valid(
        self,
        node: cst.CSTNode,
        code: str,
        check_parsing: bool,
        position: Optional[CodeRange] = None,
    ) -> None:
        if check_parsing:
            self.validate_node(node,
                               code,
                               parse_expression,
                               expected_position=position)
        else:
            self.validate_node(node, code, expected_position=position)

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