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)
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 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.create((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.create((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": parse_expression, }, # 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.create((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.create((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.create((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.create((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)
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)