Ast Call signature changed on 3.5
fix issue 744 on bitbucket port of merge request 296 https://bitbucket.org/pytest-dev/pytest/pull-request/296/astcall-signature-changed-on-35 https://bitbucket.org/pytest-dev/pytest/issue/744/
This commit is contained in:
		
							parent
							
								
									8f4f2c665d
								
							
						
					
					
						commit
						26e64fc45c
					
				|  | @ -9,6 +9,7 @@ env: | ||||||
|     - TESTENV=py26 |     - TESTENV=py26 | ||||||
|     - TESTENV=py27 |     - TESTENV=py27 | ||||||
|     - TESTENV=py34 |     - TESTENV=py34 | ||||||
|  |     - TESTENV=py35 | ||||||
|     - TESTENV=pypy |     - TESTENV=pypy | ||||||
|     - TESTENV=py27-pexpect |     - TESTENV=py27-pexpect | ||||||
|     - TESTENV=py33-pexpect |     - TESTENV=py33-pexpect | ||||||
|  |  | ||||||
|  | @ -1,6 +1,10 @@ | ||||||
| 2.8.0.dev (compared to 2.7.X) | 2.8.0.dev (compared to 2.7.X) | ||||||
| ----------------------------- | ----------------------------- | ||||||
| 
 | 
 | ||||||
|  | - fix issue744: fix for ast.Call changes in Python 3.5+.  Thanks | ||||||
|  |   Guido van Rossum, Matthias Bussonnier, Stefan Zimmermann and | ||||||
|  |   Thomas Kluyver. | ||||||
|  | 
 | ||||||
| - fix issue768: docstrings found in python modules were not setting up session | - fix issue768: docstrings found in python modules were not setting up session | ||||||
|   fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR. |   fixtures. Thanks Jason R. Coombs for reporting and Bruno Oliveira for the PR. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -35,6 +35,12 @@ PYC_TAIL = "." + PYTEST_TAG + PYC_EXT | ||||||
| REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2) | REWRITE_NEWLINES = sys.version_info[:2] != (2, 7) and sys.version_info < (3, 2) | ||||||
| ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3 | ASCII_IS_DEFAULT_ENCODING = sys.version_info[0] < 3 | ||||||
| 
 | 
 | ||||||
|  | if sys.version_info >= (3,5): | ||||||
|  |     ast_Call = ast.Call | ||||||
|  | else : | ||||||
|  |     ast_Call = lambda a,b,c : ast.Call(a, b, c, None, None) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class AssertionRewritingHook(object): | class AssertionRewritingHook(object): | ||||||
|     """PEP302 Import hook which rewrites asserts.""" |     """PEP302 Import hook which rewrites asserts.""" | ||||||
| 
 | 
 | ||||||
|  | @ -593,7 +599,7 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|         """Call a helper in this module.""" |         """Call a helper in this module.""" | ||||||
|         py_name = ast.Name("@pytest_ar", ast.Load()) |         py_name = ast.Name("@pytest_ar", ast.Load()) | ||||||
|         attr = ast.Attribute(py_name, "_" + name, ast.Load()) |         attr = ast.Attribute(py_name, "_" + name, ast.Load()) | ||||||
|         return ast.Call(attr, list(args), [], None, None) |         return ast_Call(attr, list(args), []) | ||||||
| 
 | 
 | ||||||
|     def builtin(self, name): |     def builtin(self, name): | ||||||
|         """Return the builtin called *name*.""" |         """Return the builtin called *name*.""" | ||||||
|  | @ -683,7 +689,7 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|         msg = self.pop_format_context(template) |         msg = self.pop_format_context(template) | ||||||
|         fmt = self.helper("format_explanation", msg) |         fmt = self.helper("format_explanation", msg) | ||||||
|         err_name = ast.Name("AssertionError", ast.Load()) |         err_name = ast.Name("AssertionError", ast.Load()) | ||||||
|         exc = ast.Call(err_name, [fmt], [], None, None) |         exc = ast_Call(err_name, [fmt], []) | ||||||
|         if sys.version_info[0] >= 3: |         if sys.version_info[0] >= 3: | ||||||
|             raise_ = ast.Raise(exc, None) |             raise_ = ast.Raise(exc, None) | ||||||
|         else: |         else: | ||||||
|  | @ -703,7 +709,7 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|     def visit_Name(self, name): |     def visit_Name(self, name): | ||||||
|         # Display the repr of the name if it's a local variable or |         # Display the repr of the name if it's a local variable or | ||||||
|         # _should_repr_global_name() thinks it's acceptable. |         # _should_repr_global_name() thinks it's acceptable. | ||||||
|         locs = ast.Call(self.builtin("locals"), [], [], None, None) |         locs = ast_Call(self.builtin("locals"), [], []) | ||||||
|         inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs]) |         inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs]) | ||||||
|         dorepr = self.helper("should_repr_global_name", name) |         dorepr = self.helper("should_repr_global_name", name) | ||||||
|         test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) |         test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) | ||||||
|  | @ -730,7 +736,7 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|             res, expl = self.visit(v) |             res, expl = self.visit(v) | ||||||
|             body.append(ast.Assign([ast.Name(res_var, ast.Store())], res)) |             body.append(ast.Assign([ast.Name(res_var, ast.Store())], res)) | ||||||
|             expl_format = self.pop_format_context(ast.Str(expl)) |             expl_format = self.pop_format_context(ast.Str(expl)) | ||||||
|             call = ast.Call(app, [expl_format], [], None, None) |             call = ast_Call(app, [expl_format], []) | ||||||
|             self.on_failure.append(ast.Expr(call)) |             self.on_failure.append(ast.Expr(call)) | ||||||
|             if i < levels: |             if i < levels: | ||||||
|                 cond = res |                 cond = res | ||||||
|  | @ -759,7 +765,44 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|         res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) |         res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) | ||||||
|         return res, explanation |         return res, explanation | ||||||
| 
 | 
 | ||||||
