pyupgrade


Namepyupgrade JSON
Version 3.15.2 PyPI version JSON
download
home_pagehttps://github.com/asottile/pyupgrade
SummaryA tool to automatically upgrade syntax for newer versions.
upload_time2024-03-24 17:08:02
maintainerNone
docs_urlNone
authorAnthony Sottile
requires_python>=3.8.1
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![build status](https://github.com/asottile/pyupgrade/actions/workflows/main.yml/badge.svg)](https://github.com/asottile/pyupgrade/actions/workflows/main.yml)
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/asottile/pyupgrade/main.svg)](https://results.pre-commit.ci/latest/github/asottile/pyupgrade/main)

pyupgrade
=========

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

## Installation

```bash
pip install pyupgrade
```

## As a pre-commit hook

See [pre-commit](https://github.com/pre-commit/pre-commit) for instructions

Sample `.pre-commit-config.yaml`:

```yaml
-   repo: https://github.com/asottile/pyupgrade
    rev: v3.15.2
    hooks:
    -   id: pyupgrade
```

## Implemented features

### Set literals

```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

```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}
```

### Replace unnecessary lambdas in `collections.defaultdict` calls

```diff
-defaultdict(lambda: [])
+defaultdict(list)
-defaultdict(lambda: list())
+defaultdict(list)
-defaultdict(lambda: {})
+defaultdict(dict)
-defaultdict(lambda: dict())
+defaultdict(dict)
-defaultdict(lambda: ())
+defaultdict(tuple)
-defaultdict(lambda: tuple())
+defaultdict(tuple)
-defaultdict(lambda: set())
+defaultdict(set)
-defaultdict(lambda: 0)
+defaultdict(int)
-defaultdict(lambda: 0.0)
+defaultdict(float)
-defaultdict(lambda: 0j)
+defaultdict(complex)
-defaultdict(lambda: '')
+defaultdict(str)
```

### Format Specifiers

```diff
-'{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.

```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

```diff
-u'foo'
+'foo'
-u"foo"
+'foo'
-u'''foo'''
+'''foo'''
```

### Invalid escape sequences

```diff
 # strings with only invalid sequences become raw strings
-'\d'
+r'\d'
 # strings with mixed valid / invalid sequences get escaped
-'\n\d'
+'\n\\d'
-u'\d'
+r'\d'
 # this fixes a syntax error in python3.3+
-'\N'
+r'\N'
```

### `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).

```diff
-x is 5
+x == 5
-x is not 5
+x != 5
-x is 'foo'
+x == 'foo'
```

### `.encode()` to bytes literals

```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'
```

### extraneous parens in `print(...)`

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

```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

### constant fold `isinstance` / `issubclass` / `except`

```diff
-isinstance(x, (int, int))
+isinstance(x, int)

-issubclass(y, (str, str))
+issubclass(y, str)

 try:
     raises()
-except (Error1, Error1, Error2):
+except (Error1, Error2):
     pass
```

### unittest deprecated aliases

Rewrites [deprecated unittest method aliases](https://docs.python.org/3/library/unittest.html#deprecated-aliases) to their non-deprecated forms.

```diff
 from unittest import TestCase


 class MyTests(TestCase):
     def test_something(self):
-        self.failUnlessEqual(1, 1)
+        self.assertEqual(1, 1)
-        self.assertEquals(1, 1)
+        self.assertEqual(1, 1)
```

### `super()` calls

```diff
 class C(Base):
     def f(self):
-        super(C, self).f()
+        super().f()
```

### "new style" classes

#### rewrites class declaration

```diff
-class C(object): pass
+class C: pass
-class C(B, object): pass
+class C(B): pass
```

#### removes `__metaclass__ = type` declaration

```diff
 class C:
-    __metaclass__ = type
```

### forced `str("native")` literals

```diff
-str()
+''
-str("foo")
+"foo"
```

### `.encode("utf-8")`

```diff
-"foo".encode("utf-8")
+"foo".encode()
```

### `# coding: ...` comment

as of [PEP 3120], the default encoding for python source is UTF-8

```diff
-# coding: utf-8
 x = 1
```

