def test_expression_sibling(self, expr): self.assertEqual( self.get_all_match_strings( base_matchers.AllOf( ast_matchers.Name(), syntax_matchers.HasNextSibling(ast_matchers.Name())), expr), ['a', 'b'])
def test_no_sibling(self, expr): self.assertEmpty( self.get_all_match_strings( base_matchers.AllOf( ast_matchers.Name(), syntax_matchers.HasNextSibling(ast_matchers.Name())), expr))
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_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_fully_specified_matcher(self): parsed, e = expression('~a') self.assertEqual( ast_matchers.UnaryOp( op=ast_matchers.Invert(), operand=ast_matchers.Name(ctx=ast_matchers.Load())).match( matcher.MatchContext(parsed), e), matcher.MatchInfo( matcher.LexicalASTMatch(e, parsed.text, e.first_token, e.last_token)))
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_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_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_in_named_function(self): self.assertEqual( self.get_all_match_strings( base_matchers.AllOf( ast_matchers.Name(), syntax_matchers.InNamedFunction( ast_matchers.FunctionDef(name='foo'))), textwrap.dedent("""\ in_nothing def parent(): in_parent def foo(): in_foo def foo_nested(): in_foo_nested def bar(): in_bar """), ), ['in_foo'])
def _in_exception_handler(identifier, on_conflict): """Returns a matcher for a node in the nearest ancestor `except` & binds `identifier`. Args: identifier: Name of variable to bind the identifier in the nearest ancestor exception handler to on_conflict: BindConflict strategy for binding the identifier """ return syntax_matchers.HasFirstAncestor( ast_matchers.ExceptHandler(), ast_matchers.ExceptHandler(name=base_matchers.AnyOf( # In PY2, the name is a `Name` but in PY3 just a # string. # So rather than capturing and merging the Name # nodes, we capture and merge the actual string # identifier. ast_matchers.Name( id=base_matchers.Bind(identifier, on_conflict=on_conflict)), base_matchers.Bind(identifier, on_conflict=on_conflict), )))
url= 'https://refex.readthedocs.io/en/latest/guide/fixers/logging_exceptions.html', significant=True, category=_LOGGING_EXCEPTION_CATEGORY, matcher=base_matchers.AllOf( ast_matchers.Call( func=base_matchers.Bind( 'logging_error', syntax_matchers.ExprPattern('logging.error')), args=base_matchers.Contains( base_matchers.AllOf( _in_exception_handler( 'e', on_conflict=matcher_.BindConflict.MERGE_IDENTICAL), ast_matchers.Name(id=base_matchers.Bind( 'e', on_conflict=matcher_.BindConflict.MERGE_IDENTICAL)) )), keywords=base_matchers.Unless( base_matchers.Contains( ast_matchers.keyword(arg='exc_info'))), ), ), replacement=dict(logging_error=syntactic_template.PythonStmtTemplate( 'logging.exception')), example_fragment=textwrap.dedent(""" try: x = bar() + baz() except KeyError as e: logging.error('Bad thing happened: %s', e) """), example_replacement=textwrap.dedent("""
def test_ast_matchers(self): for expr in ['ast_matchers.Name()', 'Name()']: with self.subTest(expr=expr): self.assertEqual(evaluate.compile_matcher(expr), ast_matchers.Name())