|     def visit_Call(self, call): |     def visit_Call_35(self, call): | ||||||
|  |         """ | ||||||
|  |         visit `ast.Call` nodes on Python3.5 and after | ||||||
|  |         """ | ||||||
|  |         new_func, func_expl = self.visit(call.func) | ||||||
|  |         arg_expls = [] | ||||||
|  |         new_args = [] | ||||||
|  |         new_kwargs = [] | ||||||
|  |         for arg in call.args: | ||||||
|  |             if type(arg) is ast.Starred: | ||||||
|  |                 new_star, expl = self.visit(arg) | ||||||
|  |                 arg_expls.append("*" + expl) | ||||||
|  |                 new_args.append(new_star) | ||||||
|  |             else: | ||||||
|  |                 res, expl = self.visit(arg) | ||||||
|  |                 new_args.append(res) | ||||||
|  |                 arg_expls.append(expl) | ||||||
|  |         for keyword in call.keywords: | ||||||
|  |             if keyword.arg: | ||||||
|  |                 res, expl = self.visit(keyword.value) | ||||||
|  |                 new_kwargs.append(ast.keyword(keyword.arg, res)) | ||||||
|  |                 arg_expls.append(keyword.arg + "=" + expl) | ||||||
|  |             else: ## **args have `arg` keywords with an .arg of None | ||||||
|  |                 res, expl = self.visit(keyword.value) | ||||||
|  |                 new_kwargs.append(ast.keyword(keyword.arg, res)) | ||||||
|  |                 arg_expls.append("**" + expl) | ||||||
|  | 
 | ||||||
|  |         expl = "%s(%s)" % (func_expl, ', '.join(arg_expls)) | ||||||
|  |         new_call = ast.Call(new_func, new_args, new_kwargs) | ||||||
|  |         res = self.assign(new_call) | ||||||
|  |         res_expl = self.explanation_param(self.display(res)) | ||||||
|  |         outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) | ||||||
|  |         return res, outer_expl | ||||||
|  | 
 | ||||||
|  |     def visit_Call_legacy(self, call): | ||||||
|  |         """ | ||||||
|  |         visit `ast.Call nodes on 3.4 and below` | ||||||
|  |         """ | ||||||
|         new_func, func_expl = self.visit(call.func) |         new_func, func_expl = self.visit(call.func) | ||||||
|         arg_expls = [] |         arg_expls = [] | ||||||
|         new_args = [] |         new_args = [] | ||||||
|  | @ -787,6 +830,15 @@ class AssertionRewriter(ast.NodeVisitor): | ||||||
|         outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) |         outer_expl = "%s\n{%s = %s\n}" % (res_expl, res_expl, expl) | ||||||
|         return res, outer_expl |         return res, outer_expl | ||||||
| 
 | 
 | ||||||
|  |     # ast.Call signature changed on 3.5, | ||||||
|  |     # conditionally change  which methods is named | ||||||
|  |     # visit_Call depending on Python version | ||||||
|  |     if sys.version_info >= (3, 5): | ||||||
|  |         visit_Call = visit_Call_35 | ||||||
|  |     else: | ||||||
|  |         visit_Call = visit_Call_legacy | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     def visit_Attribute(self, attr): |     def visit_Attribute(self, attr): | ||||||
|         if not isinstance(attr.ctx, ast.Load): |         if not isinstance(attr.ctx, ast.Load): | ||||||
|             return self.generic_visit(attr) |             return self.generic_visit(attr) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue