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 2022-01-06 15:51:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyupgrade (Old)
 and      /work/SRC/openSUSE:Factory/.python-pyupgrade.new.1896 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pyupgrade"

Thu Jan  6 15:51:19 2022 rev:21 rq:944190 version:2.31.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyupgrade/python-pyupgrade.changes        
2021-11-20 02:39:56.684620864 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-pyupgrade.new.1896/python-pyupgrade.changes  
    2022-01-06 15:52:04.152997148 +0100
@@ -1,0 +2,32 @@
+Mon Jan  3 11:37:47 UTC 2022 - Sebastian Wagner <sebix+novell....@sebix.at>
+
+- - update to version 2.31.0:
+ - rewrite string formatting with **locals()
+- update to version 2.30.1:
+ - don't rewrite six.reraise with named args
+- update to version 2.30.0:
+ - rewrite abspath(__file__) to __file__ in py39+
+ - fix __path__ type annotation
+ - fix the diff output of `forced str("native") literals` section
+ - improve coverage pragmas with covdefaults 2.1
+ - Use org-default .github/FUNDING.yml
+   Committed via https://github.com/asottile/all-repos
+ - Rewrite docs examples with commented code to use diffs
+
+-------------------------------------------------------------------
+Tue Dec 28 16:15:14 UTC 2021 - Sebastian Wagner <sebix+novell....@sebix.at>
+
+- - update to version 2.30.0:
+ - rewrite abspath(__file__) to __file__ in py39+
+ - fix __path__ type annotation
+ - fix the diff output of `forced str("native") literals` section
+ - improve coverage pragmas with covdefaults 2.1
+ - Use org-default .github/FUNDING.yml
+   Committed via https://github.com/asottile/all-repos
+ - Rewrite docs examples with commented code to use diffs
+- update to version 2.29.1:
+ - prevent rewriting union types with forward annotations
+ - replace exit(main()) with raise SystemExit(main())
+   Committed via https://github.com/asottile/all-repos
+
+-------------------------------------------------------------------

Old:
----
  python-pyupgrade-2.29.1.tar.gz

New:
----
  python-pyupgrade-2.31.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pyupgrade.spec ++++++
--- /var/tmp/diff_new_pack.knMMx4/_old  2022-01-06 15:52:04.476997326 +0100
+++ /var/tmp/diff_new_pack.knMMx4/_new  2022-01-06 15:52:04.484997330 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pyupgrade
 #
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-pyupgrade
-Version:        2.29.1
+Version:        2.31.0
 Release:        0
 Summary:        A tool to automatically upgrade syntax for newer versions
 License:        MIT

++++++ python-pyupgrade-2.29.1.tar.gz -> python-pyupgrade-2.31.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/.github/FUNDING.yml 
new/pyupgrade-2.31.0/.github/FUNDING.yml
--- old/pyupgrade-2.29.1/.github/FUNDING.yml    2021-11-16 02:13:55.000000000 
+0100
+++ new/pyupgrade-2.31.0/.github/FUNDING.yml    1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-github: asottile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/.pre-commit-config.yaml 
new/pyupgrade-2.31.0/.pre-commit-config.yaml
--- old/pyupgrade-2.29.1/.pre-commit-config.yaml        2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/.pre-commit-config.yaml        2022-01-01 
01:43:09.000000000 +0100
@@ -1,6 +1,6 @@
 repos:
 -   repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.0.1
+    rev: v4.1.0
     hooks:
     -   id: check-docstring-first
     -   id: check-yaml
@@ -11,7 +11,7 @@
     -   id: requirements-txt-fixer
     -   id: trailing-whitespace
 -   repo: https://github.com/asottile/setup-cfg-fmt
-    rev: v1.19.0
+    rev: v1.20.0
     hooks:
     -   id: setup-cfg-fmt
 -   repo: https://github.com/PyCQA/flake8
@@ -29,16 +29,16 @@
     -   id: reorder-python-imports
         args: [--py3-plus]
 -   repo: https://github.com/asottile/add-trailing-comma
-    rev: v2.2.0
+    rev: v2.2.1
     hooks:
     -   id: add-trailing-comma
         args: [--py36-plus]
 -   repo: https://github.com/asottile/pyupgrade
-    rev: v2.29.1
+    rev: v2.31.0
     hooks:
     -   id: pyupgrade
         args: [--py36-plus]
 -   repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v0.910-1
+    rev: v0.930
     hooks:
     -   id: mypy
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/README.md 
new/pyupgrade-2.31.0/README.md
--- old/pyupgrade-2.29.1/README.md      2021-11-16 02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/README.md      2022-01-01 01:43:09.000000000 +0100
@@ -20,7 +20,7 @@
 
 ```yaml
 -   repo: https://github.com/asottile/pyupgrade
-    rev: v2.29.1
+    rev: v2.31.0
     hooks:
     -   id: pyupgrade
 ```
@@ -29,38 +29,53 @@
 
 ### Set literals
 
