def test_wildcard_some_call_args(self): pat = prepare_pattern("f(??, 1)") assert isinstance(pat.args, listmiddle) assert pat.args.front == [] assert_ast_like(pat.args.back[0], ast.Num(n=1)) assert pat.starargs is None assert pat.keywords == must_not_exist_checker
def assert_ast_like(self, f, target): from lambdex.utils.ast import ( ast_from_source, pformat, pprint, recursively_set_attr, ) ast_f = f.__ast__ recursively_set_attr(ast_f, "type_comment", None) ast_target = ast_from_source(target, "def") ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = "\n".join( [ "", "===> Compiled:", pformat(ast_f), "===> Target:", pformat(ast_target), ] ) raise AssertionError(msg) from cause
def test_subscript_no_ctx(self): pat = prepare_pattern('?[2]') assert_ast_like(pat, ast.Subscript(slice=ast.Index(value=ast.Num(n=2)))) assert not hasattr(pat, 'ctx') matches = get_matches(pat, 'd[2] = 1') assert len(matches) == 1
def test_must_not_exist(self): assert_ast_like(for_noelse_sample.body[0], for_noelse_template) with self.assertRaisesRegexp(astcheck.ASTMismatch, "Expected: nothing") as raised: assert_ast_like(for_else_sample.body[0], for_noelse_template) assert raised.exception.path == ['tree', 'orelse']
def test_keywords_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(e=4, ??=??)")) it = apf.scan_ast(self.ast) assert_ast_like(next(it), ast.Call(keywords=[ast.keyword(arg='d'), ast.keyword(arg='e'),]) ) self.assert_no_more(it)
def test_wildcard_call_mixed_args(self): pat = prepare_pattern("f(1, ??, a=2, **{'b':3})") assert isinstance(pat.args, listmiddle) assert_ast_like(pat.args.front[0], ast.Num(n=1)) assert not hasattr(pat, 'starargs') assert isinstance(pat.keywords, types.FunctionType) assert_ast_like(pat.kwargs, ast.Dict(keys=[ast.Str(s='b')], values=[ast.Num(n=3)]))
def test_wildcard_some_call_args(self): pat = prepare_pattern("f(??, 1)") assert isinstance(pat.args, listmiddle) assert pat.args.front == [] assert_ast_like(pat.args.back[0], ast.Num(n=1)) if sys.version_info < (3, 5): assert pat.starargs is None assert pat.keywords == must_not_exist_checker
def test_wildcard_funcdef(self): pat = prepare_pattern("def f(??): ??") assert_ast_like(pat, ast.FunctionDef(name='f')) assert isinstance(pat.args.args, listmiddle) assert pat.args.args.front == [] assert pat.args.args.back == [] assert not hasattr(pat.args.args, 'vararg') assert not hasattr(pat.args.args, 'kwonlyargs') assert not hasattr(pat.args.args, 'kwarg')
def kwargs_checker(sample_keywords, path): sample_kwargs = {k.arg: k.value for k in sample_keywords} for k in template_keywords: if k.arg == MULTIWILDCARD_NAME: continue if k.arg in sample_kwargs: astcheck.assert_ast_like(sample_kwargs[k.arg], k.value, path+[k.arg]) else: raise astcheck.ASTMismatch(path, '(missing)', 'keyword arg %s' % k.arg)
def test_keywords_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(e=4, ??=??)")) it = apf.scan_ast(self.ast) assert_ast_like( next(it), ast.Call(keywords=[ ast.keyword(arg='d'), ast.keyword(arg='e'), ])) self.assert_no_more(it)
def kwargs_checker(sample_keywords, path): sample_kwargs = {k.arg: k.value for k in sample_keywords} for k in template_keywords: if k.arg == MULTIWILDCARD_NAME: continue if k.arg in sample_kwargs: astcheck.assert_ast_like(sample_kwargs[k.arg], k.value, path + [k.arg]) else: raise astcheck.ASTMismatch(path, '(missing)', 'keyword arg %s' % k.arg)
def assert_ast_like(self, f, target): from lambdex.utils.ast import ast_from_source, pformat, pprint, recursively_set_attr ast_f = f.__ast__ recursively_set_attr(ast_f, 'type_comment', None) ast_target = ast_from_source(target, 'async def') ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = '\n'.join(['', '===> Compiled:', pformat(ast_f), '===> Target:', pformat(ast_target)]) raise AssertionError(msg) from cause
def test_wildcard_call_mixed_args(self): pat = prepare_pattern("f(1, ??, a=2, **{'b':3})") assert isinstance(pat.args, listmiddle) assert_ast_like(pat.args.front[0], ast.Num(n=1)) assert not hasattr(pat, 'starargs') assert isinstance(pat.keywords, types.FunctionType) kwargs_dict = ast.Dict(keys=[ast.Str(s='b')], values=[ast.Num(n=3)]) if sys.version_info < (3, 5): assert_ast_like(pat.kwargs, kwargs_dict) else: pat.keywords([ast.keyword(arg=None, value=kwargs_dict), ast.keyword(arg='a', value=ast.Num(n=2))], [])
def test_pos_final_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(1, ??)")) it = apf.scan_ast(self.ast) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1)])) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1), ast.Num(n=2)])) assert_ast_like(next(it), ast.Call(starargs=ast.Name(id='c'))) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1)], keywords=[ast.keyword(arg='d'), ast.keyword(arg='e'), ]) ) assert_ast_like(next(it), ast.Call(kwargs=ast.Name(id='k'))) self.assert_no_more(it)
def test_wildcard_call_mixed_args(self): pat = prepare_pattern("f(1, ??, a=2, **{'b':3})") assert isinstance(pat.args, listmiddle) assert_ast_like(pat.args.front[0], ast.Num(n=1)) assert not hasattr(pat, 'starargs') assert isinstance(pat.keywords, types.FunctionType) kwargs_dict = ast.Dict(keys=[ast.Str(s='b')], values=[ast.Num(n=3)]) if sys.version_info < (3, 5): assert_ast_like(pat.kwargs, kwargs_dict) else: pat.keywords([ ast.keyword(arg=None, value=kwargs_dict), ast.keyword(arg='a', value=ast.Num(n=2)) ], [])
def test_pos_final_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(1, ??)")) it = apf.scan_ast(self.ast) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1)])) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1), ast.Num(n=2)])) assert_ast_like(next(it), ast.Call(starargs=ast.Name(id='c'))) assert_ast_like( next(it), ast.Call(args=[ast.Num(n=1)], keywords=[ ast.keyword(arg='d'), ast.keyword(arg='e'), ])) assert_ast_like(next(it), ast.Call(kwargs=ast.Name(id='k'))) self.assert_no_more(it)
def assert_ast_like(self, f, target): ast_f = f.__ast__ recursively_set_attr(ast_f, "type_comment", None) if is_coroutine_ast(ast_f): keyword = "async def" else: keyword = "def" ast_target = ast_from_source(target, keyword) ast_target.name = ast_f.name try: assert_ast_like(ast_f, ast_target) except AssertionError as cause: msg = "\n".join([ "", "===> Compiled:", pformat(ast_f), "===> Target:", pformat(ast_target), ]) raise AssertionError(msg) from cause
def test_all_divisions(self): pat = ast.BinOp(op=ast.Div()) it = ASTPatternFinder(pat).scan_file(StringIO(division_sample)) assert_ast_like(next(it), ast.BinOp(left=ast.Num(n=1))) assert_ast_like(next(it), ast.BinOp(right=ast.Name(id='c'))) assert_ast_like(next(it), ast.BinOp(left=ast.Name(id='x'))) self.assert_no_more(it)
def test_makefunction(): res = cell2function.makefunction('foobar', cell1, user_ns={'sysmod': sys}) assert_ast_like(ast.parse(res), template)
def test_wrongnode(self): with self.assertRaises(astcheck.ASTNodeTypeMismatch): assert_ast_like(sample1, template1_wrongnode) assert not is_ast_like(sample1, template1_wrongnode)
def test_wildcard_funcdef_earlyargs(self): pat = prepare_pattern("def f(??, a): ??") assert isinstance(pat.args.args, listmiddle) assert_ast_like(pat.args.args.back[0], ast.arg(arg='a')) assert pat.args.vararg is must_not_exist_checker assert pat.args.kwonly_args_dflts == []
def test_lt_7(self): assert_ast_like(number_sample, number_template_ok)
def test_not_name_or_attr(self): with self.assertRaises(astcheck.ASTNodeTypeMismatch) as raised: assert_ast_like(sample4, template4_not_name_or_attr) assert raised.exception.path == ['tree', 'body', 'right']
def test_wrong_node_type(self): with self.assertRaises(astcheck.ASTNodeTypeMismatch) as raised: assert_ast_like(sample3, template3_wrong_node_type) assert raised.exception.path == ['tree', 'body', -1]
def test_too_few_nodes(self): with self.assertRaises(astcheck.ASTNodeListMismatch) as raised: assert_ast_like(sample3, template3_too_few_nodes) assert raised.exception.path == ['tree', 'body', '<front>']
def test_simple_wildcard(self): pat = prepare_pattern('?/?') assert_ast_like(pat, ast.BinOp(op=ast.Div())) assert pat.left is must_exist_checker assert pat.right is must_exist_checker
def test_wildcard_body_part(self): pat = prepare_pattern("def foo():\n ??\n return a") assert isinstance(pat, ast.FunctionDef) assert isinstance(pat.body, listmiddle) assert_ast_like(pat.body.back[0], ast.Return(ast.Name(id='a')))
def test_pos_leading_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(??, 2)")) it = apf.scan_ast(self.ast) assert_ast_like(next(it), ast.Call(args=[ast.Num(n=1), ast.Num(n=2)])) self.assert_no_more(it)
def test_name_or_attr(self): pat = prepare_pattern('a = 1') assert_ast_like(pat, ast.Assign(value=ast.Num(1))) assert (isinstance(pat.targets[0], types.FunctionType) \ or isinstance(pat.targets[0], name_or_attr))
def test_block_must_exist(self): pat = ast.If(orelse=must_exist_checker) it = ASTPatternFinder(pat).scan_file(StringIO(if_sample)) assert_ast_like(next(it), ast.If(test=ast.Name(id='a'))) self.assert_no_more(it)
def test_matching(self): assert_ast_like(sample3, template3) assert is_ast_like(sample3, template3) assert isinstance(template3.body.front[0], ast.Delete) assert isinstance(template3.body.back[0], ast.Delete)
def test_wrong_back(self): with self.assertRaises(astcheck.ASTPlainObjMismatch) as raised: assert_ast_like(sample3, template3_wrong_back) assert raised.exception.path[:3] == ['tree', 'body', -1]
def test_name_or_attr_correct(self): assert_ast_like(sample4, template4) assert is_ast_like(sample4, template4)
def test_mixed_wildcard(self): apf = ASTPatternFinder(prepare_pattern("f(??, d=?)")) matches = list(apf.scan_ast(self.ast)) assert len(matches) == 4 assert_ast_like(matches[-1], ast.Call(kwargs=ast.Name(id='k')))
def test_attr_wrong(self): with self.assertRaises(astcheck.ASTPlainObjMismatch) as raised: assert_ast_like(sample4, template4_attr_wrong) assert raised.exception.path == ['tree', 'body', 'left', 'left', 'attr']
def test_attr_no_ctx(self): pat = prepare_pattern('?.baz') assert_ast_like(pat, ast.Attribute(attr='baz')) assert not hasattr(pat, 'ctx') matches = get_matches(pat, 'foo.baz = 1') assert len(matches) == 1
def test_lt_7_wrong(self): with self.assertRaisesRegexp(astcheck.ASTMismatch, "Expected: < 7") as raised: assert_ast_like(number_sample, number_template_wrong) assert raised.exception.path == ['tree', 'body', 'left', 'n']
def test_matching(self): assert_ast_like(sample1, template1) assert is_ast_like(sample1, template1) assert_ast_like(sample2, template2) assert is_ast_like(sample2, template2)
def test_wrong_plain_value(self): with self.assertRaisesRegexp(astcheck.ASTPlainObjMismatch, "'d' instead of 'e'"): assert_ast_like(sample1, template1_wrongvalue) assert not is_ast_like(sample1, template1_wrongvalue)
def test_wrong_nodelist(self): with self.assertRaisesRegexp(astcheck.ASTNodeListMismatch, re.escape("5 node(s) instead of 4")): assert_ast_like(sample1, template1_wrongnodelist) assert not is_ast_like(sample1, template1_wrongnodelist)
def test_wrong_plain_list(self): with self.assertRaisesRegexp(astcheck.ASTPlainListMismatch, re.escape("Expected: ['x', 'y']")): assert_ast_like(sample2, template2_wronglist) assert not is_ast_like(sample2, template2_wronglist)
def test_plain(self): pat = prepare_pattern('1/2') assert_ast_like( pat, ast.BinOp(left=ast.Num(n=1), op=ast.Div(), right=ast.Num(n=2)))
def __call__(self, sample_node, path): # Check positional-or-keyword args if self.args: if isinstance(self.args, list): astcheck._check_node_list(path + ['args'], sample_node.args, self.args) else: assert_ast_like(sample_node.args, self.args) # Check defaults for positional-or-keyword args if self.defaults: sample_args_w_defaults = sample_node.args[-len(sample_node.defaults ):] sample_arg_defaults = { a.arg: d for a, d in zip(sample_args_w_defaults, sample_node.defaults) } for argname, dflt in self.defaults: try: sample_dflt = sample_arg_defaults[argname] except KeyError: raise astcheck.ASTMismatch(path + ['defaults', argname], "(missing default)", dflt) else: assert_ast_like(dflt, sample_dflt, path + ['defaults', argname]) # *args if self.vararg: assert_ast_like(sample_node.vararg, self.vararg) # keyword-only arguments sample_kwonlyargs = { k.arg: (k, d) for k, d in zip(sample_node.kwonlyargs, sample_node.kw_defaults) } for template_arg, template_dflt in self.kwonly_args_dflts: argname = template_arg.arg try: sample_arg, sample_dflt = sample_kwonlyargs[argname] except KeyError: raise astcheck.ASTMismatch(path + ['kwonlyargs'], '(missing)', 'keyword arg %s' % argname) else: assert_ast_like(sample_arg, template_arg, path + ['kwonlyargs', argname]) if template_dflt is not None: assert_ast_like(sample_dflt, template_dflt, path + ['kw_defaults', argname]) # If keyword-only-args weren't wildcarded, then there shouldn't # be any more args in the sample than the template if not self.koa_subset: template_kwarg_names = {k.arg for k, d in self.kwonly_args_dflts} excess_names = set(sample_kwonlyargs) - template_kwarg_names if excess_names: raise astcheck.ASTMismatch(path + ['kwonlyargs'], excess_names, "(not present in template)") # **kwargs if self.kwarg: assert_ast_like(sample_node.kwarg, self.kwarg)