1[![Build Status](https://dev.azure.com/asottile/asottile/_apis/build/status/asottile.pyupgrade?branchName=master)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=2&branchName=master)
2[![Azure DevOps coverage](https://img.shields.io/azure-devops/coverage/asottile/asottile/2/master.svg)](https://dev.azure.com/asottile/asottile/_build/latest?definitionId=2&branchName=master)
3
4pyupgrade
5=========
6
7A tool (and pre-commit hook) to automatically upgrade syntax for newer
8versions of the language.
9
10## Installation
11
12`pip install pyupgrade`
13
14## As a pre-commit hook
15
16See [pre-commit](https://github.com/pre-commit/pre-commit) for instructions
17
18Sample `.pre-commit-config.yaml`:
19
20```yaml
21-   repo: https://github.com/asottile/pyupgrade
22    rev: v1.27.0
23    hooks:
24    -   id: pyupgrade
25```
26
27## Implemented features
28
29### Set literals
30
31```python
32set(())              # set()
33set([])              # set()
34set((1,))            # {1}
35set((1, 2))          # {1, 2}
36set([1, 2])          # {1, 2}
37set(x for x in y)    # {x for x in y}
38set([x for x in y])  # {x for x in y}
39```
40
41### Dictionary comprehensions
42
43```python
44dict((a, b) for a, b in y)    # {a: b for a, b in y}
45dict([(a, b) for a, b in y])  # {a: b for a, b in y}
46```
47
48### Python2.7+ Format Specifiers
49
50```python
51'{0} {1}'.format(1, 2)    # '{} {}'.format(1, 2)
52'{0}' '{1}'.format(1, 2)  # '{}' '{}'.format(1, 2)
53```
54
55### printf-style string formatting
56
57Availability:
58- Unless `--keep-percent-format` is passed.
59
60```python
61'%s %s' % (a, b)                  # '{} {}'.format(a, b)
62'%r %2f' % (a, b)                 # '{!r} {:2f}'.format(a, b)
63'%(a)s %(b)s' % {'a': 1, 'b': 2}  # '{a} {b}'.format(a=1, b=2)
64```
65
66### Unicode literals
67
68Availability:
69- File imports `from __future__ import unicode_literals`
70- `--py3-plus` is passed on the commandline.
71
72```python
73u'foo'      # 'foo'
74u"foo"      # 'foo'
75u'''foo'''  # '''foo'''
76```
77
78### Invalid escape sequences
79
80```python
81# strings with only invalid sequences become raw strings
82'\d'    # r'\d'
83# strings with mixed valid / invalid sequences get escaped
84'\n\d'  # '\n\\d'
85# `ur` is not a valid string prefix in python3
86u'\d'   # u'\\d'
87
88# this fixes a syntax error in python3.3+
89'\N'    # r'\N'
90
91# note: pyupgrade is timid in one case (that's usually a mistake)
92# in python2.x `'\u2603'` is the same as `'\\u2603'` without `unicode_literals`
93# but in python3.x, that's our friend ☃
94```
95
96### `is` / `is not` comparison to constant literals
97
98In python3.8+, comparison to literals becomes a `SyntaxWarning` as the success
99of those comparisons is implementation specific (due to common object caching).
100
101```python
102x is 5      # x == 5
103x is not 5  # x != 5
104x is 'foo'  # x == foo
105```
106
107### `ur` string literals
108
109`ur'...'` literals are not valid in python 3.x
110
111```python
112ur'foo'         # u'foo'
113ur'\s'          # u'\\s'
114# unicode escapes are left alone
115ur'\u2603'      # u'\u2603'
116ur'\U0001f643'  # u'\U0001f643'
117```
118
119### `.encode()` to bytes literals
120
121```python
122'foo'.encode()           # b'foo'
123'foo'.encode('ascii')    # b'foo'
124'foo'.encode('utf-8')    # b'foo'
125u'foo'.encode()          # b'foo'
126'\xa0'.encode('latin1')  # b'\xa0'
127```
128
129### Long literals
130
131```python
1325L                            # 5
1335l                            # 5
134123456789123456789123456789L  # 123456789123456789123456789
135```
136
137### Octal literals
138
139```
1400755  # 0o755
14105    # 5
142```
143
144### extraneous parens in `print(...)`
145
146A fix for [python-modernize/python-modernize#178]
147
148```python
149print(())                       # ok: printing an empty tuple
150print((1,))                     # ok: printing a tuple
151sum((i for i in range(3)), [])  # ok: parenthesized generator argument
152print(("foo"))                  # print("foo")
153```
154
155[python-modernize/python-modernize#178]: https://github.com/python-modernize/python-modernize/issues/178
156
157### `super()` calls
158
159Availability:
160- `--py3-plus` is passed on the commandline.
161
162```python
163class C(Base):
164    def f(self):
165        super(C, self).f()   # super().f()
166```
167
168### "new style" classes
169
170Availability:
171- `--py3-plus` is passed on the commandline.
172
173```python
174class C(object): pass     # class C: pass
175class C(B, object): pass  # class C(B): pass
176```
177
178### forced `str("native")` literals
179
180Availability:
181- `--py3-plus` is passed on the commandline.
182
183```python
184str()       # "''"
185str("foo")  # "foo"
186```
187
188### `.encode("utf-8")`
189
190Availability:
191- `--py3-plus` is passed on the commandline.
192
193```python
194"foo".encode("utf-8")  # "foo".encode()
195```
196
197### `# coding: ...` comment
198
199Availability:
200- `--py3-plus` is passed on the commandline.
201
202as of [PEP 3120], the default encoding for python source is UTF-8
203
204```diff
205-# coding: utf-8
206 x = 1
207```
208
209[PEP 3120]: https://www.python.org/dev/peps/pep-3120/
210
211### `__future__` import removal
212
213Availability:
214- by default removes `nested_scopes`, `generators`, `with_statement`
215- `--py3-plus` will also remove `absolute_import` / `division` /
216  `print_function` / `unicode_literals`
217- `--py37-plus` will also remove `generator_stop`
218
219```diff
220-from __future__ import with_statement
221```
222
223### Remove unnecessary py3-compat imports
224
225Availability:
226- `--py3-plus` is passed on the commandline.
227
228```diff
229-from io import open
230-from six.moves import map
231-from builtins import object  # python-future
232```
233
234### `yield` => `yield from`
235
236Availability:
237- `--py3-plus` is passed on the commandline.
238
239```python
240def f():
241    for x in y:       # yield from y
242        yield x
243
244    for a, b in c:    # yield from c
245        yield (a, b)
246```
247
248### `if PY2` blocks
249
250Availability:
251- `--py3-plus` is passed on the commandline.
252
253```python
254# input
255if six.PY2:      # also understands `six.PY3` and `not` and `sys.version_info`
256    print('py2')
257else:
258    print('py3')
259# output
260print('py3')
261```
262
263### remove `six` compatibility code
264
265Availability:
266- `--py3-plus` is passed on the commandline.
267
268```python
269six.text_type             # str
270six.binary_type           # bytes
271six.class_types           # (type,)
272six.string_types          # (str,)
273six.integer_types         # (int,)
274six.unichr                # chr
275six.iterbytes             # iter
276six.print_(...)           # print(...)
277six.exec_(c, g, l)        # exec(c, g, l)
278six.advance_iterator(it)  # next(it)
279six.next(it)              # next(it)
280six.callable(x)           # callable(x)
281
282from six import text_type
283text_type                 # str
284
285@six.python_2_unicode_compatible  # decorator is removed
286class C:
287    def __str__(self):
288        return u'C()'
289
290class C(six.Iterator): pass              # class C: pass
291
292class C(six.with_metaclass(M, B)): pass  # class C(B, metaclass=M): pass
293
294@six.add_metaclass(M)   # class C(B, metaclass=M): pass
295class C(B): pass
296
297isinstance(..., six.class_types)    # isinstance(..., type)
298issubclass(..., six.integer_types)  # issubclass(..., int)
299isinstance(..., six.string_types)   # isinstance(..., str)
300
301six.b('...')                            # b'...'
302six.u('...')                            # '...'
303six.byte2int(bs)                        # bs[0]
304six.indexbytes(bs, i)                   # bs[i]
305six.int2byte(i)                         # bytes((i,))
306six.iteritems(dct)                      # dct.items()
307six.iterkeys(dct)                       # dct.keys()
308six.itervalues(dct)                     # dct.values()
309next(six.iteritems(dct))                # next(iter(dct.items()))
310next(six.iterkeys(dct))                 # next(iter(dct.keys()))
311next(six.itervalues(dct))               # next(iter(dct.values()))
312six.viewitems(dct)                      # dct.items()
313six.viewkeys(dct)                       # dct.keys()
314six.viewvalues(dct)                     # dct.values()
315six.create_unbound_method(fn, cls)      # fn
316six.get_unbound_function(meth)          # meth
317six.get_method_function(meth)           # meth.__func__
318six.get_method_self(meth)               # meth.__self__
319six.get_function_closure(fn)            # fn.__closure__
320six.get_function_code(fn)               # fn.__code__
321six.get_function_defaults(fn)           # fn.__defaults__
322six.get_function_globals(fn)            # fn.__globals__
323six.assertCountEqual(self, a1, a2)      # self.assertCountEqual(a1, a2)
324six.assertRaisesRegex(self, e, r, fn)   # self.assertRaisesRegex(e, r, fn)
325six.assertRegex(self, s, r)             # self.assertRegex(s, r)
326
327# note: only for *literals*
328six.ensure_binary('...')                # b'...'
329six.ensure_str('...')                   # '...'
330six.ensure_text('...')                  # '...'
331```
332
333### `open` alias
334
335Availability:
336- `--py3-plus` is passed on the commandline.
337
338```python
339# input
340with io.open('f.txt') as f:
341    pass
342# output
343with open('f.txt') as f:
344    pass
345```
346
347### `OSError` aliases
348
349Availability:
350- `--py3-plus` is passed on the commandline.
351
352```python
353# input
354
355# also understands:
356# - IOError
357# - WindowsError
358# - mmap.error and uses of `from mmap import error`
359# - select.error and uses of `from select import error`
360# - socket.error and uses of `from socket import error`
361
362try:
363    raise EnvironmentError('boom')
364except EnvironmentError:
365    raise
366# output
367try:
368    raise OSError('boom')
369except OSError:
370    raise
371```
372
373### f-strings
374
375Availability:
376- `--py36-plus` is passed on the commandline.
377
378```python
379'{foo} {bar}'.format(foo=foo, bar=bar)  # f'{foo} {bar}'
380'{} {}'.format(foo, bar)                # f'{foo} {bar}'
381'{} {}'.format(foo.bar, baz.womp)       # f'{foo.bar} {baz.womp}'
382'{} {}'.format(f(), g())                # f'{f()} {g()}'
383```
384
385_note_: `pyupgrade` is intentionally timid and will not create an f-string
386if it would make the expression longer or if the substitution parameters are
387anything but simple names or dotted names (as this can decrease readability).
388