-```python
-set(())              # set()
-set([])              # set()
-set((1,))            # {1}
-set((1, 2))          # {1, 2}
-set([1, 2])          # {1, 2}
-set(x for x in y)    # {x for x in y}
-set([x for x in y])  # {x for x in y}
+```diff
+-set(())
++set()
+-set([])
++set()
+-set((1,))
++{1}
+-set((1, 2))
++{1, 2}
+-set([1, 2])
++{1, 2}
+-set(x for x in y)
++{x for x in y}
+-set([x for x in y])
++{x for x in y}
 ```
 
 ### Dictionary comprehensions
 
-```python
-dict((a, b) for a, b in y)    # {a: b for a, b in y}
-dict([(a, b) for a, b in y])  # {a: b for a, b in y}
+```diff
+-dict((a, b) for a, b in y)
++{a: b for a, b in y}
+-dict([(a, b) for a, b in y])
++{a: b for a, b in y}
 ```
 
 
 ### Generator expressions for some built-in functions (pep 289)
 
-```python
-min([i for i in range(3)])  # min(i for i in range(3))
-max([i for i in range(3)])  # max(i for i in range(3))
-sum([i for i in range(3)])  # sum(i for i in range(3))
-''.join([str(i) for i in range(3)])  # ''.join(str(i) for i in range(3))
+```diff
+-min([i for i in range(3)])
++min(i for i in range(3))
+-max([i for i in range(3)])
++max(i for i in range(3))
+-sum([i for i in range(3)])
++sum(i for i in range(3))
+-''.join([str(i) for i in range(3)])
++''.join(str(i) for i in range(3))
 ```
 
 ### Python2.7+ Format Specifiers
 
-```python
-'{0} {1}'.format(1, 2)    # '{} {}'.format(1, 2)
-'{0}' '{1}'.format(1, 2)  # '{}' '{}'.format(1, 2)
+```diff
+-'{0} {1}'.format(1, 2)
++'{} {}'.format(1, 2)
+-'{0}' '{1}'.format(1, 2)
++'{}' '{}'.format(1, 2)
 ```
 
 ### printf-style string formatting
@@ -68,10 +83,13 @@
 Availability:
 - Unless `--keep-percent-format` is passed.
 
-```python
-'%s %s' % (a, b)                  # '{} {}'.format(a, b)
-'%r %2f' % (a, b)                 # '{!r} {:2f}'.format(a, b)
-'%(a)s %(b)s' % {'a': 1, 'b': 2}  # '{a} {b}'.format(a=1, b=2)
+```diff
+-'%s %s' % (a, b)
++'{} {}'.format(a, b)
+-'%r %2f' % (a, b)
++'{!r} {:2f}'.format(a, b)
+-'%(a)s %(b)s' % {'a': 1, 'b': 2}
++'{a} {b}'.format(a=1, b=2)
 ```
 
 ### Unicode literals
@@ -80,24 +98,30 @@
 - File imports `from __future__ import unicode_literals`
 - `--py3-plus` is passed on the commandline.
 
-```python
-u'foo'      # 'foo'
-u"foo"      # 'foo'
-u'''foo'''  # '''foo'''
+```diff
+-u'foo'
++'foo'
+-u"foo"
++'foo'
+-u'''foo'''
++'''foo'''
 ```
 
 ### Invalid escape sequences
 
-```python
-# strings with only invalid sequences become raw strings
-'\d'    # r'\d'
-# strings with mixed valid / invalid sequences get escaped
-'\n\d'  # '\n\\d'
-# `ur` is not a valid string prefix in python3
-u'\d'   # u'\\d'
-
-# this fixes a syntax error in python3.3+
-'\N'    # r'\N'
+```diff
+ # strings with only invalid sequences become raw strings
+-'\d'
++r'\d'
+ # strings with mixed valid / invalid sequences get escaped
+-'\n\d'
++'\n\\d'
+ # `ur` is not a valid string prefix in python3
+-u'\d'
++u'\\d'
+ # this fixes a syntax error in python3.3+
+-'\N'
++r'\N'
 
 # note: pyupgrade is timid in one case (that's usually a mistake)
 # in python2.x `'\u2603'` is the same as `'\\u2603'` without `unicode_literals`
@@ -109,58 +133,80 @@
 In python3.8+, comparison to literals becomes a `SyntaxWarning` as the success
 of those comparisons is implementation specific (due to common object caching).
 
-```python
-x is 5      # x == 5
-x is not 5  # x != 5
-x is 'foo'  # x == 'foo'
+```diff
+-x is 5
++x == 5
+-x is not 5
++x != 5
+-x is 'foo'
++x == 'foo'
 ```
 
 ### `ur` string literals
 
 `ur'...'` literals are not valid in python 3.x
 
-```python
-ur'foo'         # u'foo'
-ur'\s'          # u'\\s'
-# unicode escapes are left alone
-ur'\u2603'      # u'\u2603'
-ur'\U0001f643'  # u'\U0001f643'
+```diff
+-ur'foo'
++u'foo'
+-ur'\s'
++u'\\s'
+ # unicode escapes are left alone
+-ur'\u2603'
++u'\u2603'
+-ur'\U0001f643'
++u'\U0001f643'
 ```
 
 ### `.encode()` to bytes literals
 
