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 2026-01-08 15:28:35
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyupgrade (Old)
and /work/SRC/openSUSE:Factory/.python-pyupgrade.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyupgrade"
Thu Jan 8 15:28:35 2026 rev:38 rq:1325884 version:3.21.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyupgrade/python-pyupgrade.changes
2025-08-13 16:33:49.012682367 +0200
+++
/work/SRC/openSUSE:Factory/.python-pyupgrade.new.1928/python-pyupgrade.changes
2026-01-08 15:29:24.345999561 +0100
@@ -1,0 +2,9 @@
+Thu Jan 8 04:06:59 UTC 2026 - Steve Kowalik <[email protected]>
+
+- Update to 3.21.2:
+ * fix unstringing multiline string annotations
+ * vendor cookie_re from cpython
+ * regenerate symbols for --py314-plus
+ * Rewrite version_info[0] and version_info.major
+
+-------------------------------------------------------------------
Old:
----
python-pyupgrade-3.20.0.tar.gz
New:
----
python-pyupgrade-3.21.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pyupgrade.spec ++++++
--- /var/tmp/diff_new_pack.XrVKjZ/_old 2026-01-08 15:29:24.858021318 +0100
+++ /var/tmp/diff_new_pack.XrVKjZ/_new 2026-01-08 15:29:24.862021489 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-pyupgrade
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,23 +18,23 @@
%{?sle15_python_module_pythons}
Name: python-pyupgrade
-Version: 3.20.0
+Version: 3.21.2
Release: 0
Summary: A tool to automatically upgrade syntax for newer versions
License: MIT
-Group: Development/Languages/Python
URL: https://github.com/asottile/pyupgrade
Source:
https://github.com/asottile/pyupgrade/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
+BuildRequires: %{python_module base >= 3.10}
BuildRequires: %{python_module pip}
BuildRequires: %{python_module setuptools}
BuildRequires: %{python_module wheel}
BuildRequires: python-rpm-macros
# SECTION test requirements
BuildRequires: %{python_module pytest}
-BuildRequires: %{python_module tokenize-rt >= 3.2.0}
+BuildRequires: %{python_module tokenize-rt >= 6.1.0}
# /SECTION
BuildRequires: fdupes
-Requires: python-tokenize-rt >= 3.2.0
+Requires: python-tokenize-rt >= 6.1.0
Requires(post): update-alternatives
Requires(postun): update-alternatives
BuildArch: noarch
++++++ python-pyupgrade-3.20.0.tar.gz -> python-pyupgrade-3.21.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/.github/workflows/main.yml
new/pyupgrade-3.21.2/.github/workflows/main.yml
--- old/pyupgrade-3.20.0/.github/workflows/main.yml 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/.github/workflows/main.yml 2025-11-19
01:39:36.000000000 +0100
@@ -10,10 +10,10 @@
main-windows:
uses: asottile/workflows/.github/workflows/[email protected]
with:
- env: '["py39"]'
+ env: '["py310"]'
os: windows-latest
main-linux:
uses: asottile/workflows/.github/workflows/[email protected]
with:
- env: '["py39", "py310", "py311", "py312"]'
+ env: '["py310", "py311", "py312", "py313"]'
os: ubuntu-latest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/.pre-commit-config.yaml
new/pyupgrade-3.21.2/.pre-commit-config.yaml
--- old/pyupgrade-3.20.0/.pre-commit-config.yaml 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/.pre-commit-config.yaml 2025-11-19
01:39:36.000000000 +0100
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
+ rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -10,32 +10,32 @@
- id: name-tests-test
- id: requirements-txt-fixer
- repo: https://github.com/asottile/setup-cfg-fmt
- rev: v2.8.0
+ rev: v3.1.0
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/asottile/reorder-python-imports
- rev: v3.14.0
+ rev: v3.16.0
hooks:
- id: reorder-python-imports
- args: [--py39-plus, --add-import, 'from __future__ import annotations']
+ args: [--py310-plus, --add-import, 'from __future__ import
annotations']
- repo: https://github.com/asottile/add-trailing-comma
- rev: v3.1.0
+ rev: v4.0.0
hooks:
- id: add-trailing-comma
- repo: https://github.com/asottile/pyupgrade
- rev: v3.20.0
+ rev: v3.21.2
hooks:
- id: pyupgrade
- args: [--py39-plus]
+ args: [--py310-plus]
- repo: https://github.com/hhatto/autopep8
rev: v2.3.2
hooks:
- id: autopep8
- repo: https://github.com/PyCQA/flake8
- rev: 7.2.0
+ rev: 7.3.0
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.15.0
+ rev: v1.18.2
hooks:
- id: mypy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/README.md
new/pyupgrade-3.21.2/README.md
--- old/pyupgrade-3.20.0/README.md 2025-05-23 20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/README.md 2025-11-19 01:39:36.000000000 +0100
@@ -21,7 +21,7 @@
```yaml
- repo: https://github.com/asottile/pyupgrade
- rev: v3.20.0
+ rev: v3.21.2
hooks:
- id: pyupgrade
```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/pyupgrade/_data.py
new/pyupgrade-3.21.2/pyupgrade/_data.py
--- old/pyupgrade-3.20.0/pyupgrade/_data.py 2025-05-23 20:55:31.000000000
+0200
+++ new/pyupgrade-3.21.2/pyupgrade/_data.py 2025-11-19 01:39:36.000000000
+0100
@@ -3,8 +3,8 @@
import ast
import collections
import pkgutil
+from collections.abc import Callable
from collections.abc import Iterable
-from typing import Callable
from typing import NamedTuple
from typing import Protocol
from typing import TypeVar
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/pyupgrade/_main.py
new/pyupgrade-3.21.2/pyupgrade/_main.py
--- old/pyupgrade-3.20.0/pyupgrade/_main.py 2025-05-23 20:55:31.000000000
+0200
+++ new/pyupgrade-3.21.2/pyupgrade/_main.py 2025-11-19 01:39:36.000000000
+0100
@@ -276,6 +276,10 @@
del tokens[victims]
+# copied from 3.15 @ 0ac890bea7
+_cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)', re.ASCII)
+
+
def _fix_tokens(contents_text: str) -> str:
try:
tokens = src_to_tokens(contents_text)
@@ -294,7 +298,7 @@
token.utf8_byte_offset == 0 and
token.line < 3 and
token.name == 'COMMENT' and
- tokenize.cookie_re.match(token.src)
+ _cookie_re.match(token.src)
):
del tokens[i]
assert tokens[i].name == 'NL', tokens[i].name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/pyupgrade/_plugins/imports.py
new/pyupgrade-3.21.2/pyupgrade/_plugins/imports.py
--- old/pyupgrade-3.20.0/pyupgrade/_plugins/imports.py 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/pyupgrade/_plugins/imports.py 2025-11-19
01:39:36.000000000 +0100
@@ -21,7 +21,7 @@
from pyupgrade._token_helpers import indented_amount
# GENERATED VIA generate-imports
-# Using reorder-python-imports==3.15.0
+# Using reorder-python-imports==3.16.0
REMOVALS = {
(3,): {
'__future__': {
@@ -242,6 +242,9 @@
('typing_extensions', 'is_protocol'): 'typing',
('typing_extensions', 'runtime_checkable'): 'typing',
},
+ (3, 14): {
+ ('typing_extensions', 'evaluate_forward_ref'): 'typing',
+ },
}
REPLACE_MODS = {
'six.moves.BaseHTTPServer': 'http.server',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pyupgrade-3.20.0/pyupgrade/_plugins/percent_format.py
new/pyupgrade-3.21.2/pyupgrade/_plugins/percent_format.py
--- old/pyupgrade-3.20.0/pyupgrade/_plugins/percent_format.py 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/pyupgrade/_plugins/percent_format.py 2025-11-19
01:39:36.000000000 +0100
@@ -195,7 +195,7 @@
elif k.value in KEYWORDS:
return
seen_keys.add(k.value)
- keys[ast_to_offset(k)] = k
+ keys[ast_to_offset(k)] = k.value
# TODO: this is overly timid
brace = i + 4
@@ -211,13 +211,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.value:
+ elif ast.literal_eval(token.src) != key:
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.value))
+ key_indices.append((j, key))
assert not keys, keys
tokens[brace_end] = tokens[brace_end]._replace(src=')')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/pyupgrade/_plugins/typing_pep563.py
new/pyupgrade-3.21.2/pyupgrade/_plugins/typing_pep563.py
--- old/pyupgrade-3.20.0/pyupgrade/_plugins/typing_pep563.py 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/pyupgrade/_plugins/typing_pep563.py 2025-11-19
01:39:36.000000000 +0100
@@ -6,6 +6,7 @@
from collections.abc import Iterable
from collections.abc import Sequence
+from tokenize_rt import NON_CODING_TOKENS
from tokenize_rt import Offset
from pyupgrade._ast_helpers import ast_to_offset
@@ -23,7 +24,15 @@
def _dequote(i: int, tokens: list[Token], *, new: str) -> None:
- tokens[i] = tokens[i]._replace(src=new)
+ end = i + 1
+ for j in range(end, len(tokens)):
+ if tokens[j].name == 'STRING':
+ end = j + 1
+ elif tokens[j].name not in NON_CODING_TOKENS:
+ break
+ else:
+ raise AssertionError('past end?')
+ tokens[i:end] = [tokens[i]._replace(src=new)]
def _get_name(node: ast.expr) -> str:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pyupgrade-3.20.0/pyupgrade/_plugins/versioned_branches.py
new/pyupgrade-3.21.2/pyupgrade/_plugins/versioned_branches.py
--- old/pyupgrade-3.20.0/pyupgrade/_plugins/versioned_branches.py
2025-05-23 20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/pyupgrade/_plugins/versioned_branches.py
2025-11-19 01:39:36.000000000 +0100
@@ -82,8 +82,20 @@
def _eq(test: ast.Compare, n: int) -> bool:
+ return _cmp(test, ast.Eq, n)
+
+
+def _lt(test: ast.Compare, n: int) -> bool:
+ return _cmp(test, ast.Lt, n)
+
+
+def _gte(test: ast.Compare, n: int) -> bool:
+ return _cmp(test, ast.GtE, n)
+
+
+def _cmp(test: ast.Compare, op: type[ast.cmpop], n: int) -> bool:
return (
- isinstance(test.ops[0], ast.Eq) and
+ isinstance(test.ops[0], op) and
isinstance(test.comparators[0], ast.Constant) and
test.comparators[0].value == n
)
@@ -164,6 +176,33 @@
for minor in range(min_version[1])
)
)
+ ) or
+ # sys.version_info[0] == 2 or < 3
+ # sys.version_info.major == 2 or < 3
+ (
+ isinstance(node.test, ast.Compare) and
+ (
+ (
+ isinstance(node.test.left, ast.Subscript) and
+ isinstance(node.test.left.slice, ast.Constant) and
+ node.test.left.slice.value == 0
+ ) or
+ (
+ isinstance(node.test.left, ast.Attribute) and
+ node.test.left.attr == 'major'
+ )
+ ) and
+ is_name_attr(
+ node.test.left.value,
+ state.from_imports,
+ ('sys',),
+ ('version_info',),
+ ) and
+ len(node.test.ops) == 1 and
+ (
+ _eq(node.test, 2) or
+ _lt(node.test, 3)
+ )
)
):
if len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If):
@@ -211,6 +250,33 @@
for minor in range(min_version[1])
)
)
+ ) or
+ # sys.version_info[0] == 3 or >= 3
+ # sys.version_info.major == 3 or >= 3
+ (
+ isinstance(node.test, ast.Compare) and
+ (
+ (
+ isinstance(node.test.left, ast.Subscript) and
+ isinstance(node.test.left.slice, ast.Constant) and
+ node.test.left.slice.value == 0
+ ) or
+ (
+ isinstance(node.test.left, ast.Attribute) and
+ node.test.left.attr == 'major'
+ )
+ ) and
+ is_name_attr(
+ node.test.left.value,
+ state.from_imports,
+ ('sys',),
+ ('version_info',),
+ ) and
+ len(node.test.ops) == 1 and
+ (
+ _eq(node.test, 3) or
+ _gte(node.test, 3)
+ )
)
):
if len(node.orelse) == 1 and isinstance(node.orelse[0], ast.If):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyupgrade-3.20.0/setup.cfg
new/pyupgrade-3.21.2/setup.cfg
--- old/pyupgrade-3.20.0/setup.cfg 2025-05-23 20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/setup.cfg 2025-11-19 01:39:36.000000000 +0100
@@ -1,6 +1,6 @@
[metadata]
name = pyupgrade
-version = 3.20.0
+version = 3.21.2
description = A tool to automatically upgrade syntax for newer versions.
long_description = file: README.md
long_description_content_type = text/markdown
@@ -19,7 +19,7 @@
packages = find:
install_requires =
tokenize-rt>=6.1.0
-python_requires = >=3.9
+python_requires = >=3.10
[options.packages.find]
exclude =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pyupgrade-3.20.0/tests/features/typing_pep563_test.py
new/pyupgrade-3.21.2/tests/features/typing_pep563_test.py
--- old/pyupgrade-3.20.0/tests/features/typing_pep563_test.py 2025-05-23
20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/tests/features/typing_pep563_test.py 2025-11-19
01:39:36.000000000 +0100
@@ -365,6 +365,20 @@
id='posonly args',
),
+ pytest.param(
+ 'from __future__ import annotations\n'
+ 'x: (\n'
+ ' "int | "\n'
+ ' "str"\n'
+ ')\n',
+
+ 'from __future__ import annotations\n'
+ 'x: (\n'
+ ' int | str\n'
+ ')\n',
+
+ id='multiline implicit-concat annotation',
+ ),
),
)
def test_fix_typing_pep563(s, expected):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pyupgrade-3.20.0/tests/features/versioned_branches_test.py
new/pyupgrade-3.21.2/tests/features/versioned_branches_test.py
--- old/pyupgrade-3.20.0/tests/features/versioned_branches_test.py
2025-05-23 20:55:31.000000000 +0200
+++ new/pyupgrade-3.21.2/tests/features/versioned_branches_test.py
2025-11-19 01:39:36.000000000 +0100
@@ -317,6 +317,46 @@
id='sys.version_info == 2',
),
pytest.param(
+ 'if sys.version_info[0] == 2:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ '3\n',
+
+ id='sys.version_info[0] == 2',
+ ),
+ pytest.param(
+ 'if sys.version_info[0] < 3:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ '3\n',
+
+ id='sys.version_info[0] < 3',
+ ),
+ pytest.param(
+ 'if sys.version_info.major == 2:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ '3\n',
+
+ id='sys.version_info.major == 2',
+ ),
+ pytest.param(
+ 'if sys.version_info.major < 3:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ '3\n',
+
+ id='sys.version_info.major < 3',
+ ),
+ pytest.param(
'if sys.version_info < (3,):\n'
' 2\n'
'else:\n'
@@ -367,6 +407,46 @@
id='sys.version_info >= (3,)',
),
pytest.param(
+ 'if sys.version_info[0] == 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ '3\n',
+
+ id='sys.version_info[0]== 3',
+ ),
+ pytest.param(
+ 'if sys.version_info[0] >= 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ '3\n',
+
+ id='sys.version_info[0] >= 3',
+ ),
+ pytest.param(
+ 'if sys.version_info.major == 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ '3\n',
+
+ id='testme sys.version_info.major == 3',
+ ),
+ pytest.param(
+ 'if sys.version_info.major >= 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ '3\n',
+
+ id='sys.version_info.major >= 3',
+ ),
+ pytest.param(
'from sys import version_info\n'
'if version_info > (3,):\n'
' 3\n'
@@ -379,6 +459,102 @@
id='from sys import version_info, > (3,)',
),
pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info[0] == 2:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, [0] == 2',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info[0] < 3:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, [0] < 3',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info.major == 2:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, .major == 2',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info.major < 3:\n'
+ ' 2\n'
+ 'else:\n'
+ ' 3\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, .major < 3',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info[0] == 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, [0] == 3',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info[0] >= 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, [0] >= 3',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info.major == 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, .major == 3',
+ ),
+ pytest.param(
+ 'from sys import version_info\n'
+ 'if version_info.major >= 3:\n'
+ ' 3\n'
+ 'else:\n'
+ ' 2\n',
+
+ 'from sys import version_info\n'
+ '3\n',
+
+ id='from sys import version_info, .major >= 3',
+ ),
+ pytest.param(
'if True:\n'
' print(1)\n'
'elif six.PY2:\n'