Avoid ast deprecation warnings on Python 3.12

Fix #10977.
This commit is contained in:
Ran Benita 2023-05-10 10:36:09 +03:00
parent 0ded3297a9
commit 9335a0b445
2 changed files with 36 additions and 21 deletions

View File

@ -46,8 +46,14 @@ if TYPE_CHECKING:
if sys.version_info >= (3, 8): if sys.version_info >= (3, 8):
namedExpr = ast.NamedExpr namedExpr = ast.NamedExpr
astNameConstant = ast.Constant
astStr = ast.Constant
astNum = ast.Constant
else: else:
namedExpr = ast.Expr namedExpr = ast.Expr
astNameConstant = ast.NameConstant
astStr = ast.Str
astNum = ast.Num
assertstate_key = StashKey["AssertionState"]() assertstate_key = StashKey["AssertionState"]()
@ -680,9 +686,12 @@ class AssertionRewriter(ast.NodeVisitor):
if ( if (
expect_docstring expect_docstring
and isinstance(item, ast.Expr) and isinstance(item, ast.Expr)
and isinstance(item.value, ast.Str) and isinstance(item.value, astStr)
): ):
doc = item.value.s if sys.version_info >= (3, 8):
doc = item.value.value
else:
doc = item.value.s
if self.is_rewrite_disabled(doc): if self.is_rewrite_disabled(doc):
return return
expect_docstring = False expect_docstring = False
@ -814,7 +823,7 @@ class AssertionRewriter(ast.NodeVisitor):
current = self.stack.pop() current = self.stack.pop()
if self.stack: if self.stack:
self.explanation_specifiers = self.stack[-1] self.explanation_specifiers = self.stack[-1]
keys = [ast.Str(key) for key in current.keys()] keys = [astStr(key) for key in current.keys()]
format_dict = ast.Dict(keys, list(current.values())) format_dict = ast.Dict(keys, list(current.values()))
form = ast.BinOp(expl_expr, ast.Mod(), format_dict) form = ast.BinOp(expl_expr, ast.Mod(), format_dict)
name = "@py_format" + str(next(self.variable_counter)) name = "@py_format" + str(next(self.variable_counter))
@ -868,16 +877,16 @@ class AssertionRewriter(ast.NodeVisitor):
negation = ast.UnaryOp(ast.Not(), top_condition) negation = ast.UnaryOp(ast.Not(), top_condition)
if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook
msg = self.pop_format_context(ast.Str(explanation)) msg = self.pop_format_context(astStr(explanation))
# Failed # Failed
if assert_.msg: if assert_.msg:
assertmsg = self.helper("_format_assertmsg", assert_.msg) assertmsg = self.helper("_format_assertmsg", assert_.msg)
gluestr = "\n>assert " gluestr = "\n>assert "
else: else:
assertmsg = ast.Str("") assertmsg = astStr("")
gluestr = "assert " gluestr = "assert "
err_explanation = ast.BinOp(ast.Str(gluestr), ast.Add(), msg) err_explanation = ast.BinOp(astStr(gluestr), ast.Add(), msg)
err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation) err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation)
err_name = ast.Name("AssertionError", ast.Load()) err_name = ast.Name("AssertionError", ast.Load())
fmt = self.helper("_format_explanation", err_msg) fmt = self.helper("_format_explanation", err_msg)
@ -893,8 +902,8 @@ class AssertionRewriter(ast.NodeVisitor):
hook_call_pass = ast.Expr( hook_call_pass = ast.Expr(
self.helper( self.helper(
"_call_assertion_pass", "_call_assertion_pass",
ast.Num(assert_.lineno), astNum(assert_.lineno),
ast.Str(orig), astStr(orig),
fmt_pass, fmt_pass,
) )
) )
@ -913,7 +922,7 @@ class AssertionRewriter(ast.NodeVisitor):
variables = [ variables = [
ast.Name(name, ast.Store()) for name in self.format_variables ast.Name(name, ast.Store()) for name in self.format_variables
] ]
clear_format = ast.Assign(variables, ast.NameConstant(None)) clear_format = ast.Assign(variables, astNameConstant(None))
self.statements.append(clear_format) self.statements.append(clear_format)
else: # Original assertion rewriting else: # Original assertion rewriting
@ -924,9 +933,9 @@ class AssertionRewriter(ast.NodeVisitor):
assertmsg = self.helper("_format_assertmsg", assert_.msg) assertmsg = self.helper("_format_assertmsg", assert_.msg)
explanation = "\n>assert " + explanation explanation = "\n>assert " + explanation
else: else:
assertmsg = ast.Str("") assertmsg = astStr("")
explanation = "assert " + explanation explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation)) template = ast.BinOp(assertmsg, ast.Add(), astStr(explanation))
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())
@ -938,7 +947,7 @@ class AssertionRewriter(ast.NodeVisitor):
# Clear temporary variables by setting them to None. # Clear temporary variables by setting them to None.
if self.variables: if self.variables:
variables = [ast.Name(name, ast.Store()) for name in self.variables] variables = [ast.Name(name, ast.Store()) for name in self.variables]
clear = ast.Assign(variables, ast.NameConstant(None)) clear = ast.Assign(variables, astNameConstant(None))
self.statements.append(clear) self.statements.append(clear)
# Fix locations (line numbers/column offsets). # Fix locations (line numbers/column offsets).
for stmt in self.statements: for stmt in self.statements:
@ -952,20 +961,20 @@ class AssertionRewriter(ast.NodeVisitor):
# thinks it's acceptable. # thinks it's acceptable.
locs = ast.Call(self.builtin("locals"), [], []) locs = ast.Call(self.builtin("locals"), [], [])
target_id = name.target.id # type: ignore[attr-defined] target_id = name.target.id # type: ignore[attr-defined]
inlocs = ast.Compare(ast.Str(target_id), [ast.In()], [locs]) inlocs = ast.Compare(astStr(target_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])
expr = ast.IfExp(test, self.display(name), ast.Str(target_id)) expr = ast.IfExp(test, self.display(name), astStr(target_id))
return name, self.explanation_param(expr) return name, self.explanation_param(expr)
def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]: def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]:
# 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"), [], []) locs = ast.Call(self.builtin("locals"), [], [])
inlocs = ast.Compare(ast.Str(name.id), [ast.In()], [locs]) inlocs = ast.Compare(astStr(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])
expr = ast.IfExp(test, self.display(name), ast.Str(name.id)) expr = ast.IfExp(test, self.display(name), astStr(name.id))
return name, self.explanation_param(expr) return name, self.explanation_param(expr)
def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]: def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]:
@ -1003,7 +1012,7 @@ class AssertionRewriter(ast.NodeVisitor):
self.push_format_context() self.push_format_context()
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(astStr(expl))
call = ast.Call(app, [expl_format], []) call = ast.Call(app, [expl_format], [])
self.expl_stmts.append(ast.Expr(call)) self.expl_stmts.append(ast.Expr(call))
if i < levels: if i < levels:
@ -1015,7 +1024,7 @@ class AssertionRewriter(ast.NodeVisitor):
self.statements = body = inner self.statements = body = inner
self.statements = save self.statements = save
self.expl_stmts = fail_save self.expl_stmts = fail_save
expl_template = self.helper("_format_boolop", expl_list, ast.Num(is_or)) expl_template = self.helper("_format_boolop", expl_list, astNum(is_or))
expl = self.pop_format_context(expl_template) expl = self.pop_format_context(expl_template)
return ast.Name(res_var, ast.Load()), self.explanation_param(expl) return ast.Name(res_var, ast.Load()), self.explanation_param(expl)
@ -1118,9 +1127,9 @@ class AssertionRewriter(ast.NodeVisitor):
next_expl = f"({next_expl})" next_expl = f"({next_expl})"
results.append(next_res) results.append(next_res)
sym = BINOP_MAP[op.__class__] sym = BINOP_MAP[op.__class__]
syms.append(ast.Str(sym)) syms.append(astStr(sym))
expl = f"{left_expl} {sym} {next_expl}" expl = f"{left_expl} {sym} {next_expl}"
expls.append(ast.Str(expl)) expls.append(astStr(expl))
res_expr = ast.Compare(left_res, [op], [next_res]) res_expr = ast.Compare(left_res, [op], [next_res])
self.statements.append(ast.Assign([store_names[i]], res_expr)) self.statements.append(ast.Assign([store_names[i]], res_expr))
left_res, left_expl = next_res, next_expl left_res, left_expl = next_res, next_expl

View File

@ -18,6 +18,7 @@ import ast
import dataclasses import dataclasses
import enum import enum
import re import re
import sys
import types import types
from typing import Callable from typing import Callable
from typing import Iterator from typing import Iterator
@ -26,6 +27,11 @@ from typing import NoReturn
from typing import Optional from typing import Optional
from typing import Sequence from typing import Sequence
if sys.version_info >= (3, 8):
astNameConstant = ast.Constant
else:
astNameConstant = ast.NameConstant
__all__ = [ __all__ = [
"Expression", "Expression",
@ -132,7 +138,7 @@ IDENT_PREFIX = "$"
def expression(s: Scanner) -> ast.Expression: def expression(s: Scanner) -> ast.Expression:
if s.accept(TokenType.EOF): if s.accept(TokenType.EOF):
ret: ast.expr = ast.NameConstant(False) ret: ast.expr = astNameConstant(False)
else: else:
ret = expr(s) ret = expr(s)
s.accept(TokenType.EOF, reject=True) s.accept(TokenType.EOF, reject=True)