-```python
-'foo'.encode()           # b'foo'
-'foo'.encode('ascii')    # b'foo'
-'foo'.encode('utf-8')    # b'foo'
-u'foo'.encode()          # b'foo'
-'\xa0'.encode('latin1')  # b'\xa0'
+```diff
+-'foo'.encode()
++b'foo'
+-'foo'.encode('ascii')
++b'foo'
+-'foo'.encode('utf-8')
++b'foo'
+-u'foo'.encode()
++b'foo'
+-'\xa0'.encode('latin1')
++b'\xa0'
 ```
 
 ### Long literals
 
-```python
-5L                            # 5
-5l                            # 5
-123456789123456789123456789L  # 123456789123456789123456789
+```diff
+-5L
++5
+-5l
++5
+-123456789123456789123456789L
++123456789123456789123456789
 ```
 
 ### Octal literals
 
-```
-0755  # 0o755
-05    # 5
+```diff
+-0755
++0o755
+-05
++5
 ```
 
 ### extraneous parens in `print(...)`
 
 A fix for [python-modernize/python-modernize#178]
 
-```python
-print(())                       # ok: printing an empty tuple
-print((1,))                     # ok: printing a tuple
-sum((i for i in range(3)), [])  # ok: parenthesized generator argument
-print(("foo"))                  # print("foo")
+```diff
+ # ok: printing an empty tuple
+ print(())
+ # ok: printing a tuple
+ print((1,))
+ # ok: parenthesized generator argument
+ sum((i for i in range(3)), [])
+ # fixed:
+-print(("foo"))
++print("foo")
 ```
 
 [python-modernize/python-modernize#178]: 
https://github.com/python-modernize/python-modernize/issues/178
@@ -189,10 +235,11 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-class C(Base):
-    def f(self):
-        super(C, self).f()   # super().f()
+```diff
+ class C(Base):
+     def f(self):
+-        super(C, self).f()
++        super().f()
 ```
 
 ### "new style" classes
@@ -202,15 +249,18 @@
 
 #### rewrites class declaration
 
-```python
-class C(object): pass     # class C: pass
-class C(B, object): pass  # class C(B): pass
+```diff
+-class C(object): pass
++class C: pass
+-class C(B, object): pass
++class C(B): pass
 ```
 
 #### removes `__metaclass__ = type` declaration
 
 ```diff
--__metaclass__ = type
+ class C:
+-    __metaclass__ = type
 ```
 
 ### forced `str("native")` literals
@@ -218,9 +268,11 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-str()       # "''"
-str("foo")  # "foo"
+```diff
+-str()
++''
+-str("foo")
++"foo"
 ```
 
 ### `.encode("utf-8")`
@@ -228,8 +280,9 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-"foo".encode("utf-8")  # "foo".encode()
+```diff
+-"foo".encode("utf-8")
++"foo".encode()
 ```
 
 ### `# coding: ...` comment
@@ -285,13 +338,14 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-def f():
-    for x in y:       # yield from y
-        yield x
-
-    for a, b in c:    # yield from c
-        yield (a, b)
+```diff
+ def f():
+-    for x in y:
+-        yield x
++    yield from y
+-    for a, b in c:
+-        yield (a, b)
++    yield from c
 ```
 
 ### Python2 and old Python3.x blocks
@@ -351,74 +405,127 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-six.text_type             # str
-six.binary_type           # bytes
-six.class_types           # (type,)
-six.string_types          # (str,)
-six.integer_types         # (int,)
-six.unichr                # chr
-six.iterbytes             # iter
-six.print_(...)           # print(...)
-six.exec_(c, g, l)        # exec(c, g, l)
-six.advance_iterator(it)  # next(it)
-six.next(it)              # next(it)
-six.callable(x)           # callable(x)
-six.moves.range(x)        # range(x)
-six.moves.xrange(x)       # range(x)
-
-from six import text_type
-text_type                 # str
-
-@six.python_2_unicode_compatible  # decorator is removed
-class C:
-    def __str__(self):
-        return u'C()'
-
-class C(six.Iterator): pass              # class C: pass
-
-class C(six.with_metaclass(M, B)): pass  # class C(B, metaclass=M): pass
-
-@six.add_metaclass(M)   # class C(B, metaclass=M): pass
-class C(B): pass
-
-isinstance(..., six.class_types)    # isinstance(..., type)
-issubclass(..., six.integer_types)  # issubclass(..., int)
-isinstance(..., six.string_types)   # isinstance(..., str)
-
-six.b('...')                            # b'...'
-six.u('...')                            # '...'
-six.byte2int(bs)                        # bs[0]
-six.indexbytes(bs, i)                   # bs[i]
-six.int2byte(i)                         # bytes((i,))
-six.iteritems(dct)                      # dct.items()
-six.iterkeys(dct)                       # dct.keys()
-six.itervalues(dct)                     # dct.values()
-next(six.iteritems(dct))                # next(iter(dct.items()))
-next(six.iterkeys(dct))                 # next(iter(dct.keys()))
-next(six.itervalues(dct))               # next(iter(dct.values()))
-six.viewitems(dct)                      # dct.items()
-six.viewkeys(dct)                       # dct.keys()
-six.viewvalues(dct)                     # dct.values()
-six.create_unbound_method(fn, cls)      # fn
-six.get_unbound_function(meth)          # meth
-six.get_method_function(meth)           # meth.__func__
-six.get_method_self(meth)               # meth.__self__
-six.get_function_closure(fn)            # fn.__closure__
-six.get_function_code(fn)               # fn.__code__
-six.get_function_defaults(fn)           # fn.__defaults__
-six.get_function_globals(fn)            # fn.__globals__
-six.raise_from(exc, exc_from)           # raise exc from exc_from
-six.reraise(tp, exc, tb)                # raise exc.with_traceback(tb)
-six.reraise(*sys.exc_info())            # raise
-six.assertCountEqual(self, a1, a2)      # self.assertCountEqual(a1, a2)
-six.assertRaisesRegex(self, e, r, fn)   # self.assertRaisesRegex(e, r, fn)
-six.assertRegex(self, s, r)             # self.assertRegex(s, r)
-
-# note: only for *literals*
-six.ensure_binary('...')                # b'...'
-six.ensure_str('...')                   # '...'
-six.ensure_text('...')                  # '...'
+```diff
+-six.text_type
++str
+-six.binary_type
++bytes
+-six.class_types
++(type,)
+-six.string_types
++(str,)
+-six.integer_types
++(int,)
+-six.unichr
++chr
+-six.iterbytes
++iter
+-six.print_(...)
++print(...)
+-six.exec_(c, g, l)
++exec(c, g, l)
+-six.advance_iterator(it)
++next(it)
+-six.next(it)
++next(it)
+-six.callable(x)
++callable(x)
+-six.moves.range(x)
++range(x)
+-six.moves.xrange(x)
++range(x)
+
+
+-from six import text_type
+-text_type
++str
+
+-@six.python_2_unicode_compatible
+ class C:
+     def __str__(self):
+         return u'C()'
+
+-class C(six.Iterator): pass
++class C: pass
+
+-class C(six.with_metaclass(M, B)): pass
++class C(B, metaclass=M): pass
+
+-@six.add_metaclass(M)
+-class C(B): pass
++class C(B, metaclass=M): pass
+
+-isinstance(..., six.class_types)
++isinstance(..., type)
+-issubclass(..., six.integer_types)
++issubclass(..., int)
+-isinstance(..., six.string_types)
++isinstance(..., str)
+
+-six.b('...')
++b'...'
+-six.u('...')
++'...'
+-six.byte2int(bs)
++bs[0]
+-six.indexbytes(bs, i)
++bs[i]
+-six.int2byte(i)
++bytes((i,))
+-six.iteritems(dct)
++dct.items()
+-six.iterkeys(dct)
++dct.keys()
+-six.itervalues(dct)
++dct.values()
+-next(six.iteritems(dct))
++next(iter(dct.items()))
+-next(six.iterkeys(dct))
++next(iter(dct.keys()))
+-next(six.itervalues(dct))
++next(iter(dct.values()))
+-six.viewitems(dct)
++dct.items()
+-six.viewkeys(dct)
++dct.keys()
+-six.viewvalues(dct)
++dct.values()
+-six.create_unbound_method(fn, cls)
++fn
+-six.get_unbound_function(meth)
++meth
+-six.get_method_function(meth)
++meth.__func__
+-six.get_method_self(meth)
++meth.__self__
+-six.get_function_closure(fn)
++fn.__closure__
+-six.get_function_code(fn)
++fn.__code__
+-six.get_function_defaults(fn)
++fn.__defaults__
+-six.get_function_globals(fn)
++fn.__globals__
+-six.raise_from(exc, exc_from)
++raise exc from exc_from
+-six.reraise(tp, exc, tb)
++raise exc.with_traceback(tb)
+-six.reraise(*sys.exc_info())
++raise
+-six.assertCountEqual(self, a1, a2)
++self.assertCountEqual(a1, a2)
+-six.assertRaisesRegex(self, e, r, fn)
++self.assertRaisesRegex(e, r, fn)
+-six.assertRegex(self, s, r)
++self.assertRegex(s, r)
+
+ # note: only for *literals*
+-six.ensure_binary('...')
++b'...'
+-six.ensure_str('...')
++'...'
+-six.ensure_text('...')
++'...'
 ```
 
 ### `open` alias
@@ -438,14 +545,21 @@
 Availability:
 - `--py3-plus` is passed on the commandline.
 
-```python
-open("foo", "U")                      # open("foo")
-open("foo", "Ur")                     # open("foo")
-open("foo", "Ub")                     # open("foo", "rb")
-open("foo", "rUb")                    # open("foo", "rb")
-open("foo", "r")                      # open("foo")
-open("foo", "rt")                     # open("foo")
-open("f", "r", encoding="UTF-8")      # open("f", encoding="UTF-8")
+```diff
+-open("foo", "U")
++open("foo")
+-open("foo", "Ur")
++open("foo")
+-open("foo", "Ub")
++open("foo", "rb")
+-open("foo", "rUb")
++open("foo", "rb")
+-open("foo", "r")
++open("foo")
+-open("foo", "rt")
++open("foo")
+-open("f", "r", encoding="UTF-8")
++open("f", encoding="UTF-8")
 ```
 
 
@@ -560,11 +674,17 @@
 Availability:
 - `--py36-plus` is passed on the commandline.
 
-```python
-'{foo} {bar}'.format(foo=foo, bar=bar)  # f'{foo} {bar}'
-'{} {}'.format(foo, bar)                # f'{foo} {bar}'
-'{} {}'.format(foo.bar, baz.womp)       # f'{foo.bar} {baz.womp}'
-'{} {}'.format(f(), g())                # f'{f()} {g()}'
+```diff
+-'{foo} {bar}'.format(foo=foo, bar=bar)
++f'{foo} {bar}'
+-'{} {}'.format(foo, bar)
++f'{foo} {bar}'
+-'{} {}'.format(foo.bar, baz.womp)
++f'{foo.bar} {baz.womp}'
+-'{} {}'.format(f(), g())
++f'{f()} {g()}'
+-'{x}'.format(**locals())
++f'{x}'
 ```
 
 _note_: `pyupgrade` is intentionally timid and will not create an f-string
@@ -638,6 +758,19 @@
 ```
 
 
+### remove unnecessary abspath
+
+Availability:
+- `--py39-plus` is passed on the commandline.
+
+```diff
+ from os.path import abspath
+
+-abspath(__file__)
++__file__
+```
+
+
 ### pep 604 typing rewrites
 
 Availability:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_data.py 
new/pyupgrade-2.31.0/pyupgrade/_data.py
--- old/pyupgrade-2.29.1/pyupgrade/_data.py     2021-11-16 02:13:55.000000000 
+0100
+++ new/pyupgrade-2.31.0/pyupgrade/_data.py     2022-01-01 01:43:09.000000000 
+0100
@@ -44,6 +44,7 @@
 
 RECORD_FROM_IMPORTS = frozenset((
     '__future__',
+    'os.path',
     'functools',
     'mmap',
     'select',
@@ -116,8 +117,7 @@
 
 
 def _import_plugins() -> None:
-    # https://github.com/python/mypy/issues/1422
-    plugins_path: str = _plugins.__path__  # type: ignore
+    plugins_path = _plugins.__path__
     mod_infos = pkgutil.walk_packages(plugins_path, f'{_plugins.__name__}.')
     for _, name, _ in mod_infos:
         __import__(name, fromlist=['_trash'])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_main.py 
new/pyupgrade-2.31.0/pyupgrade/_main.py
--- old/pyupgrade-2.29.1/pyupgrade/_main.py     2021-11-16 02:13:55.000000000 
+0100
+++ new/pyupgrade-2.31.0/pyupgrade/_main.py     2022-01-01 01:43:09.000000000 
+0100
@@ -694,9 +694,9 @@
     elif isinstance(node, ast.Attribute):
         return ''.join((_unparse(node.value), '.', node.attr))
     elif isinstance(node, ast.Subscript):
-        if sys.version_info >= (3, 9):  # pragma: no cover (py39+)
+        if sys.version_info >= (3, 9):  # pragma: >=3.9 cover
             node_slice: ast.expr = node.slice
-        elif isinstance(node.slice, ast.Index):  # pragma: no cover (<py39)
+        elif isinstance(node.slice, ast.Index):  # pragma: <3.9 cover
             node_slice = node.slice.value
         else:
             raise AssertionError(f'expected Slice: {ast.dump(node)}')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_plugins/abspath_file.py 
new/pyupgrade-2.31.0/pyupgrade/_plugins/abspath_file.py
--- old/pyupgrade-2.29.1/pyupgrade/_plugins/abspath_file.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_plugins/abspath_file.py     2022-01-01 
01:43:09.000000000 +0100
@@ -0,0 +1,53 @@
+import ast
+from typing import Iterable
+from typing import List
+from typing import Tuple
+
+from tokenize_rt import Offset
+from tokenize_rt import Token
+
+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 find_closing_bracket
+from pyupgrade._token_helpers import find_open_paren
+
+
+def _remove_abspath(i: int, tokens: List[Token]) -> None:
+    paren_start = find_open_paren(tokens, i + 1)
+    paren_end = find_closing_bracket(tokens, paren_start)
+    while i <= paren_start:
+        tokens[i] = Token('PLACEHOLDER', '')
+        i += 1
+    tokens[paren_end] = Token('PLACEHOLDER', '')
+
+
+@register(ast.Call)
+def visit_Call(
+        state: State,
+        node: ast.Call,
+        parent: ast.AST,
+) -> Iterable[Tuple[Offset, TokenFunc]]:
+    if (
+            state.settings.min_version >= (3, 9) and
+            (
+                (
+                    isinstance(node.func, ast.Name) and
+                    node.func.id == 'abspath' and
+                    node.func.id in state.from_imports['os.path']
+                ) or
+                (
+                    isinstance(node.func, ast.Attribute) and
+                    isinstance(node.func.value, ast.Attribute) and
+                    isinstance(node.func.value.value, ast.Name) and
+                    node.func.value.value.id == 'os' and
+                    node.func.value.attr == 'path' and
+                    node.func.attr == 'abspath'
+                )
+            ) and
+            len(node.args) == 1 and
+            isinstance(node.args[0], ast.Name) and
+            node.args[0].id == '__file__'
+    ):
+        yield ast_to_offset(node), _remove_abspath
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_plugins/format_locals.py 
new/pyupgrade-2.31.0/pyupgrade/_plugins/format_locals.py
--- old/pyupgrade-2.29.1/pyupgrade/_plugins/format_locals.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_plugins/format_locals.py    2022-01-01 
01:43:09.000000000 +0100
@@ -0,0 +1,49 @@
+import ast
+from typing import Iterable
+from typing import List
+from typing import Tuple
+
+from tokenize_rt import Offset
+from tokenize_rt import rfind_string_parts
+from tokenize_rt import Token
+
+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 find_closing_bracket
+from pyupgrade._token_helpers import find_open_paren
+from pyupgrade._token_helpers import find_token
+
+
+def _fix(i: int, tokens: List[Token]) -> None:
+    dot_pos = find_token(tokens, i, '.')
+    open_pos = find_open_paren(tokens, dot_pos)
+    close_pos = find_closing_bracket(tokens, open_pos)
+    for string_idx in rfind_string_parts(tokens, dot_pos - 1):
+        tok = tokens[string_idx]
+        tokens[string_idx] = tok._replace(src=f'f{tok.src}')
+    del tokens[dot_pos:close_pos + 1]
+
+
+@register(ast.Call)
+def visit_Call(
+        state: State,
+        node: ast.Call,
+        parent: ast.AST,
+) -> Iterable[Tuple[Offset, TokenFunc]]:
+    if (
+            state.settings.min_version >= (3, 6) and
+            isinstance(node.func, ast.Attribute) and
+            isinstance(node.func.value, ast.Str) and
+            node.func.attr == 'format' and
+            len(node.args) == 0 and
+            len(node.keywords) == 1 and
+            node.keywords[0].arg is None and
+            isinstance(node.keywords[0].value, ast.Call) and
+            isinstance(node.keywords[0].value.func, ast.Name) and
+            node.keywords[0].value.func.id == 'locals' and
+            len(node.keywords[0].value.args) == 0 and
+            len(node.keywords[0].value.keywords) == 0
+    ):
+        yield ast_to_offset(node), _fix
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_plugins/six_calls.py 
new/pyupgrade-2.31.0/pyupgrade/_plugins/six_calls.py
--- old/pyupgrade-2.29.1/pyupgrade/_plugins/six_calls.py        2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_plugins/six_calls.py        2022-01-01 
01:43:09.000000000 +0100
@@ -25,7 +25,7 @@
     ast.Await, ast.BinOp, ast.BoolOp, ast.Compare, ast.GeneratorExp, ast.IfExp,
     ast.Lambda, ast.UnaryOp,
 )
-if sys.version_info >= (3, 8):  # pragma: no cover (py38+)
+if sys.version_info >= (3, 8):  # pragma: >=3.8 cover
     _EXPR_NEEDS_PARENS += (ast.NamedExpr,)
 
 SIX_CALLS = {
@@ -172,13 +172,21 @@
                 ('reraise',),
             )
     ):
-        if len(node.args) == 2 and not has_starargs(node):
+        if (
+                len(node.args) == 2 and
+                not node.keywords and
+                not has_starargs(node)
+        ):
             func = functools.partial(
                 find_and_replace_call,
                 template=RERAISE_2_TMPL,
             )
             yield ast_to_offset(node), func
-        elif len(node.args) == 3 and not has_starargs(node):
+        elif (
+                len(node.args) == 3 and
+                not node.keywords and
+                not has_starargs(node)
+        ):
             func = functools.partial(
                 find_and_replace_call,
                 template=RERAISE_3_TMPL,
@@ -186,6 +194,7 @@
             yield ast_to_offset(node), func
         elif (
                 len(node.args) == 1 and
+                not node.keywords and
                 isinstance(node.args[0], ast.Starred) and
                 isinstance(node.args[0].value, ast.Call) and
                 is_name_attr(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_plugins/typing_pep563.py 
new/pyupgrade-2.31.0/pyupgrade/_plugins/typing_pep563.py
--- old/pyupgrade-2.29.1/pyupgrade/_plugins/typing_pep563.py    2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_plugins/typing_pep563.py    2022-01-01 
01:43:09.000000000 +0100
@@ -94,18 +94,15 @@
 def _process_subscript(node: ast.Subscript) -> Iterable[ast.AST]:
     name = _get_name(node.value)
     if name == 'Annotated':
-        if sys.version_info >= (3, 9):  # pragma: no cover (py39+)
-            node_slice: ast.expr = node.slice
-        elif isinstance(node.slice, ast.Index):  # pragma: no cover (<py39)
-            node_slice = node.slice.value
-        else:  # pragma: no cover (<py39)
-            pass  # unexpected slice type
+        if sys.version_info >= (3, 9):  # pragma: >=3.9 cover
+            node_slice = node.slice
+        elif isinstance(node.slice, ast.Index):  # pragma: <3.9 cover
+            node_slice: ast.AST = node.slice.value
+        else:  # pragma: <3.9 cover
+            node_slice = node.slice
 
-        if isinstance(node_slice, ast.Tuple):
-            if node_slice.elts:
-                yield node_slice.elts[0]
-        else:
-            raise AssertionError(f'expected ast.Tuple: {ast.dump(node_slice)}')
+        if isinstance(node_slice, ast.Tuple) and node_slice.elts:
+            yield node_slice.elts[0]
     elif name != 'Literal':
         yield node.slice
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_plugins/typing_pep604.py 
new/pyupgrade-2.31.0/pyupgrade/_plugins/typing_pep604.py
--- old/pyupgrade-2.29.1/pyupgrade/_plugins/typing_pep604.py    2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_plugins/typing_pep604.py    2022-01-01 
01:43:09.000000000 +0100
@@ -158,12 +158,15 @@
     if is_name_attr(node.value, state.from_imports, 'typing', ('Optional',)):
         yield ast_to_offset(node), _fix_optional
     elif is_name_attr(node.value, state.from_imports, 'typing', ('Union',)):
-        if sys.version_info >= (3, 9):  # pragma: no cover (py39+)
-            node_slice: ast.expr = node.slice
-        elif isinstance(node.slice, ast.Index):  # pragma: no cover (<py39)
-            node_slice = node.slice.value
-        else:  # pragma: no cover (<py39)
-            return  # unexpected slice type
+        if sys.version_info >= (3, 9):  # pragma: >=3.9 cover
+            node_slice = node.slice
+        elif isinstance(node.slice, ast.Index):  # pragma: <3.9 cover
+            node_slice: ast.AST = node.slice.value
+        else:  # pragma: <3.9 cover
+            node_slice = node.slice  # unexpected slice type
+
+        if isinstance(node_slice, ast.Slice):  # not a valid annotation
+            return
 
         if isinstance(node_slice, ast.Tuple):
             if node_slice.elts:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_string_helpers.py 
new/pyupgrade-2.31.0/pyupgrade/_string_helpers.py
--- old/pyupgrade-2.29.1/pyupgrade/_string_helpers.py   2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_string_helpers.py   2022-01-01 
01:43:09.000000000 +0100
@@ -3,9 +3,9 @@
 import string
 import sys
 
-if sys.version_info >= (3, 7):  # pragma: no cover (py37+)
+if sys.version_info >= (3, 7):  # pragma: >=3.7 cover
     is_ascii = str.isascii
-else:  # pragma: no cover (<py37)
+else:  # pragma: <3.7 cover
     def is_ascii(s: str) -> bool:
         return all(c in string.printable for c in s)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/pyupgrade/_token_helpers.py 
new/pyupgrade-2.31.0/pyupgrade/_token_helpers.py
--- old/pyupgrade-2.29.1/pyupgrade/_token_helpers.py    2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/pyupgrade/_token_helpers.py    2022-01-01 
01:43:09.000000000 +0100
@@ -65,14 +65,14 @@
     return i
 
 
-if sys.version_info >= (3, 8):  # pragma: no cover (py38+)
+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: no cover (<py38)
+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):
@@ -502,12 +502,12 @@
 
 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: no cover (py38+)
+    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: no cover (<py38)
+    else:  # pragma: >=3.8 cover
         return i
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/requirements-dev.txt 
new/pyupgrade-2.31.0/requirements-dev.txt
--- old/pyupgrade-2.29.1/requirements-dev.txt   2021-11-16 02:13:55.000000000 
+0100
+++ new/pyupgrade-2.31.0/requirements-dev.txt   2022-01-01 01:43:09.000000000 
+0100
@@ -1,3 +1,3 @@
-covdefaults
+covdefaults>=2.1.0
 coverage
 pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/setup.cfg 
new/pyupgrade-2.31.0/setup.cfg
--- old/pyupgrade-2.29.1/setup.cfg      2021-11-16 02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/setup.cfg      2022-01-01 01:43:09.000000000 +0100
@@ -1,6 +1,6 @@
 [metadata]
 name = pyupgrade
-version = 2.29.1
+version = 2.31.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-2.29.1/tests/features/abspath_file_test.py 
new/pyupgrade-2.31.0/tests/features/abspath_file_test.py
--- old/pyupgrade-2.29.1/tests/features/abspath_file_test.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/abspath_file_test.py    2022-01-01 
01:43:09.000000000 +0100
@@ -0,0 +1,52 @@
+import pytest
+
+from pyupgrade._data import Settings
+from pyupgrade._main import _fix_plugins
+
+
+@pytest.mark.parametrize(
+    ('s', 'expected'),
+    (
+        pytest.param(
+            'from os.path import abspath\n'
+            'abspath(__file__)',
+            'from os.path import abspath\n'
+            '__file__',
+            id='abspath',
+        ),
+        pytest.param(
+            'import os\n'
+            'os.path.abspath(__file__)',
+            'import os\n'
+            '__file__',
+            id='os.path.abspath',
+        ),
+    ),
+)
+def test_fix_abspath_file(s, expected):
+    ret = _fix_plugins(s, settings=Settings(min_version=(3, 9)))
+    assert ret == expected
+
+
+@pytest.mark.parametrize(
+    's, min_version',
+    (
+        pytest.param(
+            'abspath(__file__)',
+            (3, 8),
+            id='Not Python3.9+',
+        ),
+        pytest.param(
+            'os.path.abspath(file)',
+            (3, 9),
+            id='Abspath of not-__file__',
+        ),
+        pytest.param(
+            'os.path.abspath(file, foo)',
+            (3, 9),
+            id='Garbage (don\'t rewrite)',
+        ),
+    ),
+)
+def test_fix_abspath_file_noop(s, min_version):
+    assert _fix_plugins(s, settings=Settings(min_version=min_version)) == s
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pyupgrade-2.29.1/tests/features/format_locals_test.py 
new/pyupgrade-2.31.0/tests/features/format_locals_test.py
--- old/pyupgrade-2.29.1/tests/features/format_locals_test.py   1970-01-01 
01:00:00.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/format_locals_test.py   2022-01-01 
01:43:09.000000000 +0100
@@ -0,0 +1,53 @@
+import pytest
+
+from pyupgrade._data import Settings
+from pyupgrade._main import _fix_plugins
+
+
+@pytest.mark.parametrize(
+    ('s', 'version'),
+    (
+        pytest.param(
+            '"{x}".format(**locals())',
+            (3,),
+            id='not 3.6+',
+        ),
+        pytest.param(
+            '"{x} {y}".format(x, **locals())',
+            (3, 6),
+            id='mixed locals() and params',
+        ),
+    ),
+)
+def test_fix_format_locals_noop(s, version):
+    assert _fix_plugins(s, settings=Settings(min_version=version)) == s
+
+
+@pytest.mark.parametrize(
+    ('s', 'expected'),
+    (
+        pytest.param(
+            '"{x}".format(**locals())',
+            'f"{x}"',
+            id='normal case',
+        ),
+        pytest.param(
+            '"{x}" "{y}".format(**locals())',
+            'f"{x}" f"{y}"',
+            id='joined strings',
+        ),
+        pytest.param(
+            '(\n'
+            '    "{x}"\n'
+            '    "{y}"\n'
+            ').format(**locals())\n',
+            '(\n'
+            '    f"{x}"\n'
+            '    f"{y}"\n'
+            ')\n',
+            id='joined strings with parens',
+        ),
+    ),
+)
+def test_fix_format_locals(s, expected):
+    assert _fix_plugins(s, settings=Settings(min_version=(3, 6))) == expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/tests/features/fstrings_test.py 
new/pyupgrade-2.31.0/tests/features/fstrings_test.py
--- old/pyupgrade-2.29.1/tests/features/fstrings_test.py        2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/fstrings_test.py        2022-01-01 
01:43:09.000000000 +0100
@@ -61,8 +61,6 @@
             r'f"\N{snowman} {a}"',
             id='named escape sequences',
         ),
-        # TODO: poor man's f-strings?
-        # '"{foo}".format(**locals())'
     ),
 )
 def test_fix_fstrings(s, expected):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pyupgrade-2.29.1/tests/features/six_test.py 
new/pyupgrade-2.31.0/tests/features/six_test.py
--- old/pyupgrade-2.29.1/tests/features/six_test.py     2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/six_test.py     2022-01-01 
01:43:09.000000000 +0100
@@ -24,6 +24,7 @@
         'class C(six.with_metaclass(Meta, B), D): pass',
         # cannot determine args to rewrite them
         'six.reraise(*err)', 'six.u(*a)',
+        'six.reraise(a, b, tb=c)',
         'class C(six.with_metaclass(*a)): pass',
         '@six.add_metaclass(*a)\n'
         'class C: pass\n',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pyupgrade-2.29.1/tests/features/typing_pep563_test.py 
new/pyupgrade-2.31.0/tests/features/typing_pep563_test.py
--- old/pyupgrade-2.29.1/tests/features/typing_pep563_test.py   2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/typing_pep563_test.py   2022-01-01 
01:43:09.000000000 +0100
@@ -57,6 +57,12 @@
             (3,),
             id='Kwonly, untyped',
         ),
+        pytest.param(
+            'from __future__ import annotations\n'
+            'x: Annotated[1:2] = ...\n',
+            (3,),
+            id='Annotated with invalid slice',
+        ),
     ),
 )
 def test_fix_typing_pep563_noop(s, version):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pyupgrade-2.29.1/tests/features/typing_pep604_test.py 
new/pyupgrade-2.31.0/tests/features/typing_pep604_test.py
--- old/pyupgrade-2.29.1/tests/features/typing_pep604_test.py   2021-11-16 
02:13:55.000000000 +0100
+++ new/pyupgrade-2.31.0/tests/features/typing_pep604_test.py   2022-01-01 
01:43:09.000000000 +0100
@@ -54,6 +54,12 @@
             (3, 10),
             id='3.10+ Union of forward reference',
         ),
+        pytest.param(
+            'from typing import Union\n'
+            'def f() -> Union[1:2]: ...\n',
+            (3, 10),
+            id='invalid Union slicing',
+        ),
     ),
 )
 def test_fix_pep604_types_noop(s, version):

Reply via email to