Skip to content

Commit

Permalink
Merge pull request #821 from asottile/deprecated-ast-things
Browse files Browse the repository at this point in the history
remove dependence on deprecated ast things
  • Loading branch information
asottile committed May 6, 2023
2 parents 62b19b2 + 22b98a5 commit b824576
Show file tree
Hide file tree
Showing 15 changed files with 115 additions and 75 deletions.
14 changes: 10 additions & 4 deletions pyupgrade/_plugins/default_encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ def visit_Call(
parent: ast.AST,
) -> Iterable[tuple[Offset, TokenFunc]]:
if (
isinstance(node.func, ast.Attribute) and
isinstance(node.func.value, (ast.Str, ast.JoinedStr)) and
isinstance(node.func, ast.Attribute) and (
(
isinstance(node.func.value, ast.Constant) and
isinstance(node.func.value.value, str)
) or
isinstance(node.func.value, ast.JoinedStr)
) and
node.func.attr == 'encode' and
not has_starargs(node) and
len(node.args) == 1 and
isinstance(node.args[0], ast.Str) and
is_codec(node.args[0].s, 'utf-8')
isinstance(node.args[0], ast.Constant) and
isinstance(node.args[0].value, str) and
is_codec(node.args[0].value, 'utf-8')
):
yield ast_to_offset(node), _fix_default_encoding
3 changes: 2 additions & 1 deletion pyupgrade/_plugins/format_locals.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def visit_Call(
if (
state.settings.min_version >= (3, 6) and
isinstance(node.func, ast.Attribute) and
isinstance(node.func.value, ast.Str) and
isinstance(node.func.value, ast.Constant) and
isinstance(node.func.value.value, str) and
node.func.attr == 'format' and
len(node.args) == 0 and
len(node.keywords) == 1 and
Expand Down
5 changes: 3 additions & 2 deletions pyupgrade/_plugins/fstrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,13 @@ def visit_Call(

if (
isinstance(node.func, ast.Attribute) and
isinstance(node.func.value, ast.Str) and
isinstance(node.func.value, ast.Constant) and
isinstance(node.func.value.value, str) and
node.func.attr == 'format' and
not has_starargs(node)
):
try:
parsed = parse_format(node.func.value.s)
parsed = parse_format(node.func.value.value)
except ValueError:
return

Expand Down
15 changes: 9 additions & 6 deletions pyupgrade/_plugins/identity_equality.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
from pyupgrade._data import State
from pyupgrade._data import TokenFunc

LITERAL_TYPES = (ast.Str, ast.Num, ast.Bytes)


def _fix_is_literal(
i: int,
Expand All @@ -35,6 +33,14 @@ def _fix_is_literal(
tokens[i] = Token('EMPTY', '')


def _is_literal(n: ast.AST) -> bool:
return (
isinstance(n, ast.Constant) and
n.value not in {True, False} and
isinstance(n.value, (str, bytes, int, float))
)


@register(ast.Compare)
def visit_Compare(
state: State,
Expand All @@ -45,10 +51,7 @@ def visit_Compare(
for op, right in zip(node.ops, node.comparators):
if (
isinstance(op, (ast.Is, ast.IsNot)) and
(
isinstance(left, LITERAL_TYPES) or
isinstance(right, LITERAL_TYPES)
)
(_is_literal(left) or _is_literal(right))
):
func = functools.partial(_fix_is_literal, op=op)
yield ast_to_offset(right), func
Expand Down
2 changes: 1 addition & 1 deletion pyupgrade/_plugins/lru_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def _is_literal_kwarg(
) -> bool:
return (
keyword.arg == name and
isinstance(keyword.value, ast.NameConstant) and
isinstance(keyword.value, ast.Constant) and
keyword.value.value is value
)

Expand Down
6 changes: 5 additions & 1 deletion pyupgrade/_plugins/native_literals.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ def is_a_native_literal_call(
not has_starargs(node) and
(
len(node.args) == 0 or
(len(node.args) == 1 and isinstance(node.args[0], ast.Str))
(
len(node.args) == 1 and
isinstance(node.args[0], ast.Constant) and
isinstance(node.args[0].value, str)
)
)
)

Expand Down
17 changes: 11 additions & 6 deletions pyupgrade/_plugins/open_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ def visit_Call(
) and
not has_starargs(node)
):
if len(node.args) >= 2 and isinstance(node.args[1], ast.Str):
if (
len(node.args) >= 2 and
isinstance(node.args[1], ast.Constant) and
isinstance(node.args[1].value, str)
):
if (
node.args[1].s in MODE_REPLACE or
(len(node.args) == 2 and node.args[1].s in MODE_REMOVE)
node.args[1].value in MODE_REPLACE or
(len(node.args) == 2 and node.args[1].value in MODE_REMOVE)
):
func = functools.partial(_fix_open_mode, arg_idx=1)
yield ast_to_offset(node), func
Expand All @@ -99,10 +103,11 @@ def visit_Call(
)
if (
mode is not None and
isinstance(mode.value, ast.Str) and
isinstance(mode.value, ast.Constant) and
isinstance(mode.value.value, str) and
(
mode.value.s in MODE_REMOVE or
mode.value.s in MODE_REPLACE
mode.value.value in MODE_REMOVE or
mode.value.value in MODE_REPLACE
)
):
func = functools.partial(
Expand Down
19 changes: 10 additions & 9 deletions pyupgrade/_plugins/percent_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,18 +184,18 @@ def _fix_percent_format_dict(

for k in node_right.keys:
# not a string key
if not isinstance(k, ast.Str):
if not isinstance(k, ast.Constant) or not isinstance(k.value, str):
return
# duplicate key
elif k.s in seen_keys:
elif k.value in seen_keys:
return
# not an identifier
elif not k.s.isidentifier():
elif not k.value.isidentifier():
return
# a keyword
elif k.s in KEYWORDS:
elif k.value in KEYWORDS:
return
seen_keys.add(k.s)
seen_keys.add(k.value)
keys[ast_to_offset(k)] = k

# TODO: this is overly timid
Expand All @@ -212,13 +212,13 @@ def _fix_percent_format_dict(
if key is None:
continue
# we found the key, but the string didn't match (implicit join?)
elif ast.literal_eval(token.src) != key.s:
elif ast.literal_eval(token.src) != key.value:
return
# the map uses some strange syntax that's not `'key': value`
elif tokens[j + 1].src != ':' or tokens[j + 2].src != ' ':
return
else:
key_indices.append((j, key.s))
key_indices.append((j, key.value))
assert not keys, keys

tokens[brace_end] = tokens[brace_end]._replace(src=')')
Expand All @@ -238,10 +238,11 @@ def visit_BinOp(
if (
not state.settings.keep_percent_format and
isinstance(node.op, ast.Mod) and
isinstance(node.left, ast.Str)
isinstance(node.left, ast.Constant) and
isinstance(node.left.value, str)
):
try:
parsed = _parse_percent_format(node.left.s)
parsed = _parse_percent_format(node.left.value)
except ValueError:
pass
else:
Expand Down
3 changes: 2 additions & 1 deletion pyupgrade/_plugins/six_calls.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ def visit_Call(
not node.keywords and
not has_starargs(node) and
len(node.args) == 1 and
isinstance(node.args[0], ast.Str)
isinstance(node.args[0], ast.Constant) and
isinstance(node.args[0].value, str)
):
yield ast_to_offset(node), _fix_six_b
elif (
Expand Down
32 changes: 12 additions & 20 deletions pyupgrade/_plugins/type_of_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
from pyupgrade._token_helpers import find_closing_bracket
from pyupgrade._token_helpers import find_open_paren

NUM_TYPES = {
_TYPES = {
bool: 'bool',
bytes: 'bytes',
str: 'str',
int: 'int',
float: 'float',
complex: 'complex',
Expand Down Expand Up @@ -42,23 +45,12 @@ def visit_Call(
if (
isinstance(node.func, ast.Name) and
node.func.id == 'type' and
len(node.args) == 1
len(node.args) == 1 and
isinstance(node.args[0], ast.Constant) and
node.args[0].value not in {Ellipsis, None}
):
if isinstance(node.args[0], ast.Str):
func = functools.partial(
_rewrite_type_of_primitive,
src='str',
)
yield ast_to_offset(node), func
elif isinstance(node.args[0], ast.Bytes):
func = functools.partial(
_rewrite_type_of_primitive,
src='bytes',
)
yield ast_to_offset(node), func
elif isinstance(node.args[0], ast.Num):
func = functools.partial(
_rewrite_type_of_primitive,
src=NUM_TYPES[type(node.args[0].n)],
)
yield ast_to_offset(node), func
func = functools.partial(
_rewrite_type_of_primitive,
src=_TYPES[type(node.args[0].value)],
)
yield ast_to_offset(node), func
34 changes: 20 additions & 14 deletions pyupgrade/_plugins/typing_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ def _unparse(node: ast.expr) -> str:
else:
slice_s = _unparse(node_slice)
return f'{_unparse(node.value)}[{slice_s}]'
elif isinstance(node, (ast.Str, ast.Bytes)):
return repr(node.s)
elif isinstance(node, ast.Ellipsis):
elif (
isinstance(node, ast.Constant) and
isinstance(node.value, (str, bytes))
):
return repr(node.value)
elif isinstance(node, ast.Constant) and node.value is Ellipsis:
return '...'
elif isinstance(node, ast.List):
return '[{}]'.format(', '.join(_unparse(elt) for elt in node.elts))
elif isinstance(node, ast.NameConstant):
elif isinstance(node, ast.Constant) and node.value in {True, False, None}:
return repr(node.value)
elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
return f'{_unparse(node.left)} | {_unparse(node.right)}'
Expand Down Expand Up @@ -97,7 +100,7 @@ def _typed_class_replacement(

def _fix_named_tuple(i: int, tokens: list[Token], *, call: ast.Call) -> None:
types = {
tup.elts[0].s: tup.elts[1]
tup.elts[0].value: tup.elts[1]
for tup in call.args[1].elts # type: ignore # (checked below)
}
end, attrs = _typed_class_replacement(tokens, i, call, types)
Expand All @@ -123,7 +126,7 @@ def _fix_dict_typed_dict(
call: ast.Call,
) -> None:
types = {
k.s: v
k.value: v
for k, v in zip(
call.args[1].keys, # type: ignore # (checked below)
call.args[1].values, # type: ignore # (checked below)
Expand Down Expand Up @@ -160,8 +163,9 @@ def visit_Assign(
isinstance(node.targets[0], ast.Name) and
isinstance(node.value, ast.Call) and
len(node.value.args) >= 1 and
isinstance(node.value.args[0], ast.Str) and
node.targets[0].id == node.value.args[0].s and
isinstance(node.value.args[0], ast.Constant) and
isinstance(node.value.args[0].value, str) and
node.targets[0].id == node.value.args[0].value and
not has_starargs(node.value)
):
if (
Expand All @@ -178,9 +182,10 @@ def visit_Assign(
all(
isinstance(tup, ast.Tuple) and
len(tup.elts) == 2 and
isinstance(tup.elts[0], ast.Str) and
tup.elts[0].s.isidentifier() and
tup.elts[0].s not in KEYWORDS
isinstance(tup.elts[0], ast.Constant) and
isinstance(tup.elts[0].value, str) and
tup.elts[0].value.isidentifier() and
tup.elts[0].value not in KEYWORDS
for tup in node.value.args[1].elts
)
):
Expand Down Expand Up @@ -224,9 +229,10 @@ def visit_Assign(
isinstance(node.value.args[1], ast.Dict) and
node.value.args[1].keys and
all(
isinstance(k, ast.Str) and
k.s.isidentifier() and
k.s not in KEYWORDS
isinstance(k, ast.Constant) and
isinstance(k.value, str) and
k.value.isidentifier() and
k.value not in KEYWORDS
for k in node.value.args[1].keys
)
):
Expand Down
4 changes: 2 additions & 2 deletions pyupgrade/_plugins/typing_pep563.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ def _replace_string_literal(
nodes.extend(_process_call(node))
elif isinstance(node, ast.Subscript):
nodes.extend(_process_subscript(node))
elif isinstance(node, ast.Str):
func = functools.partial(_dequote, new=node.s)
elif isinstance(node, ast.Constant) and isinstance(node.value, str):
func = functools.partial(_dequote, new=node.value)
yield ast_to_offset(node), func
else:
for name in node._fields:
Expand Down
11 changes: 9 additions & 2 deletions pyupgrade/_plugins/typing_pep604.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,16 @@ def _supported_version(state: State) -> bool:

def _any_arg_is_str(node_slice: ast.expr) -> bool:
return (
isinstance(node_slice, ast.Str) or (
(
isinstance(node_slice, ast.Constant) and
isinstance(node_slice.value, str)
) or (
isinstance(node_slice, ast.Tuple) and
any(isinstance(elt, ast.Str) for elt in node_slice.elts)
any(
isinstance(elt, ast.Constant) and
isinstance(elt.value, str)
for elt in node_slice.elts
)
)
)

Expand Down
14 changes: 8 additions & 6 deletions pyupgrade/_plugins/versioned_branches.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import ast
from typing import cast
from typing import Iterable
from typing import List

from tokenize_rt import Offset
from tokenize_rt import Token
Expand Down Expand Up @@ -69,8 +68,8 @@ def _fix_py3_block_else(i: int, tokens: list[Token]) -> None:
def _eq(test: ast.Compare, n: int) -> bool:
return (
isinstance(test.ops[0], ast.Eq) and
isinstance(test.comparators[0], ast.Num) and
test.comparators[0].n == n
isinstance(test.comparators[0], ast.Constant) and
test.comparators[0].value == n
)


Expand All @@ -83,14 +82,17 @@ def _compare_to_3(
isinstance(test.ops[0], op) and
isinstance(test.comparators[0], ast.Tuple) and
len(test.comparators[0].elts) >= 1 and
all(isinstance(n, ast.Num) for n in test.comparators[0].elts)
all(
isinstance(n, ast.Constant) and isinstance(n.value, int)
for n in test.comparators[0].elts
)
):
return False

# checked above but mypy needs help
ast_elts = cast('List[ast.Num]', test.comparators[0].elts)
ast_elts = cast('list[ast.Constant]', test.comparators[0].elts)
# padding a 0 for compatibility with (3,) used as a spec
elts = tuple(e.n for e in ast_elts) + (0,)
elts = tuple(e.value for e in ast_elts) + (0,)

return elts[:2] == (3, minor) and all(n == 0 for n in elts[2:])

Expand Down
Loading

0 comments on commit b824576

Please sign in to comment.