Una herramienta (y un enlace de confirmación previa) para actualizar automáticamente la sintaxis para versiones más nuevas del lenguaje.
pip install pyupgrade
Consulte la confirmación previa para obtener instrucciones.
Ejemplo .pre-commit-config.yaml
:
- repo : https://github.com/asottile/pyupgrade
rev : v3.19.0
hooks :
- id : pyupgrade
- 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}
- 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}
collections.defaultdict
- 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)
- '{0} {1}'.format(1, 2)
+ '{} {}'.format(1, 2)
- '{0}' '{1}'.format(1, 2)
+ '{}' '{}'.format(1, 2)
Disponibilidad:
--keep-percent-format
. - '%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)
- u'foo'
+ 'foo'
- u"foo"
+ 'foo'
- u'''foo'''
+ '''foo'''
# strings with only invalid sequences become raw strings
- 'd'
+ r'd'
# strings with mixed valid / invalid sequences get escaped
- 'nd'
+ 'n\d'
- u'd'
+ r'd'
# this fixes a syntax error in python3.3+
- 'N'
+ r'N'
is
/ is not
comparación con literales constantes En python3.8+, la comparación con literales se convierte en una SyntaxWarning
ya que el éxito de esas comparaciones es específico de la implementación (debido al almacenamiento en caché de objetos común).
- x is 5
+ x == 5
- x is not 5
+ x != 5
- x is 'foo'
+ x == 'foo'
.encode()
a bytes literales - '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'
print(...)
Una solución para python-modernize/python-modernize#178
# 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")
isinstance
/ issubclass
/ except
- isinstance(x, (int, int))
+ isinstance(x, int)
- issubclass(y, (str, str))
+ issubclass(y, str)
try:
raises()
- except (Error1, Error1, Error2):
+ except (Error1, Error2):
pass
Reescribe los alias de métodos unittest obsoletos en sus formas no obsoletas.
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()
class C(Base):
def f(self):
- super(C, self).f()
+ super().f()
- class C(object): pass
+ class C: pass
- class C(B, object): pass
+ class C(B): pass
__metaclass__ = type
class C:
- __metaclass__ = type
str("native")
forzados - str()
+ ''
- str("foo")
+ "foo"
.encode("utf-8")
- "foo".encode("utf-8")
+ "foo".encode()
# coding: ...
comentarioa partir de PEP 3120, la codificación predeterminada para la fuente Python es UTF-8
- # coding: utf-8
x = 1
__future__
eliminación de importaciónDisponibilidad:
nested_scopes
, generators
, with_statement
, absolute_import
, division
, print_function
, unicode_literals
--py37-plus
también eliminará generator_stop
- from __future__ import with_statement
- from io import open
- from six.moves import map
- from builtins import object # python-future
Disponibilidad:
--py36-plus
(y otros) reemplazarán las importacionesver también reordenar-python-importaciones
algunos ejemplos:
- from collections import deque, Mapping
+ from collections import deque
+ from collections.abc import Mapping
- from typing import Sequence
+ from collections.abc import Sequence
- from typing_extensions import Concatenate
+ from typing import Concatenate
mock
Disponibilidad:
--keep-mock
en la línea de comando. - from mock import patch
+ from unittest.mock import patch
yield
=> yield from
def f():
- for x in y:
- yield x
+ yield from y
- for a, b in c:
- yield (a, b)
+ yield from c
import sys
- if sys.version_info < (3,): # also understands `six.PY2` (and `not`), `six.PY3` (and `not`)
- print('py2')
- else:
- print('py3')
+ print('py3')
Disponibilidad:
--py36-plus
eliminará solo los bloques Python <= 3.5--py37-plus
eliminará solo los bloques de Python <= 3.6 # 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+')
Tenga en cuenta que if
los bloques sin un else
no se reescribirán, ya que podría introducir un error de sintaxis.
six
códigos de compatibilidad - 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
- with io.open('f.txt') as f:
+ with open('f.txt') as f:
...
open
redundantes - 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
# 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
Disponibilidad:
--py310-plus
para socket.timeout
--py311-plus
para asyncio.TimeoutError
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
Alias de cadena de texto - def f(x: Text) -> None:
+ def f(x: str) -> None:
...
- foo, bar, baz = [fn(x) for x in items]
+ foo, bar, baz = (fn(x) for x in items)
xml.etree.cElementTree
en xml.etree.ElementTree
- import xml.etree.cElementTree as ET
+ import xml.etree.ElementTree as ET
- from xml.etree.cElementTree import XML
+ from xml.etree.ElementTree import XML
type
de primitiva - type('')
+ str
- type(b'')
+ bytes
- type(0)
+ int
- type(0.)
+ float
typing.NamedTuple
/ typing.TypedDict
py36+ sintaxisDisponibilidad:
--py36-plus
se pasa en la línea de comando. - 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
Disponibilidad:
--py36-plus
se pasa en la línea de comando. - '{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}'
nota : pyupgrade
es intencionalmente tímido y no creará una cadena f si alarga la expresión o si los parámetros de sustitución son lo suficientemente complicados (ya que esto puede disminuir la legibilidad).
subprocess.run
: reemplaza universal_newlines
con text
Disponibilidad:
--py37-plus
se pasa en la línea de comando. - output = subprocess.run(['foo'], universal_newlines=True)
+ output = subprocess.run(['foo'], text=True)
subprocess.run
: reemplace stdout=subprocess.PIPE, stderr=subprocess.PIPE
con capture_output=True
Disponibilidad:
--py37-plus
se pasa en la línea de comando. - output = subprocess.run(['foo'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ output = subprocess.run(['foo'], capture_output=True)
@functools.lru_cache()
Disponibilidad:
--py38-plus
se pasa en la línea de comando. import functools
- @functools.lru_cache()
+ @functools.lru_cache
def expensive():
...
Disponibilidad:
--py38-plus
se pasa en la línea de comando. - ' '.join(shlex.quote(arg) for arg in cmd)
+ shlex.join(cmd)
@functools.lru_cache(maxsize=None)
con taquigrafíaDisponibilidad:
--py39-plus
se pasa en la línea de comando. import functools
- @functools.lru_cache(maxsize=None)
+ @functools.cache
def expensive():
...
Disponibilidad:
from __future__ import annotations
--keep-runtime-typing
en la línea de comando.--py39-plus
se pasa en la línea de comando. - def f(x: List[str]) -> None:
+ def f(x: list[str]) -> None:
...
Disponibilidad:
from __future__ import annotations
--keep-runtime-typing
en la línea de comando.--py310-plus
se pasa en la línea de comando. - def f() -> Optional[str]:
+ def f() -> str | None:
...
- def f() -> Union[int, str]:
+ def f() -> int | str:
...
Disponibilidad:
from __future__ import annotations
--keep-runtime-typing
en la línea de comando.--py313-plus
se pasa en la línea de comando. - def f() -> Generator[int, None, None]:
+ def f() -> Generator[int]:
yield 1
- async def f() -> AsyncGenerator[int, None]:
+ async def f() -> AsyncGenerator[int]:
yield 1
Disponibilidad:
from __future__ import annotations
- def f(x: 'queue.Queue[int]') -> C:
+ def f(x: queue.Queue[int]) -> C:
datetime.UTC
Disponibilidad:
--py311-plus
se pasa en la línea de comando. import datetime
- datetime.timezone.utc
+ datetime.UTC