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 2021-09-25 22:51:24 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pyupgrade (Old) and /work/SRC/openSUSE:Factory/.python-pyupgrade.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyupgrade" Sat Sep 25 22:51:24 2021 rev:17 rq:921380 version:2.27.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pyupgrade/python-pyupgrade.changes 2021-09-23 23:04:14.676331565 +0200 +++ /work/SRC/openSUSE:Factory/.python-pyupgrade.new.1899/python-pyupgrade.changes 2021-09-25 22:51:29.903353222 +0200 @@ -1,0 +2,7 @@ +Fri Sep 24 19:39:14 UTC 2021 - Sebastian Wagner <sebix+novell....@sebix.at> + +- update to version 2.27.0: + - handle named escape sequences in format upgrades + - remove splatting of listcomp -> splat of generator + +------------------------------------------------------------------- @@ -12 +19 @@ - - revert pep584 rewrit + - revert pep584 rewrite Old: ---- python-pyupgrade-2.26.0.post1.tar.gz New: ---- python-pyupgrade-2.27.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pyupgrade.spec ++++++ --- /var/tmp/diff_new_pack.PvKu1d/_old 2021-09-25 22:51:30.423353884 +0200 +++ /var/tmp/diff_new_pack.PvKu1d/_new 2021-09-25 22:51:30.427353889 +0200 @@ -19,14 +19,14 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-pyupgrade -Version: 2.26.0.post1 +Version: 2.27.0 Release: 0 Summary: A tool to automatically upgrade syntax for newer versions License: MIT Group: Development/Languages/Python URL: https://github.com/asottile/pyupgrade # pypi tarball does not include tests, use github instead. PR for inclusion was denied https://github.com/asottile/pyupgrade/pull/326 -Source: https://github.com/asottile/pyupgrade/archive/fd60bbecb9668e4392ade23dd8451b9f74d9d6c7.tar.gz#/%{name}-%{version}.tar.gz +Source: https://github.com/asottile/pyupgrade/archive/refs/tags/v%{version}.tar.gz#/%{name}-%{version}.tar.gz #Source: https://files.pythonhosted.org/packages/source/p/pyupgrade/pyupgrade-%%{version}.tar.gz BuildRequires: %{python_module setuptools} BuildRequires: python-rpm-macros @@ -47,7 +47,7 @@ programming language. %prep -%setup -q -n pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7 +%setup -q -n pyupgrade-%{version} %build %python_build ++++++ python-pyupgrade-2.26.0.post1.tar.gz -> python-pyupgrade-2.27.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/.pre-commit-config.yaml new/pyupgrade-2.27.0/.pre-commit-config.yaml --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/.pre-commit-config.yaml 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/.pre-commit-config.yaml 2021-09-23 04:23:06.000000000 +0200 @@ -34,7 +34,7 @@ - id: add-trailing-comma args: [--py36-plus] - repo: https://github.com/asottile/pyupgrade - rev: v2.26.0 + rev: v2.27.0 hooks: - id: pyupgrade args: [--py36-plus] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/README.md new/pyupgrade-2.27.0/README.md --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/README.md 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/README.md 2021-09-23 04:23:06.000000000 +0200 @@ -20,7 +20,7 @@ ```yaml - repo: https://github.com/asottile/pyupgrade - rev: v2.26.0 + rev: v2.27.0 hooks: - id: pyupgrade ``` @@ -498,17 +498,6 @@ ``` -### Unpacking argument list comprehensions - -Availability: -- `--py3-plus` is passed on the commandline. - -```diff --foo(*[i for i in bar]) -+foo(*(i for i in bar)) -``` - - ### Rewrite `xml.etree.cElementTree` to `xml.etree.ElementTree` Availability: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_main.py new/pyupgrade-2.27.0/pyupgrade/_main.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_main.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/pyupgrade/_main.py 2021-09-23 04:23:06.000000000 +0200 @@ -31,8 +31,10 @@ from pyupgrade._data import Settings from pyupgrade._data import Version from pyupgrade._data import visit +from pyupgrade._string_helpers import curly_escape from pyupgrade._string_helpers import is_ascii from pyupgrade._string_helpers import is_codec +from pyupgrade._string_helpers import NAMED_UNICODE_RE from pyupgrade._token_helpers import CLOSING from pyupgrade._token_helpers import KEYWORDS from pyupgrade._token_helpers import OPENING @@ -47,21 +49,34 @@ def parse_format(s: str) -> Tuple[DotFormatPart, ...]: - """Makes the empty string not a special case. In the stdlib, there's - loss of information (the type) on the empty string. - """ - parsed = tuple(_stdlib_parse_format(s)) - if not parsed: - return ((s, None, None, None),) - else: - return parsed + """handle named escape sequences""" + ret: List[DotFormatPart] = [] + + for part in NAMED_UNICODE_RE.split(s): + if NAMED_UNICODE_RE.fullmatch(part): + if not ret: + ret.append((part, None, None, None)) + else: + ret[-1] = (ret[-1][0] + part, None, None, None) + else: + first = True + for tup in _stdlib_parse_format(part): + if not first or not ret: + ret.append(tup) + else: + ret[-1] = (ret[-1][0] + tup[0], *tup[1:]) + first = False + + if not ret: + ret.append((s, None, None, None)) + + return tuple(ret) def unparse_parsed_string(parsed: Sequence[DotFormatPart]) -> str: def _convert_tup(tup: DotFormatPart) -> str: ret, field_name, format_spec, conversion = tup - ret = ret.replace('{', '{{') - ret = ret.replace('}', '}}') + ret = curly_escape(ret) if field_name is not None: ret += '{' + field_name if conversion: @@ -786,10 +801,6 @@ return contents_text for i, token in reversed_enumerate(tokens): if token.offset in visitor.fstrings: - # TODO: handle \N escape sequences - if r'\N' in token.src: - continue - paren = i + 3 if tokens_to_src(tokens[i + 1:paren + 1]) != '.format(': continue diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_plugins/percent_format.py new/pyupgrade-2.27.0/pyupgrade/_plugins/percent_format.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_plugins/percent_format.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/pyupgrade/_plugins/percent_format.py 2021-09-23 04:23:06.000000000 +0200 @@ -18,6 +18,7 @@ from pyupgrade._data import register from pyupgrade._data import State from pyupgrade._data import TokenFunc +from pyupgrade._string_helpers import curly_escape from pyupgrade._token_helpers import KEYWORDS from pyupgrade._token_helpers import remove_brace from pyupgrade._token_helpers import victims @@ -120,7 +121,8 @@ def _percent_to_format(s: str) -> str: def _handle_part(part: PercentFormat) -> str: s, fmt = part - s = s.replace('{', '{{').replace('}', '}}') + s = curly_escape(s) + if fmt is None: return s else: @@ -155,10 +157,6 @@ *, node_right: ast.Tuple, ) -> None: - # TODO: handle \N escape sequences - if r'\N' in tokens[i].src: - return - # TODO: this is overly timid paren = i + 4 if tokens_to_src(tokens[i + 1:paren + 1]) != ' % (': @@ -181,10 +179,6 @@ *, node_right: ast.Dict, ) -> None: - # TODO: handle \N escape sequences - if r'\N' in tokens[i].src: - return - seen_keys: Set[str] = set() keys = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_plugins/unpacking_argument_list_comprehensions.py new/pyupgrade-2.27.0/pyupgrade/_plugins/unpacking_argument_list_comprehensions.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_plugins/unpacking_argument_list_comprehensions.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/pyupgrade/_plugins/unpacking_argument_list_comprehensions.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,26 +0,0 @@ -import ast -from typing import Iterable -from typing import Tuple - -from tokenize_rt import Offset - -from pyupgrade._ast_helpers import ast_to_offset -from pyupgrade._ast_helpers import is_async_listcomp -from pyupgrade._data import register -from pyupgrade._data import State -from pyupgrade._data import TokenFunc -from pyupgrade._token_helpers import replace_list_comp_brackets - - -@register(ast.Starred) -def visit_Starred( - state: State, - node: ast.Starred, - parent: ast.AST, -) -> Iterable[Tuple[Offset, TokenFunc]]: - if ( - state.settings.min_version >= (3,) and - isinstance(node.value, ast.ListComp) and - not is_async_listcomp(node.value) - ): - yield ast_to_offset(node.value), replace_list_comp_brackets diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_string_helpers.py new/pyupgrade-2.27.0/pyupgrade/_string_helpers.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/pyupgrade/_string_helpers.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/pyupgrade/_string_helpers.py 2021-09-23 04:23:06.000000000 +0200 @@ -1,4 +1,5 @@ import codecs +import re import string import sys @@ -8,6 +9,18 @@ def is_ascii(s: str) -> bool: return all(c in string.printable for c in s) +NAMED_UNICODE_RE = re.compile(r'(?<!\\)(?:\\\\)*(\\N\{[^}]+\})') + + +def curly_escape(s: str) -> str: + parts = NAMED_UNICODE_RE.split(s) + return ''.join( + part.replace('{', '{{').replace('}', '}}') + if not NAMED_UNICODE_RE.fullmatch(part) + else part + for part in parts + ) + def is_codec(encoding: str, name: str) -> bool: try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/setup.cfg new/pyupgrade-2.27.0/setup.cfg --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/setup.cfg 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/setup.cfg 2021-09-23 04:23:06.000000000 +0200 @@ -1,6 +1,6 @@ [metadata] name = pyupgrade -version = 2.26.0.post1 +version = 2.27.0 description = A tool to automatically upgrade syntax for newer versions. long_description = file: README.md long_description_content_type = text/markdown diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/format_literals_test.py new/pyupgrade-2.27.0/tests/features/format_literals_test.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/format_literals_test.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/tests/features/format_literals_test.py 2021-09-23 04:23:06.000000000 +0200 @@ -16,6 +16,14 @@ assert unparse_parsed_string(parse_format(s)) == s +def test_parse_format_starts_with_named(): + # technically not possible since our string always starts with quotes + assert parse_format(r'\N{snowman} hi {0} hello') == ( + (r'\N{snowman} hi ', '0', '', None), + (' hello', None, None, None), + ) + + @pytest.mark.parametrize( ('s', 'expected'), ( @@ -49,8 +57,6 @@ "'{' '0}'.format(1)", # comment looks like placeholder but is not! '("{0}" # {1}\n"{2}").format(1, 2, 3)', - # TODO: this works by accident (extended escape treated as placeholder) - r'"\N{snowman} {}".format(1)', # don't touch f-strings (these are wrong but don't make it worse) 'f"{0}".format(a)', ), @@ -101,6 +107,11 @@ ), # parenthesized string literals ('("{0}").format(1)', '("{}").format(1)'), + pytest.param( + r'"\N{snowman} {0}".format(1)', + r'"\N{snowman} {}".format(1)', + id='named escape sequence', + ), ), ) def test_format_literals(s, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/fstrings_test.py new/pyupgrade-2.27.0/tests/features/fstrings_test.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/fstrings_test.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/tests/features/fstrings_test.py 2021-09-23 04:23:06.000000000 +0200 @@ -26,8 +26,6 @@ '"{:{}}".format(x, y)', '"{a[b]}".format(a=a)', '"{a.a[b]}".format(a=a)', - # TODO: handle \N escape sequences - r'"\N{snowman} {}".format(a)', # not enough placeholders / placeholders missing '"{}{}".format(a)', '"{a}{b}".format(a=a)', # backslashes and quotes cannot nest @@ -58,6 +56,11 @@ ('"{}{{}}{}".format(escaped, y)', 'f"{escaped}{{}}{y}"'), ('"{}{b}{}".format(a, c, b=b)', 'f"{a}{b}{c}"'), ('"{}".format(0x0)', 'f"{0x0}"'), + pytest.param( + r'"\N{snowman} {}".format(a)', + r'f"\N{snowman} {a}"', + id='named escape sequences', + ), # TODO: poor man's f-strings? # '"{foo}".format(**locals())' ), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/percent_format_test.py new/pyupgrade-2.27.0/tests/features/percent_format_test.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/percent_format_test.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/tests/features/percent_format_test.py 2021-09-23 04:23:06.000000000 +0200 @@ -178,9 +178,6 @@ '"%(and)s" % {"and": 2}', # invalid string formats '"%" % {}', '"%(hi)" % {}', '"%2" % {}', - # TODO: handle \N escape sequences - r'"%s \N{snowman}" % (a,)', - r'"%(foo)s \N{snowman}" % {"foo": 1}', ), ) def test_percent_format_noop(s): @@ -223,6 +220,15 @@ # dict ('"%(k)s" % {"k": "v"}', '"{k}".format(k="v")'), ('"%(to_list)s" % {"to_list": []}', '"{to_list}".format(to_list=[])'), + # \N escapes + ( + r'"%s \N{snowman}" % (a,)', + r'"{} \N{snowman}".format(a)', + ), + ( + r'"%(foo)s \N{snowman}" % {"foo": 1}', + r'"{foo} \N{snowman}".format(foo=1)', + ), ), ) def test_percent_format(s, expected): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/unpacking_argument_list_comprehensions_test.py new/pyupgrade-2.27.0/tests/features/unpacking_argument_list_comprehensions_test.py --- old/pyupgrade-fd60bbecb9668e4392ade23dd8451b9f74d9d6c7/tests/features/unpacking_argument_list_comprehensions_test.py 2021-09-17 14:33:04.000000000 +0200 +++ new/pyupgrade-2.27.0/tests/features/unpacking_argument_list_comprehensions_test.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,80 +0,0 @@ -import pytest - -from pyupgrade._data import Settings -from pyupgrade._main import _fix_plugins - - -@pytest.mark.parametrize( - ('s', 'version'), - ( - pytest.param( - 'foo(*[i for i in bar])\n', - (2, 7), - id='Not Python3+', - ), - pytest.param( - '2*3', - (3,), - id='Multiplication star', - ), - pytest.param( - '2**3', - (3,), - id='Power star', - ), - pytest.param( - 'foo([i for i in bar])', - (3,), - id='List comp, no star', - ), - pytest.param( - 'foo(*bar)', - (3,), - id='Starred, no list comp', - ), - pytest.param( - 'foo(*[x async for x in bar])', - (3,), - id='async listcomp', - ), - ), -) -def test_fix_unpack_argument_list_comp_noop(s, version): - assert _fix_plugins(s, settings=Settings(min_version=version)) == s - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( - pytest.param( - 'foo(*[i for i in bar])\n', - - 'foo(*(i for i in bar))\n', - - id='Starred list comprehension', - ), - pytest.param( - 'foo(\n' - ' *\n' - ' [i for i in bar]\n' - ' )\n', - - 'foo(\n' - ' *\n' - ' (i for i in bar)\n' - ' )\n', - - id='Multiline starred list comprehension', - ), - pytest.param( - 'foo(*[i for i in bar], qux, quox=None)\n', - - 'foo(*(i for i in bar), qux, quox=None)\n', - - id='Single line, including other args', - ), - ), -) -def test_fix_unpack_argument_list_comp(s, expected): - ret = _fix_plugins(s, settings=Settings((3,))) - assert ret == expected