Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pyupgrade for openSUSE:Factory checked in at 2023-06-03 00:07:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyupgrade (Old) and /work/SRC/openSUSE:Factory/.python-pyupgrade.new.15902 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyupgrade" Sat Jun 3 00:07:25 2023 rev:30 rq:1090388 version:3.4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyupgrade/python-pyupgrade.changes 2022-12-03 12:48:35.698140645 +0100 +++ /work/SRC/openSUSE:Factory/.python-pyupgrade.new.15902/python-pyupgrade.changes 2023-06-03 00:07:33.478107359 +0200 @@ -1,0 +2,7 @@ +Thu Jun 1 20:18:41 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 3.4.0: + * drop python37 support + * remove use of deprecated ast + +------------------------------------------------------------------- Old: ---- python-pyupgrade-3.2.2.tar.gz New: ---- python-pyupgrade-3.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyupgrade.spec ++++++ --- /var/tmp/diff_new_pack.JqJBRh/_old 2023-06-03 00:07:34.114111115 +0200 +++ /var/tmp/diff_new_pack.JqJBRh/_new 2023-06-03 00:07:34.122111162 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pyupgrade # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,10 +16,9 @@ # -%{?!python_module:%define python_module() python-%{**} python3-%{**}} -%define skip_python2 1 +%{?sle15_python_module_pythons} Name: python-pyupgrade -Version: 3.2.2 +Version: 3.4.0 Release: 0 Summary: A tool to automatically upgrade syntax for newer versions License: MIT ++++++ python-pyupgrade-3.2.2.tar.gz -> python-pyupgrade-3.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/.github/workflows/main.yml new/pyupgrade-3.4.0/.github/workflows/main.yml --- old/pyupgrade-3.2.2/.github/workflows/main.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/pyupgrade-3.4.0/.github/workflows/main.yml 2023-05-06 23:09:25.000000000 +0200 @@ -0,0 +1,19 @@ +name: main + +on: + push: + branches: [main, test-me-*] + tags: + pull_request: + +jobs: + main-windows: + uses: asottile/workflows/.github/workflows/tox.yml@v1.0.0 + with: + env: '["py38"]' + os: windows-latest + main-linux: + uses: asottile/workflows/.github/workflows/tox.yml@v1.0.0 + with: + env: '["py38", "py39", "py310"]' + os: ubuntu-latest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/.pre-commit-config.yaml new/pyupgrade-3.4.0/.pre-commit-config.yaml --- old/pyupgrade-3.2.2/.pre-commit-config.yaml 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/.pre-commit-config.yaml 2023-05-06 23:09:25.000000000 +0200 @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -17,26 +17,26 @@ rev: v3.9.0 hooks: - id: reorder-python-imports - args: [--py37-plus, --add-import, 'from __future__ import annotations'] + args: [--py38-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/add-trailing-comma - rev: v2.3.0 + rev: v2.4.0 hooks: - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v3.2.2 + rev: v3.4.0 hooks: - id: pyupgrade - args: [--py37-plus] + args: [--py38-plus] - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v2.0.0 + rev: v2.0.2 hooks: - id: autopep8 - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 6.0.0 hooks: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.982 + rev: v1.2.0 hooks: - id: mypy diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/README.md new/pyupgrade-3.4.0/README.md --- old/pyupgrade-3.2.2/README.md 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/README.md 2023-05-06 23:09:25.000000000 +0200 @@ -1,5 +1,4 @@ -[](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=2&branchName=main) -[](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=2&branchName=main) +[](https://github.com/asottile/pyupgrade/actions/workflows/main.yml) [](https://results.pre-commit.ci/latest/github/asottile/pyupgrade/main) pyupgrade @@ -22,7 +21,7 @@ ```yaml - repo: https://github.com/asottile/pyupgrade - rev: v3.2.2 + rev: v3.4.0 hooks: - id: pyupgrade ``` @@ -694,3 +693,16 @@ -def f(x: 'queue.Queue[int]') -> C: +def f(x: queue.Queue[int]) -> C: ``` + + +### use `datetime.UTC` alias + +Availability: +- `--py311-plus` is passed on the commandline. + +```diff + import datetime + +-datetime.timezone.utc ++datetime.UTC +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/azure-pipelines.yml new/pyupgrade-3.4.0/azure-pipelines.yml --- old/pyupgrade-3.2.2/azure-pipelines.yml 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/azure-pipelines.yml 1970-01-01 01:00:00.000000000 +0100 @@ -1,23 +0,0 @@ -trigger: - branches: - include: [main, test-me-*] - tags: - include: ['*'] - -resources: - repositories: - - repository: asottile - type: github - endpoint: github - name: asottile/azure-pipeline-templates - ref: refs/tags/v2.4.1 - -jobs: -- template: job--python-tox.yml@asottile - parameters: - toxenvs: [py37] - os: windows -- template: job--python-tox.yml@asottile - parameters: - toxenvs: [py37, py38, py39] - os: linux diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/datetime_utc_alias.py new/pyupgrade-3.4.0/pyupgrade/_plugins/datetime_utc_alias.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/datetime_utc_alias.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/datetime_utc_alias.py 2023-05-06 23:09:25.000000000 +0200 @@ -0,0 +1,35 @@ +from __future__ import annotations + +import ast +import functools +from typing import Iterable + +from tokenize_rt import Offset + +from pyupgrade._ast_helpers import ast_to_offset +from pyupgrade._data import register +from pyupgrade._data import State +from pyupgrade._data import TokenFunc +from pyupgrade._token_helpers import replace_name + + +@register(ast.Attribute) +def visit_Attribute( + state: State, + node: ast.Attribute, + parent: ast.AST, +) -> Iterable[tuple[Offset, TokenFunc]]: + if ( + state.settings.min_version >= (3, 11) and + node.attr == 'utc' and + isinstance(node.value, ast.Attribute) and + node.value.attr == 'timezone' and + isinstance(node.value.value, ast.Name) and + node.value.value.id == 'datetime' + ): + func = functools.partial( + replace_name, + name='utc', + new='datetime.UTC', + ) + yield ast_to_offset(node), func diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/default_encoding.py new/pyupgrade-3.4.0/pyupgrade/_plugins/default_encoding.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/default_encoding.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/default_encoding.py 2023-05-06 23:09:25.000000000 +0200 @@ -29,12 +29,18 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/format_locals.py new/pyupgrade-3.4.0/pyupgrade/_plugins/format_locals.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/format_locals.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/format_locals.py 2023-05-06 23:09:25.000000000 +0200 @@ -35,7 +35,8 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/fstrings.py new/pyupgrade-3.4.0/pyupgrade/_plugins/fstrings.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/fstrings.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/fstrings.py 2023-05-06 23:09:25.000000000 +0200 @@ -4,6 +4,7 @@ from typing import Iterable from tokenize_rt import Offset +from tokenize_rt import parse_string_literal from tokenize_rt import Token from tokenize_rt import tokens_to_src @@ -43,7 +44,12 @@ parts = [] i = 0 - for s, name, spec, conv in parse_format('f' + src): + + # need to remove `u` prefix so it isn't invalid syntax + prefix, rest = parse_string_literal(src) + new_src = 'f' + prefix.translate({ord('u'): None, ord('U'): None}) + rest + + for s, name, spec, conv in parse_format(new_src): if name is not None: k, dot, rest = name.partition('.') name = ''.join((params[k or str(i)], dot, rest)) @@ -93,12 +99,13 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/identity_equality.py new/pyupgrade-3.4.0/pyupgrade/_plugins/identity_equality.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/identity_equality.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/identity_equality.py 2023-05-06 23:09:25.000000000 +0200 @@ -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, @@ -35,6 +33,14 @@ 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, @@ -45,10 +51,7 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/imports.py new/pyupgrade-3.4.0/pyupgrade/_plugins/imports.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/imports.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/imports.py 2023-05-06 23:09:25.000000000 +0200 @@ -281,6 +281,7 @@ mod_start: int mod_end: int names: tuple[int, ...] + ends: tuple[int, ...] end: int @classmethod @@ -310,11 +311,14 @@ for j in range(import_token + 1, end) if tokens[j].name == 'NAME' ] + ends_by_offset = {} for i in reversed(range(len(names))): if tokens[names[i]].src == 'as': + ends_by_offset[names[i - 1]] = names[i + 1] del names[i:i + 2] + ends = tuple(ends_by_offset.get(pos, pos) for pos in names) - return cls(start, mod_start, mod_end + 1, tuple(names), end) + return cls(start, mod_start, mod_end + 1, tuple(names), ends, end) def remove_self(self, tokens: list[Token]) -> None: del tokens[self.start:self.end] @@ -327,10 +331,10 @@ if idx == 0: # look forward until next name and del del tokens[self.names[idx]:self.names[idx + 1]] else: # look backward for comma and del - j = end = self.names[idx] + j = self.names[idx] while tokens[j].src != ',': j -= 1 - del tokens[j:end + 1] + del tokens[j:self.ends[idx] + 1] def _alias_to_s(alias: ast.alias) -> str: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/lru_cache.py new/pyupgrade-3.4.0/pyupgrade/_plugins/lru_cache.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/lru_cache.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/lru_cache.py 2023-05-06 23:09:25.000000000 +0200 @@ -28,7 +28,7 @@ ) -> bool: return ( keyword.arg == name and - isinstance(keyword.value, ast.NameConstant) and + isinstance(keyword.value, ast.Constant) and keyword.value.value is value ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/native_literals.py new/pyupgrade-3.4.0/pyupgrade/_plugins/native_literals.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/native_literals.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/native_literals.py 2023-05-06 23:09:25.000000000 +0200 @@ -44,7 +44,11 @@ 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) + ) ) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/open_mode.py new/pyupgrade-3.4.0/pyupgrade/_plugins/open_mode.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/open_mode.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/open_mode.py 2023-05-06 23:09:25.000000000 +0200 @@ -81,10 +81,14 @@ ) 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 @@ -99,10 +103,11 @@ ) 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( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/percent_format.py new/pyupgrade-3.4.0/pyupgrade/_plugins/percent_format.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/percent_format.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/percent_format.py 2023-05-06 23:09:25.000000000 +0200 @@ -184,18 +184,18 @@ 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 @@ -212,13 +212,13 @@ 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=')') @@ -238,10 +238,11 @@ 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: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/six_calls.py new/pyupgrade-3.4.0/pyupgrade/_plugins/six_calls.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/six_calls.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/six_calls.py 2023-05-06 23:09:25.000000000 +0200 @@ -2,7 +2,6 @@ import ast import functools -import sys from typing import Iterable from tokenize_rt import Offset @@ -21,10 +20,8 @@ _EXPR_NEEDS_PARENS: tuple[type[ast.expr], ...] = ( ast.Await, ast.BinOp, ast.BoolOp, ast.Compare, ast.GeneratorExp, ast.IfExp, - ast.Lambda, ast.UnaryOp, + ast.Lambda, ast.UnaryOp, ast.NamedExpr, ) -if sys.version_info >= (3, 8): # pragma: >=3.8 cover - _EXPR_NEEDS_PARENS += (ast.NamedExpr,) SIX_CALLS = { 'u': '{args[0]}', @@ -143,7 +140,8 @@ 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 ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/type_of_primitive.py new/pyupgrade-3.4.0/pyupgrade/_plugins/type_of_primitive.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/type_of_primitive.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/type_of_primitive.py 2023-05-06 23:09:25.000000000 +0200 @@ -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', @@ -42,23 +45,12 @@ 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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_classes.py new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_classes.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_classes.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_classes.py 2023-05-06 23:09:25.000000000 +0200 @@ -38,14 +38,19 @@ 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)}' else: raise NotImplementedError(ast.dump(node)) @@ -95,7 +100,7 @@ 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) @@ -121,7 +126,7 @@ 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) @@ -158,8 +163,9 @@ 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 ( @@ -176,9 +182,10 @@ 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 ) ): @@ -222,9 +229,10 @@ 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 ) ): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_pep563.py new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_pep563.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_pep563.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_pep563.py 2023-05-06 23:09:25.000000000 +0200 @@ -113,8 +113,8 @@ 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: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_pep604.py new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_pep604.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/typing_pep604.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/typing_pep604.py 2023-05-06 23:09:25.000000000 +0200 @@ -128,9 +128,16 @@ 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 + ) ) ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/unpack_list_comprehension.py new/pyupgrade-3.4.0/pyupgrade/_plugins/unpack_list_comprehension.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/unpack_list_comprehension.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/unpack_list_comprehension.py 2023-05-06 23:09:25.000000000 +0200 @@ -12,11 +12,10 @@ from pyupgrade._data import State from pyupgrade._data import TokenFunc from pyupgrade._token_helpers import find_closing_bracket -from pyupgrade._token_helpers import find_comprehension_opening_bracket def _replace_list_comprehension(i: int, tokens: list[Token]) -> None: - start = find_comprehension_opening_bracket(i, tokens) + start = i end = find_closing_bracket(tokens, start) tokens[start] = tokens[start]._replace(src='(') tokens[end] = tokens[end]._replace(src=')') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_plugins/versioned_branches.py new/pyupgrade-3.4.0/pyupgrade/_plugins/versioned_branches.py --- old/pyupgrade-3.2.2/pyupgrade/_plugins/versioned_branches.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_plugins/versioned_branches.py 2023-05-06 23:09:25.000000000 +0200 @@ -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 @@ -69,8 +68,8 @@ 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 ) @@ -83,14 +82,17 @@ 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:]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/pyupgrade/_token_helpers.py new/pyupgrade-3.4.0/pyupgrade/_token_helpers.py --- old/pyupgrade-3.2.2/pyupgrade/_token_helpers.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/pyupgrade/_token_helpers.py 2023-05-06 23:09:25.000000000 +0200 @@ -2,7 +2,6 @@ import ast import keyword -import sys from typing import NamedTuple from typing import Sequence @@ -64,28 +63,11 @@ return i -if sys.version_info >= (3, 8): # pragma: >=3.8 cover - # python 3.8 fixed the offsets of generators / tuples - def _arg_token_index(tokens: list[Token], i: int, arg: ast.expr) -> int: - idx = _search_until(tokens, i, arg) + 1 - while idx < len(tokens) and tokens[idx].name in NON_CODING_TOKENS: - idx += 1 - return idx -else: # pragma: <3.8 cover - def _arg_token_index(tokens: list[Token], i: int, arg: ast.expr) -> int: - # lists containing non-tuples report the first element correctly - if isinstance(arg, ast.List): - # If the first element is a tuple, the ast lies to us about its col - # offset. We must find the first `(` token after the start of the - # list element. - if isinstance(arg.elts[0], ast.Tuple): - i = _search_until(tokens, i, arg) - return find_open_paren(tokens, i) - else: - return _search_until(tokens, i, arg.elts[0]) - # others' start position points at their first child node already - else: - return _search_until(tokens, i, arg) +def _arg_token_index(tokens: list[Token], i: int, arg: ast.expr) -> int: + idx = _search_until(tokens, i, arg) + 1 + while idx < len(tokens) and tokens[idx].name in NON_CODING_TOKENS: + idx += 1 + return idx def victims( @@ -499,17 +481,6 @@ tokens[start_idx:end_idx] = [Token('SRC', new)] -def find_comprehension_opening_bracket(i: int, tokens: list[Token]) -> int: - """Find opening bracket of comprehension given first argument.""" - if sys.version_info < (3, 8): # pragma: <3.8 cover - i -= 1 - while not (tokens[i].name == 'OP' and tokens[i].src == '[') and i: - i -= 1 - return i - else: # pragma: >=3.8 cover - return i - - def has_space_before(i: int, tokens: list[Token]) -> bool: return i >= 1 and tokens[i - 1].name in {UNIMPORTANT_WS, 'INDENT'} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/setup.cfg new/pyupgrade-3.4.0/setup.cfg --- old/pyupgrade-3.2.2/setup.cfg 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/setup.cfg 2023-05-06 23:09:25.000000000 +0200 @@ -1,6 +1,6 @@ [metadata] name = pyupgrade -version = 3.2.2 +version = 3.4.0 description = A tool to automatically upgrade syntax for newer versions. long_description = file: README.md long_description_content_type = text/markdown @@ -20,7 +20,7 @@ packages = find: install_requires = tokenize-rt>=3.2.0 -python_requires = >=3.7 +python_requires = >=3.8 [options.packages.find] exclude = @@ -42,7 +42,6 @@ disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_defs = true -no_implicit_optional = true warn_redundant_casts = true warn_unused_ignores = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/datetime_utc_alias_test.py new/pyupgrade-3.4.0/tests/features/datetime_utc_alias_test.py --- old/pyupgrade-3.2.2/tests/features/datetime_utc_alias_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/datetime_utc_alias_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -0,0 +1,41 @@ +from __future__ import annotations + +import pytest + +from pyupgrade._data import Settings +from pyupgrade._main import _fix_plugins + + +@pytest.mark.parametrize( + ('s',), + ( + pytest.param( + 'import datetime\n' + 'print(datetime.timezone(-1))', + + id='not rewriting timezone object to alias', + ), + ), +) +def test_fix_datetime_utc_alias_noop(s): + assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings(min_version=(3, 11))) == s + + +@pytest.mark.parametrize( + ('s', 'expected'), + ( + pytest.param( + 'import datetime\n' + 'print(datetime.timezone.utc)', + + 'import datetime\n' + 'print(datetime.UTC)', + + id='rewriting to alias', + ), + ), +) +def test_fix_datetime_utc_alias(s, expected): + assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings(min_version=(3, 11))) == expected diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/fstrings_test.py new/pyupgrade-3.4.0/tests/features/fstrings_test.py --- old/pyupgrade-3.2.2/tests/features/fstrings_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/fstrings_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -64,6 +64,11 @@ r'f"\N{snowman} {a}"', id='named escape sequences', ), + pytest.param( + 'u"foo{}".format(1)', + 'f"foo{1}"', + id='u-prefixed format', + ), ), ) def test_fix_fstrings(s, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/import_replaces_test.py new/pyupgrade-3.4.0/tests/features/import_replaces_test.py --- old/pyupgrade-3.2.2/tests/features/import_replaces_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/import_replaces_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -305,6 +305,13 @@ 'from collections.abc import Callable\n', id='typing.Callable is rewritable in 3.10+ only', ), + pytest.param( + 'from typing import Optional, Sequence as S\n', + (3, 10), + 'from typing import Optional\n' + 'from collections.abc import Sequence as S\n', + id='aliasing in multi from import', + ), ), ) def test_import_replaces(s, min_version, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/six_test.py new/pyupgrade-3.4.0/tests/features/six_test.py --- old/pyupgrade-3.2.2/tests/features/six_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/six_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -1,7 +1,5 @@ from __future__ import annotations -import sys - import pytest from pyupgrade._data import Settings @@ -387,17 +385,6 @@ 'x = map(str, ints)\n', id='six.moves builtin attrs', ), - ), -) -def test_fix_six(s, expected): - ret = _fix_plugins(s, settings=Settings()) - assert ret == expected - - -@pytest.mark.xfail(sys.version_info < (3, 8), reason='walrus') -@pytest.mark.parametrize( - ('s', 'expected'), - ( pytest.param( 'for _ in six.itervalues(x := y): pass', 'for _ in (x := y).values(): pass', @@ -405,7 +392,7 @@ ), ), ) -def test_fix_six_py38_plus(s, expected): +def test_fix_six(s, expected): ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/type_of_primitive_test.py new/pyupgrade-3.4.0/tests/features/type_of_primitive_test.py --- old/pyupgrade-3.2.2/tests/features/type_of_primitive_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/type_of_primitive_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -14,6 +14,10 @@ id='NoneType', ), pytest.param( + 'type(...)\n', + id='ellipsis', + ), + pytest.param( 'foo = "foo"\n' 'type(foo)\n', id='String assigned to variable', @@ -62,6 +66,13 @@ id='Empty bytes string -> bytes', ), + pytest.param( + 'type(True)\n', + + 'bool\n', + + id='bool', + ), ), ) def test_fix_type_of_primitive(s, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/typing_classes_test.py new/pyupgrade-3.4.0/tests/features/typing_classes_test.py --- old/pyupgrade-3.2.2/tests/features/typing_classes_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/typing_classes_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -210,6 +210,16 @@ id='preserves comments without alignment', ), + pytest.param( + 'from typing import NamedTuple\n' + 'Foo = NamedTuple("Foo", [("union", str | None)])', + + 'from typing import NamedTuple\n' + 'class Foo(NamedTuple):\n' + ' union: str | None', + + id='BitOr unparse error', + ), ), ) def test_fix_typing_named_tuple(s, expected): @@ -393,6 +403,16 @@ id='right after a dedent', ), + pytest.param( + 'from typing import TypedDict\n' + 'Foo = TypedDict("Foo", {"union": str | int | None})', + + 'from typing import TypedDict\n' + 'class Foo(TypedDict):\n' + ' union: str | int | None', + + id='BitOr unparse error', + ), ), ) def test_typing_typed_dict(s, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tests/features/typing_pep563_test.py new/pyupgrade-3.4.0/tests/features/typing_pep563_test.py --- old/pyupgrade-3.2.2/tests/features/typing_pep563_test.py 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tests/features/typing_pep563_test.py 2023-05-06 23:09:25.000000000 +0200 @@ -1,7 +1,5 @@ from __future__ import annotations -import sys - import pytest from pyupgrade._data import Settings @@ -338,27 +336,19 @@ id='NamedTuple with no args (invalid syntax)', ), + pytest.param( + 'from __future__ import annotations\n' + 'def foo(var0, /, var1: "MyClass") -> "MyClass":\n' + ' x: "MyClass"\n', + + 'from __future__ import annotations\n' + 'def foo(var0, /, var1: MyClass) -> MyClass:\n' + ' x: MyClass\n', + + id='posonly args', + ), ), ) def test_fix_typing_pep563(s, expected): ret = _fix_plugins(s, settings=Settings(min_version=(3, 7))) assert ret == expected - - -@pytest.mark.xfail( - sys.version_info < (3, 8), - reason='posonly args not available in Python3.7', -) -def test_fix_typing_pep563_posonlyargs(): - s = ( - 'from __future__ import annotations\n' - 'def foo(var0, /, var1: "MyClass") -> "MyClass":\n' - ' x: "MyClass"\n' - ) - expected = ( - 'from __future__ import annotations\n' - 'def foo(var0, /, var1: MyClass) -> MyClass:\n' - ' x: MyClass\n' - ) - ret = _fix_plugins(s, settings=Settings(min_version=(3, 8))) - assert ret == expected diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-3.2.2/tox.ini new/pyupgrade-3.4.0/tox.ini --- old/pyupgrade-3.2.2/tox.ini 2022-11-10 16:38:09.000000000 +0100 +++ new/pyupgrade-3.4.0/tox.ini 2023-05-06 23:09:25.000000000 +0200 @@ -1,5 +1,5 @@ [tox] -envlist = py37,py38,py39,pypy3,pre-commit +envlist = py,pypy3,pre-commit [testenv] deps = -rrequirements-dev.txt