[PEP 3120]: https://www.python.org/dev/peps/pep-3120/

### `__future__` import removal

Availability:
- by default removes `nested_scopes`, `generators`, `with_statement`,
  `absolute_import`, `division`, `print_function`, `unicode_literals`
- `--py37-plus` will also remove `generator_stop`

```diff
-from __future__ import with_statement
```

### Remove unnecessary py3-compat imports

```diff
-from io import open
-from six.moves import map
-from builtins import object  # python-future
```

### import replacements

Availability:
- `--py36-plus` (and others) will replace imports

see also [reorder-python-imports](https://github.com/asottile/reorder_python_imports#removing--rewriting-obsolete-six-imports)

some examples:

```diff
-from collections import deque, Mapping
+from collections import deque
+from collections.abc import Mapping
```

```diff
-from typing import Sequence
+from collections.abc import Sequence
```

```diff
-from typing_extensions import Concatenate
+from typing import Concatenate
```

### rewrite `mock` imports

Availability:
- [Unless `--keep-mock` is passed on the commandline](https://github.com/asottile/pyupgrade/issues/314).

```diff
-from mock import patch
+from unittest.mock import patch
```

### `yield` => `yield from`

```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

```diff
 import sys
-if sys.version_info < (3,):  # also understands `six.PY2` (and `not`), `six.PY3` (and `not`)
-    print('py2')
-else:
-    print('py3')
+print('py3')
```

Availability:
- `--py36-plus` will remove Python <= 3.5 only blocks
- `--py37-plus` will remove Python <= 3.6 only blocks
- so on and so forth

```diff
 # using --py36-plus for this example

 import sys
-if sys.version_info < (3, 6):
-    print('py3.5')
-else:
-    print('py3.6+')
+print('py3.6+')

-if sys.version_info <= (3, 5):
-    print('py3.5')
-else:
-    print('py3.6+')
+print('py3.6+')

-if sys.version_info >= (3, 6):
-    print('py3.6+')
-else:
-    print('py3.5')
+print('py3.6+')
```

Note that `if` blocks without an `else` will not be rewritten as it could introduce a syntax error.

### remove `six` compatibility code

```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

```diff
-with io.open('f.txt') as f:
+with open('f.txt') as f:
     ...
```


### redundant `open` modes

```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")
-open("f", "wt")
+open("f", "w")
```


### `OSError` aliases

```diff
 # also understands:
 # - IOError
 # - WindowsError
 # - mmap.error and uses of `from mmap import error`
 # - select.error and uses of `from select import error`
 # - socket.error and uses of `from socket import error`

 def throw():
-    raise EnvironmentError('boom')
+    raise OSError('boom')

 def catch():
     try:
         throw()
-    except EnvironmentError:
+    except OSError:
         handle_error()
```

### `TimeoutError` aliases

Availability:
- `--py310-plus` for `socket.timeout`
- `--py311-plus` for `asyncio.TimeoutError`

```diff

 def throw(a):
     if a:
-        raise asyncio.TimeoutError('boom')
+        raise TimeoutError('boom')
     else:
-        raise socket.timeout('boom')
+        raise TimeoutError('boom')

 def catch(a):
     try:
         throw(a)
-    except (asyncio.TimeoutError, socket.timeout):
+    except TimeoutError:
         handle_error()
```

### `typing.Text` str alias

```diff
-def f(x: Text) -> None:
+def f(x: str) -> None:
     ...
```


### Unpacking list comprehensions

```diff
-foo, bar, baz = [fn(x) for x in items]
+foo, bar, baz = (fn(x) for x in items)
```


### Rewrite `xml.etree.cElementTree` to `xml.etree.ElementTree`

```diff
-import xml.etree.cElementTree as ET
+import xml.etree.ElementTree as ET
-from xml.etree.cElementTree import XML
+from xml.etree.ElementTree import XML
```


### Rewrite `type` of primitive

```diff
-type('')
+str
-type(b'')
+bytes
-type(0)
+int
-type(0.)
+float
```

### `typing.NamedTuple` / `typing.TypedDict` py36+ syntax

Availability:
- `--py36-plus` is passed on the commandline.

```diff
-NT = typing.NamedTuple('NT', [('a', int), ('b', Tuple[str, ...])])
+class NT(typing.NamedTuple):
+    a: int
+    b: Tuple[str, ...]

-D1 = typing.TypedDict('D1', a=int, b=str)
+class D1(typing.TypedDict):
+    a: int
+    b: str

-D2 = typing.TypedDict('D2', {'a': int, 'b': str})
+class D2(typing.TypedDict):
+    a: int
+    b: str
```

### f-strings

Availability:
- `--py36-plus` is passed on the commandline.

```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
if it would make the expression longer or if the substitution parameters are
sufficiently complicated (as this can decrease readability).


### `subprocess.run`: replace `universal_newlines` with `text`

Availability:
- `--py37-plus` is passed on the commandline.

```diff
-output = subprocess.run(['foo'], universal_newlines=True)
+output = subprocess.run(['foo'], text=True)
```


### `subprocess.run`: replace `stdout=subprocess.PIPE, stderr=subprocess.PIPE` with `capture_output=True`

Availability:
- `--py37-plus` is passed on the commandline.

```diff
-output = subprocess.run(['foo'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+output = subprocess.run(['foo'], capture_output=True)
```


### remove parentheses from `@functools.lru_cache()`

Availability:
- `--py38-plus` is passed on the commandline.

```diff
 import functools

-@functools.lru_cache()
+@functools.lru_cache
 def expensive():
     ...
```

### shlex.join

Availability:
- `--py38-plus` is passed on the commandline.

```diff
-' '.join(shlex.quote(arg) for arg in cmd)
+shlex.join(cmd)
```

### replace `@functools.lru_cache(maxsize=None)` with shorthand

Availability:
- `--py39-plus` is passed on the commandline.

```diff
 import functools

-@functools.lru_cache(maxsize=None)
+@functools.cache
 def expensive():
     ...
```


### pep 585 typing rewrites

Availability:
- File imports `from __future__ import annotations`
    - Unless `--keep-runtime-typing` is passed on the commandline.
- `--py39-plus` is passed on the commandline.

```diff
-def f(x: List[str]) -> None:
+def f(x: list[str]) -> None:
     ...
```


### pep 604 typing rewrites

Availability:
- File imports `from __future__ import annotations`
    - Unless `--keep-runtime-typing` is passed on the commandline.
- `--py310-plus` is passed on the commandline.

```diff
-def f() -> Optional[str]:
+def f() -> str | None:
     ...
```

```diff
-def f() -> Union[int, str]:
+def f() -> int | str:
     ...
```


### remove quoted annotations

Availability:
- File imports `from __future__ import annotations`

```diff
-def f(x: 'queue.Queue[int]') -> C:
+def f(x: queue.Queue[int]) -> C:
```


### use `datetime.UTC` alias

Availability:
- `--py311-plus` is passed on the commandline.

```diff
 import datetime

-datetime.timezone.utc
+datetime.UTC
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/asottile/pyupgrade",
    "name": "pyupgrade",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8.1",
    "maintainer_email": null,
    "keywords": null,
    "author": "Anthony Sottile",
    "author_email": "asottile@umich.edu",
    "download_url": "https://files.pythonhosted.org/packages/d1/33/db1101ea1f847ab7407ea24f7470a6db4702e1f49fbc7f3cecd1ceb4eafa/pyupgrade-3.15.2.tar.gz",
    "platform": null,
    "description": "[![build status](https://github.com/asottile/pyupgrade/actions/workflows/main.yml/badge.svg)](https://github.com/asottile/pyupgrade/actions/workflows/main.yml)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/asottile/pyupgrade/main.svg)](https://results.pre-commit.ci/latest/github/asottile/pyupgrade/main)\n\npyupgrade\n=========\n\nA tool (and pre-commit hook) to automatically upgrade syntax for newer\nversions of the language.\n\n## Installation\n\n```bash\npip install pyupgrade\n```\n\n## As a pre-commit hook\n\nSee [pre-commit](https://github.com/pre-commit/pre-commit) for instructions\n\nSample `.pre-commit-config.yaml`:\n\n```yaml\n-   repo: https://github.com/asottile/pyupgrade\n    rev: v3.15.2\n    hooks:\n    -   id: pyupgrade\n```\n\n## Implemented features\n\n### Set literals\n\n```diff\n-set(())\n+set()\n-set([])\n+set()\n-set((1,))\n+{1}\n-set((1, 2))\n+{1, 2}\n-set([1, 2])\n+{1, 2}\n-set(x for x in y)\n+{x for x in y}\n-set([x for x in y])\n+{x for x in y}\n```\n\n### Dictionary comprehensions\n\n```diff\n-dict((a, b) for a, b in y)\n+{a: b for a, b in y}\n-dict([(a, b) for a, b in y])\n+{a: b for a, b in y}\n```\n\n### Replace unnecessary lambdas in `collections.defaultdict` calls\n\n```diff\n-defaultdict(lambda: [])\n+defaultdict(list)\n-defaultdict(lambda: list())\n+defaultdict(list)\n-defaultdict(lambda: {})\n+defaultdict(dict)\n-defaultdict(lambda: dict())\n+defaultdict(dict)\n-defaultdict(lambda: ())\n+defaultdict(tuple)\n-defaultdict(lambda: tuple())\n+defaultdict(tuple)\n-defaultdict(lambda: set())\n+defaultdict(set)\n-defaultdict(lambda: 0)\n+defaultdict(int)\n-defaultdict(lambda: 0.0)\n+defaultdict(float)\n-defaultdict(lambda: 0j)\n+defaultdict(complex)\n-defaultdict(lambda: '')\n+defaultdict(str)\n```\n\n### Format Specifiers\n\n```diff\n-'{0} {1}'.format(1, 2)\n+'{} {}'.format(1, 2)\n-'{0}' '{1}'.format(1, 2)\n+'{}' '{}'.format(1, 2)\n```\n\n### printf-style string formatting\n\nAvailability:\n- Unless `--keep-percent-format` is passed.\n\n```diff\n-'%s %s' % (a, b)\n+'{} {}'.format(a, b)\n-'%r %2f' % (a, b)\n+'{!r} {:2f}'.format(a, b)\n-'%(a)s %(b)s' % {'a': 1, 'b': 2}\n+'{a} {b}'.format(a=1, b=2)\n```\n\n### Unicode literals\n\n```diff\n-u'foo'\n+'foo'\n-u\"foo\"\n+'foo'\n-u'''foo'''\n+'''foo'''\n```\n\n### Invalid escape sequences\n\n```diff\n # strings with only invalid sequences become raw strings\n-'\\d'\n+r'\\d'\n # strings with mixed valid / invalid sequences get escaped\n-'\\n\\d'\n+'\\n\\\\d'\n-u'\\d'\n+r'\\d'\n # this fixes a syntax error in python3.3+\n-'\\N'\n+r'\\N'\n```\n\n### `is` / `is not` comparison to constant literals\n\nIn python3.8+, comparison to literals becomes a `SyntaxWarning` as the success\nof those comparisons is implementation specific (due to common object caching).\n\n```diff\n-x is 5\n+x == 5\n-x is not 5\n+x != 5\n-x is 'foo'\n+x == 'foo'\n```\n\n### `.encode()` to bytes literals\n\n```diff\n-'foo'.encode()\n+b'foo'\n-'foo'.encode('ascii')\n+b'foo'\n-'foo'.encode('utf-8')\n+b'foo'\n-u'foo'.encode()\n+b'foo'\n-'\\xa0'.encode('latin1')\n+b'\\xa0'\n```\n\n### extraneous parens in `print(...)`\n\nA fix for [python-modernize/python-modernize#178]\n\n```diff\n # ok: printing an empty tuple\n print(())\n # ok: printing a tuple\n print((1,))\n # ok: parenthesized generator argument\n sum((i for i in range(3)), [])\n # fixed:\n-print((\"foo\"))\n+print(\"foo\")\n```\n\n[python-modernize/python-modernize#178]: https://github.com/python-modernize/python-modernize/issues/178\n\n### constant fold `isinstance` / `issubclass` / `except`\n\n```diff\n-isinstance(x, (int, int))\n+isinstance(x, int)\n\n-issubclass(y, (str, str))\n+issubclass(y, str)\n\n try:\n     raises()\n-except (Error1, Error1, Error2):\n+except (Error1, Error2):\n     pass\n```\n\n### unittest deprecated aliases\n\nRewrites [deprecated unittest method aliases](https://docs.python.org/3/library/unittest.html#deprecated-aliases) to their non-deprecated forms.\n\n```diff\n from unittest import TestCase\n\n\n class MyTests(TestCase):\n     def test_something(self):\n-        self.failUnlessEqual(1, 1)\n+        self.assertEqual(1, 1)\n-        self.assertEquals(1, 1)\n+        self.assertEqual(1, 1)\n```\n\n### `super()` calls\n\n```diff\n class C(Base):\n     def f(self):\n-        super(C, self).f()\n+        super().f()\n```\n\n### \"new style\" classes\n\n#### rewrites class declaration\n\n```diff\n-class C(object): pass\n+class C: pass\n-class C(B, object): pass\n+class C(B): pass\n```\n\n#### removes `__metaclass__ = type` declaration\n\n```diff\n class C:\n-    __metaclass__ = type\n```\n\n### forced `str(\"native\")` literals\n\n```diff\n-str()\n+''\n-str(\"foo\")\n+\"foo\"\n```\n\n### `.encode(\"utf-8\")`\n\n```diff\n-\"foo\".encode(\"utf-8\")\n+\"foo\".encode()\n```\n\n### `# coding: ...` comment\n\nas of [PEP 3120], the default encoding for python source is UTF-8\n\n```diff\n-# coding: utf-8\n x = 1\n```\n\n[PEP 3120]: https://www.python.org/dev/peps/pep-3120/\n\n### `__future__` import removal\n\nAvailability:\n- by default removes `nested_scopes`, `generators`, `with_statement`,\n  `absolute_import`, `division`, `print_function`, `unicode_literals`\n- `--py37-plus` will also remove `generator_stop`\n\n```diff\n-from __future__ import with_statement\n```\n\n### Remove unnecessary py3-compat imports\n\n```diff\n-from io import open\n-from six.moves import map\n-from builtins import object  # python-future\n```\n\n### import replacements\n\nAvailability:\n- `--py36-plus` (and others) will replace imports\n\nsee also [reorder-python-imports](https://github.com/asottile/reorder_python_imports#removing--rewriting-obsolete-six-imports)\n\nsome examples:\n\n```diff\n-from collections import deque, Mapping\n+from collections import deque\n+from collections.abc import Mapping\n```\n\n```diff\n-from typing import Sequence\n+from collections.abc import Sequence\n```\n\n```diff\n-from typing_extensions import Concatenate\n+from typing import Concatenate\n```\n\n### rewrite `mock` imports\n\nAvailability:\n- [Unless `--keep-mock` is passed on the commandline](https://github.com/asottile/pyupgrade/issues/314).\n\n```diff\n-from mock import patch\n+from unittest.mock import patch\n```\n\n### `yield` => `yield from`\n\n```diff\n def f():\n-    for x in y:\n-        yield x\n+    yield from y\n-    for a, b in c:\n-        yield (a, b)\n+    yield from c\n```\n\n### Python2 and old Python3.x blocks\n\n```diff\n import sys\n-if sys.version_info < (3,):  # also understands `six.PY2` (and `not`), `six.PY3` (and `not`)\n-    print('py2')\n-else:\n-    print('py3')\n+print('py3')\n```\n\nAvailability:\n- `--py36-plus` will remove Python <= 3.5 only blocks\n- `--py37-plus` will remove Python <= 3.6 only blocks\n- so on and so forth\n\n```diff\n # using --py36-plus for this example\n\n import sys\n-if sys.version_info < (3, 6):\n-    print('py3.5')\n-else:\n-    print('py3.6+')\n+print('py3.6+')\n\n-if sys.version_info <= (3, 5):\n-    print('py3.5')\n-else:\n-    print('py3.6+')\n+print('py3.6+')\n\n-if sys.version_info >= (3, 6):\n-    print('py3.6+')\n-else:\n-    print('py3.5')\n+print('py3.6+')\n```\n\nNote that `if` blocks without an `else` will not be rewritten as it could introduce a syntax error.\n\n### remove `six` compatibility code\n\n```diff\n-six.text_type\n+str\n-six.binary_type\n+bytes\n-six.class_types\n+(type,)\n-six.string_types\n+(str,)\n-six.integer_types\n+(int,)\n-six.unichr\n+chr\n-six.iterbytes\n+iter\n-six.print_(...)\n+print(...)\n-six.exec_(c, g, l)\n+exec(c, g, l)\n-six.advance_iterator(it)\n+next(it)\n-six.next(it)\n+next(it)\n-six.callable(x)\n+callable(x)\n-six.moves.range(x)\n+range(x)\n-six.moves.xrange(x)\n+range(x)\n\n\n-from six import text_type\n-text_type\n+str\n\n-@six.python_2_unicode_compatible\n class C:\n     def __str__(self):\n         return u'C()'\n\n-class C(six.Iterator): pass\n+class C: pass\n\n-class C(six.with_metaclass(M, B)): pass\n+class C(B, metaclass=M): pass\n\n-@six.add_metaclass(M)\n-class C(B): pass\n+class C(B, metaclass=M): pass\n\n-isinstance(..., six.class_types)\n+isinstance(..., type)\n-issubclass(..., six.integer_types)\n+issubclass(..., int)\n-isinstance(..., six.string_types)\n+isinstance(..., str)\n\n-six.b('...')\n+b'...'\n-six.u('...')\n+'...'\n-six.byte2int(bs)\n+bs[0]\n-six.indexbytes(bs, i)\n+bs[i]\n-six.int2byte(i)\n+bytes((i,))\n-six.iteritems(dct)\n+dct.items()\n-six.iterkeys(dct)\n+dct.keys()\n-six.itervalues(dct)\n+dct.values()\n-next(six.iteritems(dct))\n+next(iter(dct.items()))\n-next(six.iterkeys(dct))\n+next(iter(dct.keys()))\n-next(six.itervalues(dct))\n+next(iter(dct.values()))\n-six.viewitems(dct)\n+dct.items()\n-six.viewkeys(dct)\n+dct.keys()\n-six.viewvalues(dct)\n+dct.values()\n-six.create_unbound_method(fn, cls)\n+fn\n-six.get_unbound_function(meth)\n+meth\n-six.get_method_function(meth)\n+meth.__func__\n-six.get_method_self(meth)\n+meth.__self__\n-six.get_function_closure(fn)\n+fn.__closure__\n-six.get_function_code(fn)\n+fn.__code__\n-six.get_function_defaults(fn)\n+fn.__defaults__\n-six.get_function_globals(fn)\n+fn.__globals__\n-six.raise_from(exc, exc_from)\n+raise exc from exc_from\n-six.reraise(tp, exc, tb)\n+raise exc.with_traceback(tb)\n-six.reraise(*sys.exc_info())\n+raise\n-six.assertCountEqual(self, a1, a2)\n+self.assertCountEqual(a1, a2)\n-six.assertRaisesRegex(self, e, r, fn)\n+self.assertRaisesRegex(e, r, fn)\n-six.assertRegex(self, s, r)\n+self.assertRegex(s, r)\n\n # note: only for *literals*\n-six.ensure_binary('...')\n+b'...'\n-six.ensure_str('...')\n+'...'\n-six.ensure_text('...')\n+'...'\n```\n\n### `open` alias\n\n```diff\n-with io.open('f.txt') as f:\n+with open('f.txt') as f:\n     ...\n```\n\n\n### redundant `open` modes\n\n```diff\n-open(\"foo\", \"U\")\n+open(\"foo\")\n-open(\"foo\", \"Ur\")\n+open(\"foo\")\n-open(\"foo\", \"Ub\")\n+open(\"foo\", \"rb\")\n-open(\"foo\", \"rUb\")\n+open(\"foo\", \"rb\")\n-open(\"foo\", \"r\")\n+open(\"foo\")\n-open(\"foo\", \"rt\")\n+open(\"foo\")\n-open(\"f\", \"r\", encoding=\"UTF-8\")\n+open(\"f\", encoding=\"UTF-8\")\n-open(\"f\", \"wt\")\n+open(\"f\", \"w\")\n```\n\n\n### `OSError` aliases\n\n```diff\n # also understands:\n # - IOError\n # - WindowsError\n # - mmap.error and uses of `from mmap import error`\n # - select.error and uses of `from select import error`\n # - socket.error and uses of `from socket import error`\n\n def throw():\n-    raise EnvironmentError('boom')\n+    raise OSError('boom')\n\n def catch():\n     try:\n         throw()\n-    except EnvironmentError:\n+    except OSError:\n         handle_error()\n```\n\n### `TimeoutError` aliases\n\nAvailability:\n- `--py310-plus` for `socket.timeout`\n- `--py311-plus` for `asyncio.TimeoutError`\n\n```diff\n\n def throw(a):\n     if a:\n-        raise asyncio.TimeoutError('boom')\n+        raise TimeoutError('boom')\n     else:\n-        raise socket.timeout('boom')\n+        raise TimeoutError('boom')\n\n def catch(a):\n     try:\n         throw(a)\n-    except (asyncio.TimeoutError, socket.timeout):\n+    except TimeoutError:\n         handle_error()\n```\n\n### `typing.Text` str alias\n\n```diff\n-def f(x: Text) -> None:\n+def f(x: str) -> None:\n     ...\n```\n\n\n### Unpacking list comprehensions\n\n```diff\n-foo, bar, baz = [fn(x) for x in items]\n+foo, bar, baz = (fn(x) for x in items)\n```\n\n\n### Rewrite `xml.etree.cElementTree` to `xml.etree.ElementTree`\n\n```diff\n-import xml.etree.cElementTree as ET\n+import xml.etree.ElementTree as ET\n-from xml.etree.cElementTree import XML\n+from xml.etree.ElementTree import XML\n```\n\n\n### Rewrite `type` of primitive\n\n```diff\n-type('')\n+str\n-type(b'')\n+bytes\n-type(0)\n+int\n-type(0.)\n+float\n```\n\n### `typing.NamedTuple` / `typing.TypedDict` py36+ syntax\n\nAvailability:\n- `--py36-plus` is passed on the commandline.\n\n```diff\n-NT = typing.NamedTuple('NT', [('a', int), ('b', Tuple[str, ...])])\n+class NT(typing.NamedTuple):\n+    a: int\n+    b: Tuple[str, ...]\n\n-D1 = typing.TypedDict('D1', a=int, b=str)\n+class D1(typing.TypedDict):\n+    a: int\n+    b: str\n\n-D2 = typing.TypedDict('D2', {'a': int, 'b': str})\n+class D2(typing.TypedDict):\n+    a: int\n+    b: str\n```\n\n### f-strings\n\nAvailability:\n- `--py36-plus` is passed on the commandline.\n\n```diff\n-'{foo} {bar}'.format(foo=foo, bar=bar)\n+f'{foo} {bar}'\n-'{} {}'.format(foo, bar)\n+f'{foo} {bar}'\n-'{} {}'.format(foo.bar, baz.womp)\n+f'{foo.bar} {baz.womp}'\n-'{} {}'.format(f(), g())\n+f'{f()} {g()}'\n-'{x}'.format(**locals())\n+f'{x}'\n```\n\n_note_: `pyupgrade` is intentionally timid and will not create an f-string\nif it would make the expression longer or if the substitution parameters are\nsufficiently complicated (as this can decrease readability).\n\n\n### `subprocess.run`: replace `universal_newlines` with `text`\n\nAvailability:\n- `--py37-plus` is passed on the commandline.\n\n```diff\n-output = subprocess.run(['foo'], universal_newlines=True)\n+output = subprocess.run(['foo'], text=True)\n```\n\n\n### `subprocess.run`: replace `stdout=subprocess.PIPE, stderr=subprocess.PIPE` with `capture_output=True`\n\nAvailability:\n- `--py37-plus` is passed on the commandline.\n\n```diff\n-output = subprocess.run(['foo'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n+output = subprocess.run(['foo'], capture_output=True)\n```\n\n\n### remove parentheses from `@functools.lru_cache()`\n\nAvailability:\n- `--py38-plus` is passed on the commandline.\n\n```diff\n import functools\n\n-@functools.lru_cache()\n+@functools.lru_cache\n def expensive():\n     ...\n```\n\n### shlex.join\n\nAvailability:\n- `--py38-plus` is passed on the commandline.\n\n```diff\n-' '.join(shlex.quote(arg) for arg in cmd)\n+shlex.join(cmd)\n```\n\n### replace `@functools.lru_cache(maxsize=None)` with shorthand\n\nAvailability:\n- `--py39-plus` is passed on the commandline.\n\n```diff\n import functools\n\n-@functools.lru_cache(maxsize=None)\n+@functools.cache\n def expensive():\n     ...\n```\n\n\n### pep 585 typing rewrites\n\nAvailability:\n- File imports `from __future__ import annotations`\n    - Unless `--keep-runtime-typing` is passed on the commandline.\n- `--py39-plus` is passed on the commandline.\n\n```diff\n-def f(x: List[str]) -> None:\n+def f(x: list[str]) -> None:\n     ...\n```\n\n\n### pep 604 typing rewrites\n\nAvailability:\n- File imports `from __future__ import annotations`\n    - Unless `--keep-runtime-typing` is passed on the commandline.\n- `--py310-plus` is passed on the commandline.\n\n```diff\n-def f() -> Optional[str]:\n+def f() -> str | None:\n     ...\n```\n\n```diff\n-def f() -> Union[int, str]:\n+def f() -> int | str:\n     ...\n```\n\n\n### remove quoted annotations\n\nAvailability:\n- File imports `from __future__ import annotations`\n\n```diff\n-def f(x: 'queue.Queue[int]') -> C:\n+def f(x: queue.Queue[int]) -> C:\n```\n\n\n### use `datetime.UTC` alias\n\nAvailability:\n- `--py311-plus` is passed on the commandline.\n\n```diff\n import datetime\n\n-datetime.timezone.utc\n+datetime.UTC\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A tool to automatically upgrade syntax for newer versions.",
    "version": "3.15.2",
    "project_urls": {
        "Homepage": "https://github.com/asottile/pyupgrade"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7fd82f5c6481ce50886a29cd2bfa8070a0f76672272446549ddcfe6baa5ec6bc",
                "md5": "6f19fb12c3d894be810d48c031135c08",
                "sha256": "ce309e0ff8ecb73f56a45f12570be84bbbde9540d13697cacb261a7f595fb1f5"
            },
            "downloads": -1,
            "filename": "pyupgrade-3.15.2-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "6f19fb12c3d894be810d48c031135c08",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": ">=3.8.1",
            "size": 61213,
            "upload_time": "2024-03-24T17:07:59",
            "upload_time_iso_8601": "2024-03-24T17:07:59.386447Z",
            "url": "https://files.pythonhosted.org/packages/7f/d8/2f5c6481ce50886a29cd2bfa8070a0f76672272446549ddcfe6baa5ec6bc/pyupgrade-3.15.2-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d133db1101ea1f847ab7407ea24f7470a6db4702e1f49fbc7f3cecd1ceb4eafa",
                "md5": "6ca4f964aaafa00b7d1544b3583039c5",
                "sha256": "c488d6896c546d25845712ef6402657123008d56c1063174e27aabe15bd6b4e5"
            },
            "downloads": -1,
            "filename": "pyupgrade-3.15.2.tar.gz",
            "has_sig": false,
            "md5_digest": "6ca4f964aaafa00b7d1544b3583039c5",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8.1",
            "size": 44973,
            "upload_time": "2024-03-24T17:08:02",
            "upload_time_iso_8601": "2024-03-24T17:08:02.411126Z",
            "url": "https://files.pythonhosted.org/packages/d1/33/db1101ea1f847ab7407ea24f7470a6db4702e1f49fbc7f3cecd1ceb4eafa/pyupgrade-3.15.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-24 17:08:02",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "asottile",
    "github_project": "pyupgrade",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "pyupgrade"
}
        
Elapsed time: 0.20503s