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