Skip to main content

A tool to automatically upgrade syntax for newer versions.

Project description

Build Status Azure DevOps coverage

pyupgrade

A tool (and pre-commit hook) to automatically upgrade syntax for newer versions of the language.

Installation

pip install pyupgrade

As a pre-commit hook

See pre-commit for instructions

Sample .pre-commit-config.yaml:

-   repo: https://github.com/asottile/pyupgrade
    rev: v1.21.0
    hooks:
    -   id: pyupgrade

Implemented features

Set literals

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

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}

Python2.7+ Format Specifiers

'{0} {1}'.format(1, 2)    # '{} {}'.format(1, 2)
'{0}' '{1}'.format(1, 2)  # '{}' '{}'.format(1, 2)

printf-style string formatting

Availability:

  • Unless --keep-percent-format is passed.
'%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

Availability:

  • File imports from __future__ import unicode_literals
  • --py3-plus is passed on the commandline.
u'foo'      # 'foo'
u"foo"      # 'foo'
u'''foo'''  # '''foo'''

Invalid escape sequences

# 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`
# but in python3.x, that's our friend ☃

is / is not comparison to constant literals

In python3.8+, comparison to literals becomes a SyntaxWarning as the success of those comparisons is implementation specific (due to common object caching).

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

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

'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

5L                            # 5
5l                            # 5
123456789123456789123456789L  # 123456789123456789123456789

Octal literals

0755  # 0o755
05    # 5

extraneous parens in print(...)

A fix for python-modernize/python-modernize#178

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")

super() calls

Availability:

  • --py3-plus is passed on the commandline.
class C(Base):
    def f(self):
        super(C, self).f()   # super().f()

"new style" classes

Availability:

  • --py3-plus is passed on the commandline.
class C(object): pass     # class C: pass
class C(B, object): pass  # class C(B): pass

forced str("native") literals

Availability:

  • --py3-plus is passed on the commandline.
str("foo")  # "foo"

.encode("utf-8")

Availability:

  • --py3-plus is passed on the commandline.
"foo".encode("utf-8")  # "foo".encode()

yield => yield from

Availability:

  • --py3-plus is passed on the commandline.
def f():
    for x in y:       # yield from y
        yield x

    for a, b in c:    # yield from c
        yield (a, b)

if PY2 blocks

Availability:

  • --py3-plus is passed on the commandline.
# input
if six.PY2:      # also understands `six.PY3` and `not` and `sys.version_info`
    print('py2')
else:
    print('py3')
# output
print('py3')

remove six compatibility code

Availability:

  • --py3-plus is passed on the commandline.
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)

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.iteritems(dct)                      # dct.items()
six.iterkeys(dct)                       # dct.keys()
six.itervalues(dct)                     # 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_method(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.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)

OSError aliases

Availability:

  • --py3-plus is passed on the commandline.
# input
x = EnvironmentError('boom')        # also understands IOError and WindowsError
raise EnvironmentError('boom')
# output
x = OSError('boom')
raise OSError('boom')

f-strings

Availability:

  • --py36-plus is passed on the commandline.
'{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}'

note: pyupgrade is intentionally timid and will not create an f-string if it would make the expression longer or if the substitution parameters are anything but simple names or dotted names (as this can decrease readability).

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyupgrade-1.21.0.tar.gz (20.5 kB view details)

Uploaded Source

Built Distribution

pyupgrade-1.21.0-py2.py3-none-any.whl (20.1 kB view details)

Uploaded Python 2 Python 3

File details

Details for the file pyupgrade-1.21.0.tar.gz.

File metadata

  • Download URL: pyupgrade-1.21.0.tar.gz
  • Upload date:
  • Size: 20.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.8.0 tqdm/4.29.1 CPython/3.7.2

File hashes

Hashes for pyupgrade-1.21.0.tar.gz
Algorithm Hash digest
SHA256 868a92e8bd6ed6ef8a3ace3a7e08e9d59cbaff958e2c2d20efbe117cf1f52175
MD5 5b75b3ee421c112dfe3fe5c2ff65e79a
BLAKE2b-256 764269629274730ef0dea3751ee16f250b0d20d072657f3ba445290fc076ddf6

See more details on using hashes here.

Provenance

File details

Details for the file pyupgrade-1.21.0-py2.py3-none-any.whl.

File metadata

  • Download URL: pyupgrade-1.21.0-py2.py3-none-any.whl
  • Upload date:
  • Size: 20.1 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.8.0 tqdm/4.29.1 CPython/3.7.2

File hashes

Hashes for pyupgrade-1.21.0-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 bec54923c4e2d13a73e7a70828d3c5cb1562e72b3a622959309ec93ebafb0f88
MD5 2aa731783e29c78a2117918d70b5480a
BLAKE2b-256 614eb64dedcccd51f66ab3e065d2cc07fc1a5491a5ecf72a48c1c8019c5cc617

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page