def test_nonexpr_in_expr_context(self, template): parsed = matcher.parse_ast('[x]') m = base_matchers.Bind('bound', ast_matchers.Name()) [matchinfo] = matcher.find_iter(m, parsed) with self.assertRaises(formatting.RewriteError): template.substitute_match(parsed, matchinfo.match, {'bound': matchinfo.match})
def test_inner_nomatches(self): parsed = matcher.parse_ast('xy = 2', '<string>') matches = list( matcher.find_iter( base_matchers.MatchesRegex( r'', base_matchers.Unless(base_matchers.Anything())), parsed)) self.assertEqual(matches, [])
def test_matches(self): parsed = matcher.parse_ast('var_hello = 42', '<string>') m = base_matchers.AllOf(base_matchers.FileMatchesRegex('hello'), ast_matchers.Num()) matches = list(matcher.find_iter(m, parsed)) self.assertLen(matches, 1)
def test_nonpython_dollars_source(self, src): parsed = matcher.parse_ast(src) m = base_matchers.Bind('bound', ast_matchers.Call()) [matchinfo] = matcher.find_iter(m, parsed) self.assertEqual( src, syntactic_template.PythonExprTemplate('$bound').substitute_match( parsed, matchinfo.match, {'bound': matchinfo.match}))
def test_doesnt_match(self): parsed = matcher.parse_ast('hi = 42', '<string>') m = base_matchers.AllOf(base_matchers.FileMatchesRegex('hello'), ast_matchers.Num()) matches = list(matcher.find_iter(m, parsed)) self.assertEqual(matches, [])
def test_invalid_syntax(self): parsed = matcher.parse_ast('x') m = base_matchers.Bind('x', ast_matchers.Name()) [matchinfo] = matcher.find_iter(m, parsed) template = syntactic_template.PythonTemplate('$x') with self.assertRaises(formatting.RewriteError): template.substitute_match(parsed, matchinfo.match, {'x': match.StringMatch('x y')}),
def test_fullmatch_semantics(self): """The regexp only matches the full expression.""" for var in ['x_', '_x']: with self.subTest(var=var): parsed = matcher.parse_ast(var, '<string>') self.assertEqual( list( matcher.find_iter(base_matchers.MatchesRegex(r'x'), parsed)), [])
def test_nonpython_dollars_dest(self): src = 'f' parsed = matcher.parse_ast(src) m = base_matchers.Bind('bound', ast_matchers.Name()) [matchinfo] = matcher.find_iter(m, parsed) self.assertEqual( 'f("$x")', syntactic_template.PythonExprTemplate( '$bound("$x")').substitute_match(parsed, matchinfo.match, {'bound': matchinfo.match}))
def test_autoparen_outer(self): parsed = matcher.parse_ast('x * 2') m = base_matchers.Bind('x', ast_matchers.Name()) [matchinfo] = matcher.find_iter(m, parsed) template = syntactic_template.PythonTemplate('$x') self.assertEqual( template.substitute_match(parsed, matchinfo.match, {'x': match.StringMatch('x + y')}), '(x + y)', )
def test_bindings(self): parsed = matcher.parse_ast('2', '<string>') matches = list( matcher.find_iter( base_matchers.MatchesRegex(r'(?P<var>.)', ast_matchers.Num()), parsed)) self.assertLen(matches, 1) [m] = matches self.assertIn('var', m.bindings) self.assertEqual(m.bindings['var'].value.span, (0, 1))
def test_assignment(self, template): template = syntactic_template.PythonStmtTemplate(template) # Test with different values of `ctx` for the variable being substituted. for variable_source in 'a = 1', 'a': with self.subTest(variable_souce=variable_source): [matchinfo] = matcher.find_iter( base_matchers.Bind('x', ast_matchers.Name()), matcher.parse_ast(variable_source)) substituted = template.substitute_match( None, None, {'x': matchinfo.match}) self.assertEqual(substituted, template.template.replace('$x', 'a'))
def test_multi_regex(self): """Tests that the lazy dictionary doesn't walk over itself or something.""" parsed = matcher.parse_ast('var_hello = 42', '<string>') m = base_matchers.AllOf( base_matchers.FileMatchesRegex('var'), base_matchers.FileMatchesRegex('hello'), base_matchers.FileMatchesRegex('42'), base_matchers.FileMatchesRegex(r'\Avar_hello = 42\Z'), ast_matchers.Num()) matches = list(matcher.find_iter(m, parsed)) self.assertLen(matches, 1)
def test_nonsingular_py_ok(self, template): """Tests non-singular PythonTemplate in a context where it's acceptable. If it is not being placed into a context where it's expected to parse as an expression, then '' and even 'a; b' are fine. Args: template: the template for this test. """ parsed = matcher.parse_ast('x') m = base_matchers.Bind('bound', ast_matchers.Name()) [matchinfo] = matcher.find_iter(m, parsed) self.assertEqual( template, syntactic_template.PythonTemplate(template).substitute_match( parsed, matchinfo.match, {'bound': matchinfo.match}))
def test_matches(self): parsed = matcher.parse_ast('xy = 2', '<string>') matches = list( matcher.find_iter( base_matchers.MatchesRegex(r'^(?P<name>.)(.)$', base_matchers.Bind('inner')), parsed)) # There is only one AST node of length >= 2 (which the regex requires): xy. self.assertEqual(matches, [ matcher.MatchInfo( mock.ANY, { 'inner': mock.ANY, 'name': matcher.BoundValue(match.SpanMatch('x', (0, 1))), }) ]) [matchinfo] = matches self.assertEqual(matchinfo.match.span, (0, 2)) self.assertEqual(matchinfo.match, matchinfo.bindings['inner'].value)
def find_dicts_parsed( self, parsed: _matcher.PythonParsedFile ) -> Iterable[Tuple[Mapping[MatchKey, match.Match], Mapping[ MatchKey, formatting.Template]]]: # All node IDs that have been removed. removed_nodes = set([]) # All node IDs in a suite that have been removed AND whose previous # siblings have all been removed, as well. removed_suite_prefix_nodes = set([]) for result in _matcher.find_iter(self.matcher, parsed): matches = { bound_name: match.value for bound_name, match in result.bindings.items() } self._sanitize_removed_stmt( parsed, matches, result.replacements, removed_nodes, removed_suite_prefix_nodes, ) yield (matches, result.replacements)
def test_matcherror(self): parsed = matcher.parse_ast('x+y') bind = base_matchers.Bind('var', on_conflict=matcher.BindConflict.ERROR) m = ast_matchers.BinOp(left=bind, right=bind) self.assertEqual(list(matcher.find_iter(m, parsed)), [])
def get_all_match_strings(self, m, source_code): return [ self._get_matchinfo_string(matchinfo, source_code) for matchinfo in matcher.find_iter( m, matcher.parse_ast(source_code, '<string>')) ]
def test_nomatches(self): parsed = matcher.parse_ast('xy = 2', '<string>') matches = list( matcher.find_iter(base_matchers.MatchesRegex(r'not found'), parsed)) self.assertEqual(matches, [])