def test_suite(self) -> None: # Test that we can insert various types of statement suites into a # spot accepting a suite. module = parse_template_module( "if x is True: {suite}\n", suite=cst.SimpleStatementSuite(body=(cst.Pass(),),), ) self.assertEqual( module.code, "if x is True: pass\n", ) module = parse_template_module( "if x is True: {suite}\n", suite=cst.IndentedBlock(body=(cst.SimpleStatementLine((cst.Pass(),),),),), ) self.assertEqual( module.code, "if x is True:\n pass\n", ) module = parse_template_module( "if x is True:\n {suite}\n", suite=cst.SimpleStatementSuite(body=(cst.Pass(),),), ) self.assertEqual( module.code, "if x is True: pass\n", ) module = parse_template_module( "if x is True:\n {suite}\n", suite=cst.IndentedBlock(body=(cst.SimpleStatementLine((cst.Pass(),),),),), ) self.assertEqual( module.code, "if x is True:\n pass\n", )
def test_deep_replace_complex(self) -> None: old_code = """ def a(): def b(): def c(): pass """ new_code = """ def a(): def b(): def d(): break """ module = cst.parse_module(dedent(old_code)) outer_fun = cst.ensure_type(module.body[0], cst.FunctionDef) middle_fun = cst.ensure_type( cst.ensure_type(outer_fun.body, cst.IndentedBlock).body[0], cst.FunctionDef) inner_fun = cst.ensure_type( cst.ensure_type(middle_fun.body, cst.IndentedBlock).body[0], cst.FunctionDef) new_module = cst.ensure_type( module.deep_replace( inner_fun, cst.FunctionDef( name=cst.Name("d"), params=cst.Parameters(), body=cst.SimpleStatementSuite(body=(cst.Break(), )), ), ), cst.Module, ) self.assertEqual(new_module.code, dedent(new_code))
class ElseTest(CSTNodeTest): @data_provider( ( { "node": cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), "code": "else: pass\n", "expected_position": CodeRange.create((1, 0), (1, 10)), }, { "node": cst.Else( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_before_colon=cst.SimpleWhitespace(" "), ), "code": "else : pass\n", "expected_position": CodeRange.create((1, 0), (1, 12)), }, ) ) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs)
def test_statement(self) -> None: # Test that we can insert various types of statements into a # statement list. module = parse_template_module( "{statement1}\n{statement2}\n{statement3}\n", statement1=cst.If( test=cst.Name("foo"), body=cst.SimpleStatementSuite((cst.Pass(),),), ), statement2=cst.SimpleStatementLine((cst.Expr(cst.Call(cst.Name("bar"))),),), statement3=cst.Pass(), ) self.assertEqual( module.code, "if foo: pass\nbar()\npass\n", )
def test_adding_parens(self) -> None: node = cst.With( ( cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma( whitespace_after=cst.ParenthesizedWhitespace(), ), ), cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()), ), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")), rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")), ) module = cst.Module([]) self.assertEqual( module.code_for_node(node), ("with ( foo(),\n" "bar(), ): pass\n") # noqa )
class NamedExprTest(CSTNodeTest): @data_provider(( # Simple named expression { "node": cst.NamedExpr(cst.Name("x"), cst.Float("5.5")), "code": "x := 5.5", "parser": None, # Walrus operator is illegal as top-level statement "expected_position": None, }, # Parenthesized named expression { "node": cst.NamedExpr( lpar=(cst.LeftParen(), ), target=cst.Name("foo"), value=cst.Integer("5"), rpar=(cst.RightParen(), ), ), "code": "(foo := 5)", "parser": _parse_expression_force_38, "expected_position": CodeRange((1, 1), (1, 9)), }, # Make sure that spacing works { "node": cst.NamedExpr( lpar=(cst.LeftParen( whitespace_after=cst.SimpleWhitespace(" ")), ), target=cst.Name("foo"), whitespace_before_walrus=cst.SimpleWhitespace(" "), whitespace_after_walrus=cst.SimpleWhitespace(" "), value=cst.Name("bar"), rpar=(cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), ), ), "code": "( foo := bar )", "parser": _parse_expression_force_38, "expected_position": CodeRange((1, 2), (1, 14)), }, # Make sure we can use these where allowed in if/while statements { "node": cst.While( test=cst.NamedExpr( target=cst.Name(value="x"), value=cst.Call(func=cst.Name(value="some_input")), ), body=cst.SimpleStatementSuite(body=[cst.Pass()]), ), "code": "while x := some_input(): pass\n", "parser": _parse_statement_force_38, "expected_position": None, }, { "node": cst.If( test=cst.NamedExpr( target=cst.Name(value="x"), value=cst.Call(func=cst.Name(value="some_input")), ), body=cst.SimpleStatementSuite(body=[cst.Pass()]), ), "code": "if x := some_input(): pass\n", "parser": _parse_statement_force_38, "expected_position": None, }, { "node": cst.If( test=cst.NamedExpr( target=cst.Name(value="x"), value=cst.Integer(value="1"), whitespace_before_walrus=cst.SimpleWhitespace(""), whitespace_after_walrus=cst.SimpleWhitespace(""), ), body=cst.SimpleStatementSuite(body=[cst.Pass()]), ), "code": "if x:=1: pass\n", "parser": _parse_statement_force_38, "expected_position": None, }, # Function args { "node": cst.Call( func=cst.Name(value="f"), args=[ cst.Arg(value=cst.NamedExpr( target=cst.Name(value="y"), value=cst.Integer(value="1"), whitespace_before_walrus=cst.SimpleWhitespace(""), whitespace_after_walrus=cst.SimpleWhitespace(""), )), ], ), "code": "f(y:=1)", "parser": _parse_expression_force_38, "expected_position": None, }, # Whitespace handling on args is fragile { "node": cst.Call( func=cst.Name(value="f"), args=[ cst.Arg( value=cst.Name(value="x"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg( value=cst.NamedExpr( target=cst.Name(value="y"), value=cst.Integer(value="1"), whitespace_before_walrus=cst.SimpleWhitespace( " "), whitespace_after_walrus=cst.SimpleWhitespace( " "), ), whitespace_after_arg=cst.SimpleWhitespace(" "), ), ], ), "code": "f(x, y := 1 )", "parser": _parse_expression_force_38, "expected_position": None, }, { "node": cst.Call( func=cst.Name(value="f"), args=[ cst.Arg( value=cst.NamedExpr( target=cst.Name(value="y"), value=cst.Integer(value="1"), whitespace_before_walrus=cst.SimpleWhitespace( " "), whitespace_after_walrus=cst.SimpleWhitespace( " "), ), whitespace_after_arg=cst.SimpleWhitespace(" "), ), ], whitespace_before_args=cst.SimpleWhitespace(" "), ), "code": "f( y := 1 )", "parser": _parse_expression_force_38, "expected_position": None, }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider(( { "get_node": (lambda: cst.NamedExpr( cst.Name("foo"), cst.Name("bar"), lpar=(cst.LeftParen(), ))), "expected_re": "left paren without right paren", }, { "get_node": (lambda: cst.NamedExpr( cst.Name("foo"), cst.Name("bar"), rpar=(cst.RightParen(), ))), "expected_re": "right paren without left paren", }, )) def test_invalid(self, **kwargs: Any) -> None: self.assert_invalid(**kwargs)
class ClassDefParserTest(CSTNodeTest): @data_provider(( # Simple classdef # pyre-fixme[6]: Incompatible parameter type { "node": cst.ClassDef(cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), ))), "code": "class Foo: pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), rpar=cst.RightParen(), ), "code": "class Foo(): pass\n", }, # Positional arguments render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), bases=(cst.Arg(cst.Name("obj")), ), rpar=cst.RightParen(), ), "code": "class Foo(obj): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), bases=( cst.Arg( cst.Name("Bar"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg( cst.Name("Baz"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg(cst.Name("object")), ), rpar=cst.RightParen(), ), "code": "class Foo(Bar, Baz, object): pass\n", }, # Keyword arguments render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), keywords=(cst.Arg( keyword=cst.Name("metaclass"), equal=cst.AssignEqual(), value=cst.Name("Bar"), ), ), rpar=cst.RightParen(), ), "code": "class Foo(metaclass = Bar): pass\n", }, # Iterator expansion render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), bases=(cst.Arg(star="*", value=cst.Name("one")), ), rpar=cst.RightParen(), ), "code": "class Foo(*one): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), bases=( cst.Arg( star="*", value=cst.Name("one"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg( star="*", value=cst.Name("two"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg(star="*", value=cst.Name("three")), ), rpar=cst.RightParen(), ), "code": "class Foo(*one, *two, *three): pass\n", }, # Dictionary expansion render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), keywords=(cst.Arg(star="**", value=cst.Name("one")), ), rpar=cst.RightParen(), ), "code": "class Foo(**one): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), keywords=( cst.Arg( star="**", value=cst.Name("one"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg( star="**", value=cst.Name("two"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.Arg(star="**", value=cst.Name("three")), ), rpar=cst.RightParen(), ), "code": "class Foo(**one, **two, **three): pass\n", }, # Decorator render tests { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), decorators=(cst.Decorator(cst.Name("foo")), ), lpar=cst.LeftParen(), rpar=cst.RightParen(), ), "code": "@foo\nclass Foo(): pass\n", "expected_position": CodeRange((2, 0), (2, 17)), }, { "node": cst.ClassDef( leading_lines=( cst.EmptyLine(), cst.EmptyLine(comment=cst.Comment("# leading comment 1")), ), decorators=( cst.Decorator(cst.Name("foo"), leading_lines=()), cst.Decorator( cst.Name("bar"), leading_lines=(cst.EmptyLine( comment=cst.Comment("# leading comment 2")), ), ), cst.Decorator( cst.Name("baz"), leading_lines=(cst.EmptyLine( comment=cst.Comment("# leading comment 3")), ), ), ), lines_after_decorators=(cst.EmptyLine( comment=cst.Comment("# class comment")), ), name=cst.Name("Foo"), body=cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), rpar=cst.RightParen(), ), "code": "\n# leading comment 1\n@foo\n# leading comment 2\n@bar\n# leading comment 3\n@baz\n# class comment\nclass Foo(): pass\n", "expected_position": CodeRange((9, 0), (9, 17)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs, parser=parse_statement)
class ClassDefCreationTest(CSTNodeTest): @data_provider(( # Simple classdef # pyre-fixme[6]: Incompatible parameter type { "node": cst.ClassDef(cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), ))), "code": "class Foo: pass\n", "expected_position": CodeRange((1, 0), (1, 15)), }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), rpar=cst.RightParen(), ), "code": "class Foo(): pass\n", }, # Positional arguments render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), bases=(cst.Arg(cst.Name("obj")), ), ), "code": "class Foo(obj): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), bases=( cst.Arg(cst.Name("Bar")), cst.Arg(cst.Name("Baz")), cst.Arg(cst.Name("object")), ), ), "code": "class Foo(Bar, Baz, object): pass\n", }, # Keyword arguments render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), keywords=(cst.Arg(keyword=cst.Name("metaclass"), value=cst.Name("Bar")), ), ), "code": "class Foo(metaclass = Bar): pass\n", "expected_position": CodeRange((1, 0), (1, 32)), }, # Iterator expansion render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), bases=(cst.Arg(star="*", value=cst.Name("one")), ), ), "code": "class Foo(*one): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), bases=( cst.Arg(star="*", value=cst.Name("one")), cst.Arg(star="*", value=cst.Name("two")), cst.Arg(star="*", value=cst.Name("three")), ), ), "code": "class Foo(*one, *two, *three): pass\n", }, # Dictionary expansion render test { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), keywords=(cst.Arg(star="**", value=cst.Name("one")), ), ), "code": "class Foo(**one): pass\n", }, { "node": cst.ClassDef( cst.Name("Foo"), cst.SimpleStatementSuite((cst.Pass(), )), keywords=( cst.Arg(star="**", value=cst.Name("one")), cst.Arg(star="**", value=cst.Name("two")), cst.Arg(star="**", value=cst.Name("three")), ), ), "code": "class Foo(**one, **two, **three): pass\n", }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider(( # Basic parenthesis tests. ( lambda: cst.ClassDef( name=cst.Name("Foo"), body=cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(), ), "Do not mix concrete LeftParen/RightParen with MaybeSentinel", ), ( lambda: cst.ClassDef( name=cst.Name("Foo"), body=cst.SimpleStatementSuite((cst.Pass(), )), rpar=cst.RightParen(), ), "Do not mix concrete LeftParen/RightParen with MaybeSentinel", ), # Whitespace validation ( lambda: cst.ClassDef( name=cst.Name("Foo"), body=cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_class=cst.SimpleWhitespace(""), ), "at least one space between 'class' and name", ), )) def test_invalid(self, get_node: Callable[[], cst.CSTNode], expected_re: str) -> None: self.assert_invalid(get_node, expected_re)
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)
class WithTest(CSTNodeTest): @data_provider(( # Simple with block { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with context_mgr(): pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 24)), }, # Simple async with block { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), asynchronous=cst.Asynchronous(), ), "code": "async with context_mgr(): pass\n", "parser": lambda code: parse_statement( code, config=PartialParserConfig(python_version="3.7")), }, # Python 3.6 async with block { "node": cst.FunctionDef( cst.Name("foo"), cst.Parameters(), cst.IndentedBlock((cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), asynchronous=cst.Asynchronous(), ), )), asynchronous=cst.Asynchronous(), ), "code": "async def foo():\n async with context_mgr(): pass\n", "parser": lambda code: parse_statement( code, config=PartialParserConfig(python_version="3.6")), }, # Multiple context managers { "node": cst.With( ( cst.WithItem(cst.Call(cst.Name("foo"))), cst.WithItem(cst.Call(cst.Name("bar"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with foo(), bar(): pass\n", "parser": None, }, { "node": cst.With( ( cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.WithItem(cst.Call(cst.Name("bar"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with foo(), bar(): pass\n", "parser": parse_statement, }, # With block containing variable for context manager. { "node": cst.With( (cst.WithItem( cst.Call(cst.Name("context_mgr")), cst.AsName(cst.Name("ctx")), ), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with context_mgr() as ctx: pass\n", "parser": parse_statement, }, # indentation { "node": DummyIndentedBlock( " ", cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), ), "code": " with context_mgr(): pass\n", "parser": None, "expected_position": CodeRange((1, 4), (1, 28)), }, # with an indented body { "node": DummyIndentedBlock( " ", cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.IndentedBlock((cst.SimpleStatementLine( (cst.Pass(), )), )), ), ), "code": " with context_mgr():\n pass\n", "parser": None, "expected_position": CodeRange((1, 4), (2, 12)), }, # leading_lines { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), leading_lines=(cst.EmptyLine( comment=cst.Comment("# leading comment")), ), ), "code": "# leading comment\nwith context_mgr(): pass\n", "parser": parse_statement, "expected_position": CodeRange((2, 0), (2, 24)), }, # Weird spacing rules { "node": cst.With( (cst.WithItem( cst.Call( cst.Name("context_mgr"), lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), ), )), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(""), ), "code": "with(context_mgr()): pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 25)), }, # Whitespace { "node": cst.With( (cst.WithItem( cst.Call(cst.Name("context_mgr")), cst.AsName( cst.Name("ctx"), whitespace_before_as=cst.SimpleWhitespace(" "), whitespace_after_as=cst.SimpleWhitespace(" "), ), ), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(" "), whitespace_before_colon=cst.SimpleWhitespace(" "), ), "code": "with context_mgr() as ctx : pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 36)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider(( { "get_node": lambda: cst.With((), cst.IndentedBlock((cst.SimpleStatementLine( (cst.Pass(), )), ))), "expected_re": "A With statement must have at least one WithItem", }, { "get_node": lambda: cst.With( (cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ") ), ), ), cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )), ), "expected_re": "The last WithItem in a With cannot have a trailing comma", }, { "get_node": lambda: cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(""), ), "expected_re": "Must have at least one space after with keyword", }, )) def test_invalid(self, **kwargs: Any) -> None: self.assert_invalid(**kwargs) @data_provider(( { "code": "with a, b: pass", "parser": parse_statement_as(python_version="3.1"), "expect_success": True, }, { "code": "with a, b: pass", "parser": parse_statement_as(python_version="3.0"), "expect_success": False, }, )) def test_versions(self, **kwargs: Any) -> None: self.assert_parses(**kwargs)
class TupleTest(CSTNodeTest): @data_provider( [ # zero-element tuple {"node": cst.Tuple([]), "code": "()", "parser": parse_expression}, # one-element tuple, sentinel comma value { "node": cst.Tuple([cst.Element(cst.Name("single_element"))]), "code": "(single_element,)", "parser": None, }, { "node": cst.Tuple([cst.StarredElement(cst.Name("single_element"))]), "code": "(*single_element,)", "parser": None, }, # two-element tuple, sentinel comma value { "node": cst.Tuple( [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))] ), "code": "(one, two)", "parser": None, }, # remove parenthesis { "node": cst.Tuple( [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))], lpar=[], rpar=[], ), "code": "one, two", "parser": None, }, # add extra parenthesis { "node": cst.Tuple( [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))], lpar=[cst.LeftParen(), cst.LeftParen()], rpar=[cst.RightParen(), cst.RightParen()], ), "code": "((one, two))", "parser": None, }, # starred element { "node": cst.Tuple( [ cst.StarredElement(cst.Name("one")), cst.StarredElement(cst.Name("two")), ] ), "code": "(*one, *two)", "parser": None, }, # custom comma on Element { "node": cst.Tuple( [ cst.Element(cst.Name("one"), comma=cst.Comma()), cst.Element(cst.Name("two"), comma=cst.Comma()), ] ), "code": "(one,two,)", "parser": parse_expression, }, # custom comma on StarredElement { "node": cst.Tuple( [ cst.StarredElement(cst.Name("one"), comma=cst.Comma()), cst.StarredElement(cst.Name("two"), comma=cst.Comma()), ] ), "code": "(*one,*two,)", "parser": parse_expression, "expected_position": CodeRange((1, 1), (1, 11)), }, # custom parenthesis on StarredElement { "node": cst.Tuple( [ cst.StarredElement( cst.Name("abc"), lpar=[cst.LeftParen()], rpar=[cst.RightParen()], comma=cst.Comma(), ) ] ), "code": "((*abc),)", "parser": parse_expression, "expected_position": CodeRange((1, 1), (1, 8)), }, # custom whitespace on StarredElement { "node": cst.Tuple( [ cst.Element(cst.Name("one"), comma=cst.Comma()), cst.StarredElement( cst.Name("two"), whitespace_before_value=cst.SimpleWhitespace(" "), lpar=[cst.LeftParen()], rpar=[cst.RightParen()], ), ], lpar=[], rpar=[], # rpar can't own the trailing whitespace if it's not there ), "code": "one,(* two)", "parser": parse_expression, "expected_position": CodeRange((1, 0), (1, 12)), }, # missing spaces around tuple, okay with parenthesis { "node": cst.For( target=cst.Tuple( [ cst.Element(cst.Name("k"), comma=cst.Comma()), cst.Element(cst.Name("v")), ] ), iter=cst.Name("abc"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_after_for=cst.SimpleWhitespace(""), whitespace_before_in=cst.SimpleWhitespace(""), ), "code": "for(k,v)in abc: pass\n", "parser": parse_statement, }, # no spaces around tuple, but using values that are parenthesized { "node": cst.For( target=cst.Tuple( [ cst.Element( cst.Name( "k", lpar=[cst.LeftParen()], rpar=[cst.RightParen()] ), comma=cst.Comma(), ), cst.Element( cst.Name( "v", lpar=[cst.LeftParen()], rpar=[cst.RightParen()] ) ), ], lpar=[], rpar=[], ), iter=cst.Name("abc"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_after_for=cst.SimpleWhitespace(""), whitespace_before_in=cst.SimpleWhitespace(""), ), "code": "for(k),(v)in abc: pass\n", "parser": parse_statement, }, # starred elements are safe to use without a space before them { "node": cst.For( target=cst.Tuple( [cst.StarredElement(cst.Name("foo"), comma=cst.Comma())], lpar=[], rpar=[], ), iter=cst.Name("bar"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_after_for=cst.SimpleWhitespace(""), ), "code": "for*foo, in bar: pass\n", "parser": parse_statement, }, # a trailing comma doesn't mess up TrailingWhitespace { "node": cst.SimpleStatementLine( [ cst.Expr( cst.Tuple( [ cst.Element(cst.Name("one"), comma=cst.Comma()), cst.Element(cst.Name("two"), comma=cst.Comma()), ], lpar=[], rpar=[], ) ) ], trailing_whitespace=cst.TrailingWhitespace( whitespace=cst.SimpleWhitespace(" "), comment=cst.Comment("# comment"), ), ), "code": "one,two, # comment\n", "parser": parse_statement, }, ] ) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider( ( ( lambda: cst.Tuple([], lpar=[], rpar=[]), "A zero-length tuple must be wrapped in parentheses.", ), ( lambda: cst.Tuple( [cst.Element(cst.Name("mismatched"))], lpar=[cst.LeftParen(), cst.LeftParen()], rpar=[cst.RightParen()], ), "unbalanced parens", ), ( lambda: cst.For( target=cst.Tuple([cst.Element(cst.Name("el"))], lpar=[], rpar=[]), iter=cst.Name("it"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_after_for=cst.SimpleWhitespace(""), ), "Must have at least one space after 'for' keyword.", ), ( lambda: cst.For( target=cst.Tuple([cst.Element(cst.Name("el"))], lpar=[], rpar=[]), iter=cst.Name("it"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_before_in=cst.SimpleWhitespace(""), ), "Must have at least one space before 'in' keyword.", ), # an additional check for StarredElement, since it's a separate codepath ( lambda: cst.For( target=cst.Tuple( [cst.StarredElement(cst.Name("el"))], lpar=[], rpar=[] ), iter=cst.Name("it"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_before_in=cst.SimpleWhitespace(""), ), "Must have at least one space before 'in' keyword.", ), ) ) def test_invalid( self, get_node: Callable[[], cst.CSTNode], expected_re: str ) -> None: self.assert_invalid(get_node, expected_re)
class ListTest(CSTNodeTest): # A lot of Element/StarredElement tests are provided by the tests for Tuple, so we # we don't need to duplicate them here. @data_provider([ # zero-element list { "node": cst.List([]), "code": "[]", "parser": parse_expression }, # one-element list, sentinel comma value { "node": cst.List([cst.Element(cst.Name("single_element"))]), "code": "[single_element]", "parser": parse_expression, }, # custom whitespace between brackets { "node": cst.List( [cst.Element(cst.Name("single_element"))], lbracket=cst.LeftSquareBracket( whitespace_after=cst.SimpleWhitespace("\t")), rbracket=cst.RightSquareBracket( whitespace_before=cst.SimpleWhitespace(" ")), ), "code": "[\tsingle_element ]", "parser": parse_expression, "expected_position": CodeRange.create((1, 0), (1, 21)), }, # two-element list, sentinel comma value { "node": cst.List( [cst.Element(cst.Name("one")), cst.Element(cst.Name("two"))]), "code": "[one, two]", "parser": None, }, # with parenthesis { "node": cst.List( [cst.Element(cst.Name("one"))], lpar=[cst.LeftParen()], rpar=[cst.RightParen()], ), "code": "([one])", "parser": None, "expected_position": CodeRange.create((1, 1), (1, 6)), }, # starred element { "node": cst.List([ cst.StarredElement(cst.Name("one")), cst.StarredElement(cst.Name("two")), ]), "code": "[*one, *two]", "parser": None, "expected_position": CodeRange.create((1, 0), (1, 12)), }, # missing spaces around list, always okay { "node": cst.For( target=cst.List([ cst.Element(cst.Name("k"), comma=cst.Comma()), cst.Element(cst.Name("v")), ]), iter=cst.Name("abc"), body=cst.SimpleStatementSuite([cst.Pass()]), whitespace_after_for=cst.SimpleWhitespace(""), whitespace_before_in=cst.SimpleWhitespace(""), ), "code": "for[k,v]in abc: pass\n", "parser": parse_statement, }, ]) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider((( lambda: cst.List( [cst.Element(cst.Name("mismatched"))], lpar=[cst.LeftParen(), cst.LeftParen()], rpar=[cst.RightParen()], ), "unbalanced parens", ), )) def test_invalid(self, get_node: Callable[[], cst.CSTNode], expected_re: str) -> None: self.assert_invalid(get_node, expected_re)
class WithTest(CSTNodeTest): maxDiff: int = 2000 @data_provider(( # Simple with block { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with context_mgr(): pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 24)), }, # Simple async with block { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), asynchronous=cst.Asynchronous(), ), "code": "async with context_mgr(): pass\n", "parser": lambda code: parse_statement( code, config=PartialParserConfig(python_version="3.7")), }, # Python 3.6 async with block { "node": cst.FunctionDef( cst.Name("foo"), cst.Parameters(), cst.IndentedBlock((cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), asynchronous=cst.Asynchronous(), ), )), asynchronous=cst.Asynchronous(), ), "code": "async def foo():\n async with context_mgr(): pass\n", "parser": lambda code: parse_statement( code, config=PartialParserConfig(python_version="3.6")), }, # Multiple context managers { "node": cst.With( ( cst.WithItem(cst.Call(cst.Name("foo"))), cst.WithItem(cst.Call(cst.Name("bar"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with foo(), bar(): pass\n", "parser": None, }, { "node": cst.With( ( cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ")), ), cst.WithItem(cst.Call(cst.Name("bar"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with foo(), bar(): pass\n", "parser": parse_statement, }, # With block containing variable for context manager. { "node": cst.With( (cst.WithItem( cst.Call(cst.Name("context_mgr")), cst.AsName(cst.Name("ctx")), ), ), cst.SimpleStatementSuite((cst.Pass(), )), ), "code": "with context_mgr() as ctx: pass\n", "parser": parse_statement, }, # indentation { "node": DummyIndentedBlock( " ", cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), ), ), "code": " with context_mgr(): pass\n", "parser": None, "expected_position": CodeRange((1, 4), (1, 28)), }, # with an indented body { "node": DummyIndentedBlock( " ", cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.IndentedBlock((cst.SimpleStatementLine( (cst.Pass(), )), )), ), ), "code": " with context_mgr():\n pass\n", "parser": None, "expected_position": CodeRange((1, 4), (2, 12)), }, # leading_lines { "node": cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), leading_lines=(cst.EmptyLine( comment=cst.Comment("# leading comment")), ), ), "code": "# leading comment\nwith context_mgr(): pass\n", "parser": parse_statement, "expected_position": CodeRange((2, 0), (2, 24)), }, # Whitespace { "node": cst.With( (cst.WithItem( cst.Call(cst.Name("context_mgr")), cst.AsName( cst.Name("ctx"), whitespace_before_as=cst.SimpleWhitespace(" "), whitespace_after_as=cst.SimpleWhitespace(" "), ), ), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(" "), whitespace_before_colon=cst.SimpleWhitespace(" "), ), "code": "with context_mgr() as ctx : pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 36)), }, # Weird spacing rules, that parse differently depending on whether # we are using a grammar that included parenthesized with statements. { "node": cst.With( (cst.WithItem( cst.Call( cst.Name("context_mgr"), lpar=() if is_native() else (cst.LeftParen(), ), rpar=() if is_native() else (cst.RightParen(), ), )), ), cst.SimpleStatementSuite((cst.Pass(), )), lpar=(cst.LeftParen() if is_native() else MaybeSentinel.DEFAULT), rpar=(cst.RightParen() if is_native() else MaybeSentinel.DEFAULT), whitespace_after_with=cst.SimpleWhitespace(""), ), "code": "with(context_mgr()): pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (1, 25)), }, # Multi-line parenthesized with. { "node": cst.With( ( cst.WithItem( cst.Call(cst.Name("foo")), comma=cst. Comma(whitespace_after=cst.ParenthesizedWhitespace( first_line=cst.TrailingWhitespace( whitespace=cst.SimpleWhitespace(value="", ), comment=None, newline=cst.Newline(value=None, ), ), empty_lines=[], indent=True, last_line=cst.SimpleWhitespace(value=" ", ), )), ), cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()), ), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")), rpar=cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), ), "code": ("with ( foo(),\n" " bar(), ): pass\n"), # noqa "parser": parse_statement if is_native() else None, "expected_position": CodeRange((1, 0), (2, 21)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider(( { "get_node": lambda: cst.With((), cst.IndentedBlock((cst.SimpleStatementLine( (cst.Pass(), )), ))), "expected_re": "A With statement must have at least one WithItem", }, { "get_node": lambda: cst.With( (cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma(whitespace_after=cst.SimpleWhitespace(" ") ), ), ), cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(), )), )), ), "expected_re": "The last WithItem in an unparenthesized With cannot " + "have a trailing comma.", }, { "get_node": lambda: cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(""), ), "expected_re": "Must have at least one space after with keyword", }, { "get_node": lambda: cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(""), lpar=cst.LeftParen(), ), "expected_re": "Do not mix concrete LeftParen/RightParen with " + "MaybeSentinel", }, { "get_node": lambda: cst.With( (cst.WithItem(cst.Call(cst.Name("context_mgr"))), ), cst.SimpleStatementSuite((cst.Pass(), )), whitespace_after_with=cst.SimpleWhitespace(""), rpar=cst.RightParen(), ), "expected_re": "Do not mix concrete LeftParen/RightParen with " + "MaybeSentinel", }, )) def test_invalid(self, **kwargs: Any) -> None: self.assert_invalid(**kwargs) @data_provider(( { "code": "with a, b: pass", "parser": parse_statement_as(python_version="3.1"), "expect_success": True, }, { "code": "with a, b: pass", "parser": parse_statement_as(python_version="3.0"), "expect_success": False, }, )) def test_versions(self, **kwargs: Any) -> None: if is_native() and not kwargs.get("expect_success", True): self.skipTest("parse errors are disabled for native parser") self.assert_parses(**kwargs) def test_adding_parens(self) -> None: node = cst.With( ( cst.WithItem( cst.Call(cst.Name("foo")), comma=cst.Comma( whitespace_after=cst.ParenthesizedWhitespace(), ), ), cst.WithItem(cst.Call(cst.Name("bar")), comma=cst.Comma()), ), cst.SimpleStatementSuite((cst.Pass(), )), lpar=cst.LeftParen(whitespace_after=cst.SimpleWhitespace(" ")), rpar=cst.RightParen(whitespace_before=cst.SimpleWhitespace(" ")), ) module = cst.Module([]) self.assertEqual( module.code_for_node(node), ("with ( foo(),\n" "bar(), ): pass\n") # noqa )
class IfTest(CSTNodeTest): @data_provider(( # Simple if without elif or else { "node": cst.If(cst.Name("conditional"), cst.SimpleStatementSuite((cst.Pass(), ))), "code": "if conditional: pass\n", "parser": parse_statement, "expected_position": CodeRange((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((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((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((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((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((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((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((1, 0), (5, 10)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs)
class SimpleStatementTest(CSTNodeTest): @data_provider(( # a single-element SimpleStatementLine # pyre-fixme[6]: Incompatible parameter type { "node": cst.SimpleStatementLine((cst.Pass(), )), "code": "pass\n", "parser": parse_statement, }, # a multi-element SimpleStatementLine { "node": cst.SimpleStatementLine( (cst.Pass(semicolon=cst.Semicolon()), cst.Continue())), "code": "pass;continue\n", "parser": parse_statement, }, # a multi-element SimpleStatementLine with whitespace { "node": cst.SimpleStatementLine(( cst.Pass(semicolon=cst.Semicolon( whitespace_before=cst.SimpleWhitespace(" "), whitespace_after=cst.SimpleWhitespace(" "), )), cst.Continue(), )), "code": "pass ; continue\n", "parser": parse_statement, }, # A more complicated SimpleStatementLine { "node": cst.SimpleStatementLine(( cst.Pass(semicolon=cst.Semicolon()), cst.Continue(semicolon=cst.Semicolon()), cst.Break(), )), "code": "pass;continue;break\n", "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (1, 19)), }, # a multi-element SimpleStatementLine, inferred semicolons { "node": cst.SimpleStatementLine((cst.Pass(), cst.Continue(), cst.Break())), "code": "pass; continue; break\n", "parser": None, # No test for parsing, since we are using sentinels. }, # some expression statements { "node": cst.SimpleStatementLine((cst.Expr(cst.Name("None")), )), "code": "None\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr(cst.Name("True")), )), "code": "True\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr(cst.Name("False")), )), "code": "False\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr(cst.Ellipsis()), )), "code": "...\n", "parser": parse_statement, }, # Test some numbers { "node": cst.SimpleStatementLine((cst.Expr(cst.Integer("5")), )), "code": "5\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr(cst.Float("5.5")), )), "code": "5.5\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr(cst.Imaginary("5j")), )), "code": "5j\n", "parser": parse_statement, }, # Test some numbers with parens { "node": cst.SimpleStatementLine((cst.Expr( cst.Integer("5", lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), ))), )), "code": "(5)\n", "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (1, 3)), }, { "node": cst.SimpleStatementLine((cst.Expr( cst.Float("5.5", lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), ))), )), "code": "(5.5)\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr( cst.Imaginary("5j", lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), ))), )), "code": "(5j)\n", "parser": parse_statement, }, # Test some strings { "node": cst.SimpleStatementLine((cst.Expr(cst.SimpleString('"abc"')), )), "code": '"abc"\n', "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr( cst.ConcatenatedString(cst.SimpleString('"abc"'), cst.SimpleString('"def"'))), )), "code": '"abc""def"\n', "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr( cst.ConcatenatedString( left=cst.SimpleString('"abc"'), whitespace_between=cst.SimpleWhitespace(" "), right=cst.ConcatenatedString( left=cst.SimpleString('"def"'), whitespace_between=cst.SimpleWhitespace(" "), right=cst.SimpleString('"ghi"'), ), )), )), "code": '"abc" "def" "ghi"\n', "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (1, 17)), }, # Test parenthesis rules { "node": cst.SimpleStatementLine((cst.Expr( cst.Ellipsis(lpar=(cst.LeftParen(), ), rpar=(cst.RightParen(), ))), )), "code": "(...)\n", "parser": parse_statement, }, # Test parenthesis with whitespace ownership { "node": cst.SimpleStatementLine((cst.Expr( cst.Ellipsis( lpar=(cst.LeftParen( whitespace_after=cst.SimpleWhitespace(" ")), ), rpar=(cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), ), )), )), "code": "( ... )\n", "parser": parse_statement, }, { "node": cst.SimpleStatementLine((cst.Expr( cst.Ellipsis( lpar=( cst.LeftParen( whitespace_after=cst.SimpleWhitespace(" ")), cst.LeftParen( whitespace_after=cst.SimpleWhitespace(" ")), cst.LeftParen( whitespace_after=cst.SimpleWhitespace(" ")), ), rpar=( cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), cst.RightParen( whitespace_before=cst.SimpleWhitespace(" ")), ), )), )), "code": "( ( ( ... ) ) )\n", "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (1, 21)), }, # Test parenthesis rules with expressions { "node": cst.SimpleStatementLine((cst.Expr( cst.Ellipsis( lpar=(cst.LeftParen( whitespace_after=cst.ParenthesizedWhitespace( first_line=cst.TrailingWhitespace(), empty_lines=(cst.EmptyLine( comment=cst.Comment("# Wow, a comment!")), ), indent=True, last_line=cst.SimpleWhitespace(" "), )), ), rpar=(cst.RightParen( whitespace_before=cst.ParenthesizedWhitespace( first_line=cst.TrailingWhitespace(), empty_lines=(), indent=True, last_line=cst.SimpleWhitespace(""), )), ), )), )), "code": "(\n# Wow, a comment!\n ...\n)\n", "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (4, 1)), }, # test trailing whitespace { "node": cst.SimpleStatementLine( (cst.Pass(), ), trailing_whitespace=cst.TrailingWhitespace( whitespace=cst.SimpleWhitespace(" "), comment=cst.Comment("# trailing comment"), ), ), "code": "pass # trailing comment\n", "parser": parse_statement, "expected_position": CodeRange.create((1, 0), (1, 4)), }, # test leading comment { "node": cst.SimpleStatementLine( (cst.Pass(), ), leading_lines=(cst.EmptyLine( comment=cst.Comment("# comment")), ), ), "code": "# comment\npass\n", "parser": parse_statement, "expected_position": CodeRange.create((2, 0), (2, 4)), }, # test indentation { "node": DummyIndentedBlock( " ", cst.SimpleStatementLine( (cst.Pass(), ), leading_lines=(cst.EmptyLine( comment=cst.Comment("# comment")), ), ), ), "code": " # comment\n pass\n", "expected_position": CodeRange.create((2, 4), (2, 8)), }, # test suite variant { "node": cst.SimpleStatementSuite((cst.Pass(), )), "code": " pass\n", "expected_position": CodeRange.create((1, 1), (1, 5)), }, { "node": cst.SimpleStatementSuite( (cst.Pass(), ), leading_whitespace=cst.SimpleWhitespace("")), "code": "pass\n", "expected_position": CodeRange.create((1, 0), (1, 4)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs)
class TryTest(CSTNodeTest): @data_provider( ( # Simple try/except block { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), ), "code": "try: pass\nexcept: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (2, 12)), }, # Try/except with a class { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("Exception"), ), ), ), "code": "try: pass\nexcept Exception: pass\n", "parser": parse_statement, }, # Try/except with a named class { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("Exception"), name=cst.AsName(cst.Name("exc")), ), ), ), "code": "try: pass\nexcept Exception as exc: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (2, 29)), }, # Try/except with multiple clauses { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("TypeError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("KeyError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), ), "code": "try: pass\n" + "except TypeError as e: pass\n" + "except KeyError as e: pass\n" + "except: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (4, 12)), }, # Simple try/finally block { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), "code": "try: pass\nfinally: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (2, 13)), }, # Simple try/except/finally block { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), "code": "try: pass\nexcept: pass\nfinally: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (3, 13)), }, # Simple try/except/else block { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), ), "code": "try: pass\nexcept: pass\nelse: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (3, 10)), }, # Simple try/except/else block/finally { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), "code": "try: pass\nexcept: pass\nelse: pass\nfinally: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (4, 13)), }, # Verify whitespace in various locations { "node": cst.Try( leading_lines=(cst.EmptyLine(comment=cst.Comment("# 1")),), body=cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( leading_lines=(cst.EmptyLine(comment=cst.Comment("# 2")),), type=cst.Name("TypeError"), name=cst.AsName( cst.Name("e"), whitespace_before_as=cst.SimpleWhitespace(" "), whitespace_after_as=cst.SimpleWhitespace(" "), ), whitespace_after_except=cst.SimpleWhitespace(" "), whitespace_before_colon=cst.SimpleWhitespace(" "), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ), orelse=cst.Else( leading_lines=(cst.EmptyLine(comment=cst.Comment("# 3")),), body=cst.SimpleStatementSuite((cst.Pass(),)), whitespace_before_colon=cst.SimpleWhitespace(" "), ), finalbody=cst.Finally( leading_lines=(cst.EmptyLine(comment=cst.Comment("# 4")),), body=cst.SimpleStatementSuite((cst.Pass(),)), whitespace_before_colon=cst.SimpleWhitespace(" "), ), whitespace_before_colon=cst.SimpleWhitespace(" "), ), "code": "# 1\ntry : pass\n# 2\nexcept TypeError as e : pass\n# 3\nelse : pass\n# 4\nfinally : pass\n", "parser": parse_statement, "expected_position": CodeRange((2, 0), (8, 14)), }, # Please don't write code like this { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("TypeError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("KeyError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), "code": "try: pass\n" + "except TypeError as e: pass\n" + "except KeyError as e: pass\n" + "except: pass\n" + "else: pass\n" + "finally: pass\n", "parser": parse_statement, "expected_position": CodeRange((1, 0), (6, 13)), }, # Verify indentation { "node": DummyIndentedBlock( " ", cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("TypeError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("KeyError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), ), "code": " try: pass\n" + " except TypeError as e: pass\n" + " except KeyError as e: pass\n" + " except: pass\n" + " else: pass\n" + " finally: pass\n", "parser": None, }, # Verify indentation in bodies { "node": DummyIndentedBlock( " ", cst.Try( cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),)), handlers=( cst.ExceptHandler( cst.IndentedBlock( (cst.SimpleStatementLine((cst.Pass(),)),) ), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else( cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),)) ), finalbody=cst.Finally( cst.IndentedBlock((cst.SimpleStatementLine((cst.Pass(),)),)) ), ), ), "code": " try:\n" + " pass\n" + " except:\n" + " pass\n" + " else:\n" + " pass\n" + " finally:\n" + " pass\n", "parser": None, }, # No space when using grouping parens { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), type=cst.Name( "Exception", lpar=(cst.LeftParen(),), rpar=(cst.RightParen(),), ), ), ), ), "code": "try: pass\nexcept(Exception): pass\n", "parser": parse_statement, }, # No space when using tuple { "node": cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), handlers=( cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_except=cst.SimpleWhitespace(""), type=cst.Tuple( [ cst.Element( cst.Name("IOError"), comma=cst.Comma( whitespace_after=cst.SimpleWhitespace(" ") ), ), cst.Element(cst.Name("ImportError")), ] ), ), ), ), "code": "try: pass\nexcept(IOError, ImportError): pass\n", "parser": parse_statement, }, ) ) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs) @data_provider( ( { "get_node": lambda: cst.AsName(cst.Name("")), "expected_re": "empty name identifier", }, { "get_node": lambda: cst.AsName( cst.Name("bla"), whitespace_after_as=cst.SimpleWhitespace("") ), "expected_re": "between 'as'", }, { "get_node": lambda: cst.AsName( cst.Name("bla"), whitespace_before_as=cst.SimpleWhitespace("") ), "expected_re": "before 'as'", }, { "get_node": lambda: cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), name=cst.AsName(cst.Name("bla")), ), "expected_re": "name for an empty type", }, { "get_node": lambda: cst.ExceptHandler( cst.SimpleStatementSuite((cst.Pass(),)), type=cst.Name("TypeError"), whitespace_after_except=cst.SimpleWhitespace(""), ), "expected_re": "at least one space after except", }, { "get_node": lambda: cst.Try(cst.SimpleStatementSuite((cst.Pass(),))), "expected_re": "at least one ExceptHandler or Finally", }, { "get_node": lambda: cst.Try( cst.SimpleStatementSuite((cst.Pass(),)), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(),))), finalbody=cst.Finally(cst.SimpleStatementSuite((cst.Pass(),))), ), "expected_re": "at least one ExceptHandler in order to have an Else", }, ) ) def test_invalid(self, **kwargs: Any) -> None: self.assert_invalid(**kwargs)
class TryStarTest(CSTNodeTest): @data_provider(( # Try/except with a class { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=(cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("Exception"), ), ), ), "code": "try: pass\nexcept* Exception: pass\n", "parser": native_parse_statement, }, # Try/except with a named class { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=(cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("Exception"), name=cst.AsName(cst.Name("exc")), ), ), ), "code": "try: pass\nexcept* Exception as exc: pass\n", "parser": native_parse_statement, "expected_position": CodeRange((1, 0), (2, 30)), }, # Try/except with multiple clauses { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=( cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("TypeError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("KeyError"), name=cst.AsName(cst.Name("e")), ), ), ), "code": "try: pass\n" + "except* TypeError as e: pass\n" + "except* KeyError as e: pass\n", "parser": native_parse_statement, "expected_position": CodeRange((1, 0), (3, 27)), }, # Simple try/except/finally block { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=(cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("KeyError"), whitespace_after_except=cst.SimpleWhitespace(""), ), ), finalbody=cst.Finally(cst.SimpleStatementSuite( (cst.Pass(), ))), ), "code": "try: pass\nexcept* KeyError: pass\nfinally: pass\n", "parser": native_parse_statement, "expected_position": CodeRange((1, 0), (3, 13)), }, # Simple try/except/else block { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=(cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("KeyError"), whitespace_after_except=cst.SimpleWhitespace(""), ), ), orelse=cst.Else(cst.SimpleStatementSuite((cst.Pass(), ))), ), "code": "try: pass\nexcept* KeyError: pass\nelse: pass\n", "parser": native_parse_statement, "expected_position": CodeRange((1, 0), (3, 10)), }, # Verify whitespace in various locations { "node": cst.TryStar( leading_lines=(cst.EmptyLine(comment=cst.Comment("# 1")), ), body=cst.SimpleStatementSuite((cst.Pass(), )), handlers=(cst.ExceptStarHandler( 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_after_star=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": native_parse_statement, "expected_position": CodeRange((2, 0), (8, 14)), }, # Now all together { "node": cst.TryStar( cst.SimpleStatementSuite((cst.Pass(), )), handlers=( cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("TypeError"), name=cst.AsName(cst.Name("e")), ), cst.ExceptStarHandler( cst.SimpleStatementSuite((cst.Pass(), )), type=cst.Name("KeyError"), name=cst.AsName(cst.Name("e")), ), ), 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" + "else: pass\n" + "finally: pass\n", "parser": native_parse_statement, "expected_position": CodeRange((1, 0), (5, 13)), }, )) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs)
class WhileTest(CSTNodeTest): @data_provider(( # Simple while block # pyre-fixme[6]: Incompatible parameter type { "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)
class MatchTest(CSTNodeTest): @data_provider( ( # Values and singletons { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( pattern=cst.MatchSingleton(cst.Name("None")), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchValue(cst.SimpleString('"foo"')), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": "match x:\n" + " case None: pass\n" + ' case "foo": pass\n', "parser": parser, }, # Parenthesized value { "node": cst.Match( subject=cst.Name( value="x", ), cases=[ cst.MatchCase( pattern=cst.MatchAs( pattern=cst.MatchValue( value=cst.Integer( value="1", lpar=[ cst.LeftParen(), ], rpar=[ cst.RightParen(), ], ), ), name=cst.Name( value="z", ), whitespace_before_as=cst.SimpleWhitespace(" "), whitespace_after_as=cst.SimpleWhitespace(" "), ), body=cst.SimpleStatementSuite([cst.Pass()]), ), ], ), "code": "match x:\n case (1) as z: pass\n", "parser": parser, }, # List patterns { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( # empty list pattern=cst.MatchList( [], lbracket=cst.LeftSquareBracket(), rbracket=cst.RightSquareBracket(), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single element list pattern=cst.MatchList( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")) ) ], lbracket=cst.LeftSquareBracket(), rbracket=cst.RightSquareBracket(), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single element list with trailing comma pattern=cst.MatchList( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ) ], lbracket=cst.LeftSquareBracket(), rbracket=cst.RightSquareBracket(), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": ( "match x:\n" + " case []: pass\n" + " case [None]: pass\n" + " case [None,]: pass\n" ), "parser": parser, }, # Tuple patterns { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( # empty tuple pattern=cst.MatchTuple( [], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # two element tuple pattern=cst.MatchTuple( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ), cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), ), ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single element tuple with trailing comma pattern=cst.MatchTuple( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # two element tuple pattern=cst.MatchTuple( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ), cst.MatchStar( comma=cst.Comma(), ), cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), ), ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": ( "match x:\n" + " case (): pass\n" + " case (None,None): pass\n" + " case (None,): pass\n" + " case (None,*_,None): pass\n" ), "parser": parser, }, # Mapping patterns { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( # empty mapping pattern=cst.MatchMapping( [], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # two element mapping pattern=cst.MatchMapping( [ cst.MatchMappingElement( key=cst.SimpleString('"a"'), pattern=cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ), cst.MatchMappingElement( key=cst.SimpleString('"b"'), pattern=cst.MatchSingleton(cst.Name("None")), ), ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single element mapping with trailing comma pattern=cst.MatchMapping( [ cst.MatchMappingElement( key=cst.SimpleString('"a"'), pattern=cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # rest pattern=cst.MatchMapping( rest=cst.Name("rest"), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": ( "match x:\n" + " case {}: pass\n" + ' case {"a": None,"b": None}: pass\n' + ' case {"a": None,}: pass\n' + " case {**rest}: pass\n" ), "parser": parser, }, # Class patterns { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( # empty class pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single pattern class pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), patterns=[ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")) ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single pattern class with trailing comma pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), patterns=[ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single keyword pattern class pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), kwds=[ cst.MatchKeywordElement( key=cst.Name("foo"), pattern=cst.MatchSingleton(cst.Name("None")), ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # single keyword pattern class with trailing comma pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), kwds=[ cst.MatchKeywordElement( key=cst.Name("foo"), pattern=cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ) ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( # now all at once pattern=cst.MatchClass( cls=cst.Attribute(cst.Name("a"), cst.Name("b")), patterns=[ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ), cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")), cst.Comma(), ), ], kwds=[ cst.MatchKeywordElement( key=cst.Name("foo"), pattern=cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ), cst.MatchKeywordElement( key=cst.Name("bar"), pattern=cst.MatchSingleton(cst.Name("None")), comma=cst.Comma(), ), ], ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": ( "match x:\n" + " case a.b(): pass\n" + " case a.b(None): pass\n" + " case a.b(None,): pass\n" + " case a.b(foo=None): pass\n" + " case a.b(foo=None,): pass\n" + " case a.b(None,None,foo=None,bar=None,): pass\n" ), "parser": parser, }, # as pattern { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( pattern=cst.MatchAs(), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchAs(name=cst.Name("foo")), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchAs( pattern=cst.MatchSingleton(cst.Name("None")), name=cst.Name("bar"), whitespace_before_as=cst.SimpleWhitespace(" "), whitespace_after_as=cst.SimpleWhitespace(" "), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": "match x:\n" + " case _: pass\n" + " case foo: pass\n" + " case None as bar: pass\n", "parser": parser, }, # or pattern { "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( pattern=cst.MatchOr( [ cst.MatchOrElement( cst.MatchSingleton(cst.Name("None")), cst.BitOr(), ), cst.MatchOrElement( cst.MatchSingleton(cst.Name("False")), cst.BitOr(), ), cst.MatchOrElement( cst.MatchSingleton(cst.Name("True")) ), ] ), body=cst.SimpleStatementSuite((cst.Pass(),)), ) ], ), "code": "match x:\n case None | False | True: pass\n", "parser": parser, }, { # exercise sentinels "node": cst.Match( subject=cst.Name("x"), cases=[ cst.MatchCase( pattern=cst.MatchList( [cst.MatchStar(), cst.MatchStar()], lbracket=None, rbracket=None, ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchTuple( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")) ) ] ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchAs( pattern=cst.MatchTuple( [ cst.MatchSequenceElement( cst.MatchSingleton(cst.Name("None")) ) ] ), name=cst.Name("bar"), ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), cst.MatchCase( pattern=cst.MatchOr( [ cst.MatchOrElement( cst.MatchSingleton(cst.Name("None")), ), cst.MatchOrElement( cst.MatchSingleton(cst.Name("False")), ), cst.MatchOrElement( cst.MatchSingleton(cst.Name("True")) ), ] ), body=cst.SimpleStatementSuite((cst.Pass(),)), ), ], ), "code": "match x:\n" + " case *_, *_: pass\n" + " case (None,): pass\n" + " case (None,) as bar: pass\n" + " case None | False | True: pass\n", "parser": None, }, # Match without whitespace between keyword and the expr { "node": cst.Match( subject=cst.Name( "x", lpar=[cst.LeftParen()], rpar=[cst.RightParen()] ), cases=[ cst.MatchCase( pattern=cst.MatchSingleton( cst.Name( "None", lpar=[cst.LeftParen()], rpar=[cst.RightParen()], ) ), body=cst.SimpleStatementSuite((cst.Pass(),)), whitespace_after_case=cst.SimpleWhitespace( value="", ), ), ], whitespace_after_match=cst.SimpleWhitespace( value="", ), ), "code": "match(x):\n case(None): pass\n", "parser": parser, }, ) ) def test_valid(self, **kwargs: Any) -> None: self.validate_node(**kwargs)