diff --git a/README.md b/README.md index f9d844e5..04e4e1fe 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Sample `.pre-commit-config.yaml`: ``` -### Python2.7+ Format Specifiers +### Format Specifiers ```diff -'{0} {1}'.format(1, 2) @@ -83,10 +83,6 @@ Availability: ### Unicode literals -Availability: -- File imports `from __future__ import unicode_literals` -- `--py3-plus` is passed on the commandline. - ```diff -u'foo' +'foo' @@ -105,9 +101,8 @@ Availability: # 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' ++r'\d' # this fixes a syntax error in python3.3+ -'\N' +r'\N' @@ -131,22 +126,6 @@ of those comparisons is implementation specific (due to common object caching). +x == 'foo' ``` -### `ur` string literals - -`ur'...'` literals are not valid in python 3.x - -```diff --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 ```diff @@ -162,26 +141,6 @@ of those comparisons is implementation specific (due to common object caching). +b'\xa0' ``` -### Long literals - -```diff --5L -+5 --5l -+5 --123456789123456789123456789L -+123456789123456789123456789 -``` - -### Octal literals - -```diff --0755 -+0o755 --05 -+5 -``` - ### extraneous parens in `print(...)` A fix for [python-modernize/python-modernize#178] @@ -204,9 +163,6 @@ A fix for [python-modernize/python-modernize#178] Rewrites [deprecated unittest method aliases](https://docs.python.org/3/library/unittest.html#deprecated-aliases) to their non-deprecated forms. -Availability: -- More deprecated aliases are rewritten with `--py3-plus` - ```diff from unittest import TestCase @@ -221,9 +177,6 @@ Availability: ### `super()` calls -Availability: -- `--py3-plus` is passed on the commandline. - ```diff class C(Base): def f(self): @@ -233,9 +186,6 @@ Availability: ### "new style" classes -Availability: -- `--py3-plus` is passed on the commandline. - #### rewrites class declaration ```diff @@ -254,9 +204,6 @@ Availability: ### forced `str("native")` literals -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -str() +'' @@ -266,9 +213,6 @@ Availability: ### `.encode("utf-8")` -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -"foo".encode("utf-8") +"foo".encode() @@ -276,9 +220,6 @@ Availability: ### `# coding: ...` comment -Availability: -- `--py3-plus` is passed on the commandline. - as of [PEP 3120], the default encoding for python source is UTF-8 ```diff @@ -291,9 +232,8 @@ as of [PEP 3120], the default encoding for python source is UTF-8 ### `__future__` import removal Availability: -- by default removes `nested_scopes`, `generators`, `with_statement` -- `--py3-plus` will also remove `absolute_import` / `division` / - `print_function` / `unicode_literals` +- by default removes `nested_scopes`, `generators`, `with_statement`, + `absolute_import`, `division`, `print_function`, `unicode_literals` - `--py37-plus` will also remove `generator_stop` ```diff @@ -302,9 +242,6 @@ Availability: ### Remove unnecessary py3-compat imports -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -from io import open -from six.moves import map @@ -314,7 +251,7 @@ Availability: ### import replacements Availability: -- `--py3-plus` (and others) will replace imports +- `--py36-plus` (and others) will replace imports see also [reorder-python-imports](https://github.com/asottile/reorder_python_imports#removing--rewriting-obsolete-six-imports) @@ -339,7 +276,6 @@ some examples: ### rewrite `mock` imports Availability: -- `--py3-plus` is passed on the commandline. - [Unless `--keep-mock` is passed on the commandline](https://github.com/asottile/pyupgrade/issues/314). ```diff @@ -349,9 +285,6 @@ Availability: ### `yield` => `yield from` -Availability: -- `--py3-plus` is passed on the commandline. - ```diff def f(): - for x in y: @@ -364,9 +297,6 @@ Availability: ### Python2 and old Python3.x blocks -Availability: -- `--py3-plus` is passed on the commandline. - ```diff import sys -if sys.version_info < (3,): # also understands `six.PY2` (and `not`), `six.PY3` (and `not`) @@ -408,9 +338,6 @@ Note that `if` blocks without an `else` will not be rewritten as it could introd ### remove `six` compatibility code -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -six.text_type +str @@ -536,9 +463,6 @@ Availability: ### `open` alias -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -with io.open('f.txt') as f: +with open('f.txt') as f: @@ -548,9 +472,6 @@ Availability: ### redundant `open` modes -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -open("foo", "U") +open("foo") @@ -571,9 +492,6 @@ Availability: ### `OSError` aliases -Availability: -- `--py3-plus` is passed on the commandline. - ```diff # also understands: # - IOError @@ -596,9 +514,6 @@ Availability: ### `typing.Text` str alias -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -def f(x: Text) -> None: +def f(x: str) -> None: @@ -608,9 +523,6 @@ Availability: ### Unpacking list comprehensions -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -foo, bar, baz = [fn(x) for x in items] +foo, bar, baz = (fn(x) for x in items) @@ -619,9 +531,6 @@ Availability: ### Rewrite `xml.etree.cElementTree` to `xml.etree.ElementTree` -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -import xml.etree.cElementTree as ET +import xml.etree.ElementTree as ET @@ -632,9 +541,6 @@ Availability: ### Rewrite `type` of primitive -Availability: -- `--py3-plus` is passed on the commandline. - ```diff -type('') +str diff --git a/pyupgrade/_data.py b/pyupgrade/_data.py index 06d99891..65d345d0 100644 --- a/pyupgrade/_data.py +++ b/pyupgrade/_data.py @@ -25,7 +25,7 @@ class Settings(NamedTuple): - min_version: Version = (2, 7) + min_version: Version = (3,) keep_percent_format: bool = False keep_mock: bool = False keep_runtime_typing: bool = False diff --git a/pyupgrade/_main.py b/pyupgrade/_main.py index 538d151b..18feb8eb 100644 --- a/pyupgrade/_main.py +++ b/pyupgrade/_main.py @@ -20,7 +20,6 @@ from pyupgrade._ast_helpers import ast_parse from pyupgrade._data import FUNCS from pyupgrade._data import Settings -from pyupgrade._data import Version from pyupgrade._data import visit from pyupgrade._string_helpers import DotFormatPart from pyupgrade._string_helpers import is_codec @@ -83,33 +82,6 @@ def _fix_plugins(contents_text: str, settings: Settings) -> str: return tokens_to_src(tokens).lstrip() -def _imports_future(contents_text: str, future_name: str) -> bool: - try: - ast_obj = ast_parse(contents_text) - except SyntaxError: - return False - - for node in ast_obj.body: - # Docstring - if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str): - continue - elif isinstance(node, ast.ImportFrom): - if ( - node.level == 0 and - node.module == '__future__' and - any(name.name == future_name for name in node.names) - ): - return True - elif node.module == '__future__': - continue - else: - return False - else: - return False - - return False - - # https://docs.python.org/3/reference/lexical_analysis.html ESCAPE_STARTS = frozenset(( '\n', '\r', '\\', "'", '"', 'a', 'b', 'f', 'n', 'r', 't', 'v', @@ -173,36 +145,6 @@ def _remove_u_prefix(token: Token) -> Token: return token._replace(src=new_prefix + rest) -def _fix_ur_literals(token: Token) -> Token: - prefix, rest = parse_string_literal(token.src) - if prefix.lower() != 'ur': - return token - else: - def cb(match: Match[str]) -> str: - escape = match.group() - if escape[1].lower() == 'u': - return escape - else: - return '\\' + match.group() - - rest = ESCAPE_RE.sub(cb, rest) - prefix = prefix.replace('r', '').replace('R', '') - return token._replace(src=prefix + rest) - - -def _fix_long(src: str) -> str: - return src.rstrip('lL') - - -def _fix_octal(s: str) -> str: - if not s.startswith('0') or not s.isdigit() or s == len(s) * '0': - return s - elif len(s) == 2: - return s[1:] - else: - return '0o' + s[1:] - - def _fix_extraneous_parens(tokens: list[Token], i: int) -> None: # search forward for another non-coding token i += 1 @@ -334,66 +276,14 @@ def _fix_encode_to_binary(tokens: list[Token], i: int) -> None: del tokens[victims] -def _build_import_removals() -> dict[Version, dict[str, tuple[str, ...]]]: - ret = {} - future: tuple[tuple[Version, tuple[str, ...]], ...] = ( - ((2, 7), ('nested_scopes', 'generators', 'with_statement')), - ( - (3,), ( - 'absolute_import', 'division', 'print_function', - 'unicode_literals', - ), - ), - ((3, 6), ()), - ((3, 7), ('generator_stop',)), - ((3, 8), ()), - ((3, 9), ()), - ((3, 10), ()), - ((3, 11), ()), - ) - - prev: tuple[str, ...] = () - for min_version, names in future: - prev += names - ret[min_version] = {'__future__': prev} - # see reorder_python_imports - for k, v in ret.items(): - if k >= (3,): - v.update({ - 'builtins': ( - 'ascii', 'bytes', 'chr', 'dict', 'filter', 'hex', 'input', - 'int', 'list', 'map', 'max', 'min', 'next', 'object', - 'oct', 'open', 'pow', 'range', 'round', 'str', 'super', - 'zip', '*', - ), - 'io': ('open',), - 'six': ('callable', 'next'), - 'six.moves': ('filter', 'input', 'map', 'range', 'zip'), - }) - return ret - - -IMPORT_REMOVALS = _build_import_removals() - - -def _fix_tokens(contents_text: str, min_version: Version) -> str: - remove_u = ( - min_version >= (3,) or - _imports_future(contents_text, 'unicode_literals') - ) - +def _fix_tokens(contents_text: str) -> str: try: tokens = src_to_tokens(contents_text) except tokenize.TokenError: return contents_text for i, token in reversed_enumerate(tokens): - if token.name == 'NUMBER': - tokens[i] = token._replace(src=_fix_long(_fix_octal(token.src))) - elif token.name == 'STRING': - tokens[i] = _fix_ur_literals(tokens[i]) - if remove_u: - tokens[i] = _remove_u_prefix(tokens[i]) - tokens[i] = _fix_escape_sequences(tokens[i]) + if token.name == 'STRING': + tokens[i] = _fix_escape_sequences(_remove_u_prefix(tokens[i])) elif token.src == '(': _fix_extraneous_parens(tokens, i) elif token.src == 'format' and i > 0 and tokens[i - 1].src == '.': @@ -401,7 +291,6 @@ def _fix_tokens(contents_text: str, min_version: Version) -> str: elif token.src == 'encode' and i > 0 and tokens[i - 1].src == '.': _fix_encode_to_binary(tokens, i) elif ( - min_version >= (3,) and token.utf8_byte_offset == 0 and token.line < 3 and token.name == 'COMMENT' and @@ -435,7 +324,7 @@ def _fix_file(filename: str, args: argparse.Namespace) -> int: keep_runtime_typing=args.keep_runtime_typing, ), ) - contents_text = _fix_tokens(contents_text, min_version=args.min_version) + contents_text = _fix_tokens(contents_text) if filename == '-': print(contents_text, end='') @@ -459,7 +348,7 @@ def main(argv: Sequence[str] | None = None) -> int: parser.add_argument('--keep-runtime-typing', action='store_true') parser.add_argument( '--py3-plus', '--py3-only', - action='store_const', dest='min_version', default=(2, 7), const=(3,), + action='store_const', dest='min_version', default=(3,), const=(3,), ) parser.add_argument( '--py36-plus', @@ -487,12 +376,6 @@ def main(argv: Sequence[str] | None = None) -> int: ) args = parser.parse_args(argv) - if args.min_version < (3,): - print( - 'WARNING: pyupgrade will default to --py3-plus in 3.x', - file=sys.stderr, - ) - ret = 0 for filename in args.filenames: ret |= _fix_file(filename, args) diff --git a/pyupgrade/_plugins/collections_abc.py b/pyupgrade/_plugins/collections_abc.py index 2612ba01..f7e879e3 100644 --- a/pyupgrade/_plugins/collections_abc.py +++ b/pyupgrade/_plugins/collections_abc.py @@ -25,7 +25,6 @@ def visit_Attribute( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.value, ast.Name) and node.value.id == 'collections' and node.attr in COLLECTIONS_ABC_ATTRS diff --git a/pyupgrade/_plugins/default_encoding.py b/pyupgrade/_plugins/default_encoding.py index 3d725c03..f1ee54c8 100644 --- a/pyupgrade/_plugins/default_encoding.py +++ b/pyupgrade/_plugins/default_encoding.py @@ -29,7 +29,6 @@ def visit_Call( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.func, ast.Attribute) and isinstance(node.func.value, (ast.Str, ast.JoinedStr)) and node.func.attr == 'encode' and diff --git a/pyupgrade/_plugins/imports.py b/pyupgrade/_plugins/imports.py index 31e977c4..5e9cf9a9 100644 --- a/pyupgrade/_plugins/imports.py +++ b/pyupgrade/_plugins/imports.py @@ -23,11 +23,10 @@ # GENERATED VIA generate-imports # Using reorder-python-imports==3.8.3 REMOVALS = { - (2, 7): {'__future__': {'generators', 'nested_scopes', 'with_statement'}}, (3,): { '__future__': { - 'absolute_import', 'division', 'print_function', - 'unicode_literals', + 'absolute_import', 'division', 'generators', 'nested_scopes', + 'print_function', 'unicode_literals', 'with_statement', }, 'builtins': { '*', 'ascii', 'bytes', 'chr', 'dict', 'filter', 'hex', 'input', @@ -244,15 +243,13 @@ def _for_version( if ver <= version: exact.update(ver_exact) - mods = {} - if version >= (3,): - mods.update(REPLACE_MODS) - if not keep_mock: - exact['mock', 'mock'] = 'unittest' - mods.update({ - 'mock': 'unittest.mock', - 'mock.mock': 'unittest.mock', - }) + mods = {**REPLACE_MODS} + if not keep_mock: + exact['mock', 'mock'] = 'unittest' + mods.update({ + 'mock': 'unittest.mock', + 'mock.mock': 'unittest.mock', + }) return removals, exact, mods diff --git a/pyupgrade/_plugins/io_open.py b/pyupgrade/_plugins/io_open.py index eb4fa6af..571a8bf1 100644 --- a/pyupgrade/_plugins/io_open.py +++ b/pyupgrade/_plugins/io_open.py @@ -25,7 +25,6 @@ def visit_Call( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.func, ast.Attribute) and isinstance(node.func.value, ast.Name) and node.func.value.id == 'io' and diff --git a/pyupgrade/_plugins/legacy.py b/pyupgrade/_plugins/legacy.py index 568eebe0..19a11372 100644 --- a/pyupgrade/_plugins/legacy.py +++ b/pyupgrade/_plugins/legacy.py @@ -207,9 +207,6 @@ def visit_Module( node: ast.Module, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version < (3,): - return - visitor = Visitor() visitor.visit(node) diff --git a/pyupgrade/_plugins/metaclass_type.py b/pyupgrade/_plugins/metaclass_type.py index 37306096..5749050a 100644 --- a/pyupgrade/_plugins/metaclass_type.py +++ b/pyupgrade/_plugins/metaclass_type.py @@ -25,7 +25,6 @@ def visit_Assign( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and len(node.targets) == 1 and isinstance(node.targets[0], ast.Name) and node.targets[0].col_offset == 0 and diff --git a/pyupgrade/_plugins/mock.py b/pyupgrade/_plugins/mock.py index 6e567dfa..9b41fc9d 100644 --- a/pyupgrade/_plugins/mock.py +++ b/pyupgrade/_plugins/mock.py @@ -25,7 +25,6 @@ def visit_Attribute( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and not state.settings.keep_mock and isinstance(node.value, ast.Name) and node.value.id == 'mock' and diff --git a/pyupgrade/_plugins/native_literals.py b/pyupgrade/_plugins/native_literals.py index e95dfe7a..48ced5bd 100644 --- a/pyupgrade/_plugins/native_literals.py +++ b/pyupgrade/_plugins/native_literals.py @@ -55,14 +55,10 @@ def visit_Call( node: ast.Call, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if ( - state.settings.min_version >= (3,) and - is_a_native_literal_call(node, state.from_imports) - ): + if is_a_native_literal_call(node, state.from_imports): func = functools.partial(_fix_literal, empty="''") yield ast_to_offset(node), func elif ( - state.settings.min_version >= (3,) and isinstance(node.func, ast.Name) and node.func.id == 'bytes' and not node.keywords and not has_starargs(node) and ( diff --git a/pyupgrade/_plugins/new_style_classes.py b/pyupgrade/_plugins/new_style_classes.py index 2b4dc962..f0bb6f4e 100644 --- a/pyupgrade/_plugins/new_style_classes.py +++ b/pyupgrade/_plugins/new_style_classes.py @@ -18,7 +18,6 @@ def visit_ClassDef( node: ast.ClassDef, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,): - for base in node.bases: - if isinstance(base, ast.Name) and base.id == 'object': - yield ast_to_offset(base), remove_base_class + for base in node.bases: + if isinstance(base, ast.Name) and base.id == 'object': + yield ast_to_offset(base), remove_base_class diff --git a/pyupgrade/_plugins/open_mode.py b/pyupgrade/_plugins/open_mode.py index bc3169ab..38b3e722 100644 --- a/pyupgrade/_plugins/open_mode.py +++ b/pyupgrade/_plugins/open_mode.py @@ -54,7 +54,6 @@ def visit_Call( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and ( ( isinstance(node.func, ast.Name) and diff --git a/pyupgrade/_plugins/oserror_aliases.py b/pyupgrade/_plugins/oserror_aliases.py index 3c1144b9..9b57037a 100644 --- a/pyupgrade/_plugins/oserror_aliases.py +++ b/pyupgrade/_plugins/oserror_aliases.py @@ -107,7 +107,7 @@ def visit_Raise( node: ast.Raise, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,) and node.exc is not None: + if node.exc is not None: yield from _oserror_alias_cbs(node.exc, state.from_imports) if isinstance(node.exc, ast.Call): yield from _oserror_alias_cbs(node.exc.func, state.from_imports) @@ -119,19 +119,18 @@ def visit_Try( node: ast.Try, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,): - for handler in node.handlers: - if ( - isinstance(handler.type, ast.Tuple) and - any( - _is_oserror_alias(elt, state.from_imports) - for elt in handler.type.elts - ) - ): - func = functools.partial( - _fix_oserror_except, - from_imports=state.from_imports, + for handler in node.handlers: + if ( + isinstance(handler.type, ast.Tuple) and + any( + _is_oserror_alias(elt, state.from_imports) + for elt in handler.type.elts ) - yield ast_to_offset(handler.type), func - elif handler.type is not None: - yield from _oserror_alias_cbs(handler.type, state.from_imports) + ): + func = functools.partial( + _fix_oserror_except, + from_imports=state.from_imports, + ) + yield ast_to_offset(handler.type), func + elif handler.type is not None: + yield from _oserror_alias_cbs(handler.type, state.from_imports) diff --git a/pyupgrade/_plugins/six_base_classes.py b/pyupgrade/_plugins/six_base_classes.py index f24f3704..77008bce 100644 --- a/pyupgrade/_plugins/six_base_classes.py +++ b/pyupgrade/_plugins/six_base_classes.py @@ -19,7 +19,6 @@ def visit_ClassDef( node: ast.ClassDef, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,): - for base in node.bases: - if is_name_attr(base, state.from_imports, ('six',), ('Iterator',)): - yield ast_to_offset(base), remove_base_class + for base in node.bases: + if is_name_attr(base, state.from_imports, ('six',), ('Iterator',)): + yield ast_to_offset(base), remove_base_class diff --git a/pyupgrade/_plugins/six_calls.py b/pyupgrade/_plugins/six_calls.py index 4d149da8..e948a8ed 100644 --- a/pyupgrade/_plugins/six_calls.py +++ b/pyupgrade/_plugins/six_calls.py @@ -72,9 +72,6 @@ def visit_Call( node: ast.Call, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version < (3,): - return - if isinstance(node.func, ast.Name): name = node.func.id elif isinstance(node.func, ast.Attribute): @@ -137,7 +134,6 @@ def visit_Call( ) yield ast_to_offset(node), func elif ( - state.settings.min_version >= (3,) and is_name_attr( node.func, state.from_imports, diff --git a/pyupgrade/_plugins/six_metaclasses.py b/pyupgrade/_plugins/six_metaclasses.py index ea7f164f..c4619529 100644 --- a/pyupgrade/_plugins/six_metaclasses.py +++ b/pyupgrade/_plugins/six_metaclasses.py @@ -76,9 +76,6 @@ def visit_ClassDef( node: ast.ClassDef, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version < (3,): - return - for decorator in node.decorator_list: if ( isinstance(decorator, ast.Call) and diff --git a/pyupgrade/_plugins/six_remove_decorators.py b/pyupgrade/_plugins/six_remove_decorators.py index f1ac1483..6998ac70 100644 --- a/pyupgrade/_plugins/six_remove_decorators.py +++ b/pyupgrade/_plugins/six_remove_decorators.py @@ -19,12 +19,11 @@ def visit_ClassDef( node: ast.ClassDef, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,): - for decorator in node.decorator_list: - if is_name_attr( - decorator, - state.from_imports, - ('six',), - ('python_2_unicode_compatible',), - ): - yield ast_to_offset(decorator), remove_decorator + for decorator in node.decorator_list: + if is_name_attr( + decorator, + state.from_imports, + ('six',), + ('python_2_unicode_compatible',), + ): + yield ast_to_offset(decorator), remove_decorator diff --git a/pyupgrade/_plugins/six_simple.py b/pyupgrade/_plugins/six_simple.py index c2095bc3..e583a7b2 100644 --- a/pyupgrade/_plugins/six_simple.py +++ b/pyupgrade/_plugins/six_simple.py @@ -51,7 +51,6 @@ def visit_Attribute( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.value, ast.Name) and node.value.id == 'six' and node.attr in NAMES @@ -71,7 +70,6 @@ def visit_Attribute( func = functools.partial(replace_name, name=node.attr, new=new) yield ast_to_offset(node), func elif ( - state.settings.min_version >= (3,) and isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and node.value.value.id == 'six' and @@ -81,7 +79,6 @@ def visit_Attribute( func = functools.partial(replace_name, name=node.attr, new='range') yield ast_to_offset(node), func elif ( - state.settings.min_version >= (3,) and isinstance(node.value, ast.Attribute) and isinstance(node.value.value, ast.Name) and node.value.value.id == 'six' and @@ -99,7 +96,6 @@ def visit_Name( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and node.id in state.from_imports['six'] and node.id in NAMES ): @@ -118,7 +114,6 @@ def visit_Name( func = functools.partial(replace_name, name=node.id, new=new) yield ast_to_offset(node), func elif ( - state.settings.min_version >= (3,) and node.id in state.from_imports['six.moves'] and node.id in {'xrange', 'range'} ): diff --git a/pyupgrade/_plugins/type_of_primitive.py b/pyupgrade/_plugins/type_of_primitive.py index 908da4c3..1fc323d4 100644 --- a/pyupgrade/_plugins/type_of_primitive.py +++ b/pyupgrade/_plugins/type_of_primitive.py @@ -40,7 +40,6 @@ def visit_Call( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.func, ast.Name) and node.func.id == 'type' and len(node.args) == 1 diff --git a/pyupgrade/_plugins/typing_text.py b/pyupgrade/_plugins/typing_text.py index f3c6ba50..031504b4 100644 --- a/pyupgrade/_plugins/typing_text.py +++ b/pyupgrade/_plugins/typing_text.py @@ -20,16 +20,11 @@ def visit_Attribute( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and isinstance(node.value, ast.Name) and node.value.id == 'typing' and node.attr == 'Text' ): - func = functools.partial( - replace_name, - name=node.attr, - new='str', - ) + func = functools.partial(replace_name, name=node.attr, new='str') yield ast_to_offset(node), func @@ -39,14 +34,6 @@ def visit_Name( node: ast.Name, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if ( - state.settings.min_version >= (3,) and - node.id in state.from_imports['typing'] and - node.id == 'Text' - ): - func = functools.partial( - replace_name, - name=node.id, - new='str', - ) + if node.id in state.from_imports['typing'] and node.id == 'Text': + func = functools.partial(replace_name, name=node.id, new='str') yield ast_to_offset(node), func diff --git a/pyupgrade/_plugins/unittest_aliases.py b/pyupgrade/_plugins/unittest_aliases.py index 1aefc8bf..6ab643b9 100644 --- a/pyupgrade/_plugins/unittest_aliases.py +++ b/pyupgrade/_plugins/unittest_aliases.py @@ -12,8 +12,7 @@ from pyupgrade._data import TokenFunc from pyupgrade._token_helpers import replace_name - -METHOD_MAPPING_PY27 = { +METHOD_MAPPING = { 'assertEquals': 'assertEqual', 'failUnlessEqual': 'assertEqual', 'failIfEqual': 'assertNotEqual', @@ -23,10 +22,6 @@ 'failUnlessRaises': 'assertRaises', 'failUnlessAlmostEqual': 'assertAlmostEqual', 'failIfAlmostEqual': 'assertNotAlmostEqual', -} - -METHOD_MAPPING_PY35_PLUS = { - **METHOD_MAPPING_PY27, 'assertNotEquals': 'assertNotEqual', 'assertAlmostEquals': 'assertAlmostEqual', 'assertNotAlmostEquals': 'assertNotAlmostEqual', @@ -48,21 +43,16 @@ def visit_Call( node: ast.Call, parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: - if state.settings.min_version >= (3,): - method_mapping = METHOD_MAPPING_PY35_PLUS - else: - method_mapping = METHOD_MAPPING_PY27 - if ( isinstance(node.func, ast.Attribute) and isinstance(node.func.value, ast.Name) and node.func.value.id == 'self' and - node.func.attr in method_mapping + node.func.attr in METHOD_MAPPING ): func = functools.partial( replace_name, name=node.func.attr, - new=f'self.{method_mapping[node.func.attr]}', + new=f'self.{METHOD_MAPPING[node.func.attr]}', ) yield ast_to_offset(node.func), func elif ( diff --git a/pyupgrade/_plugins/unpack_list_comprehension.py b/pyupgrade/_plugins/unpack_list_comprehension.py index 80effd79..fac6bdde 100644 --- a/pyupgrade/_plugins/unpack_list_comprehension.py +++ b/pyupgrade/_plugins/unpack_list_comprehension.py @@ -29,7 +29,6 @@ def visit_Assign( parent: ast.AST, ) -> Iterable[tuple[Offset, TokenFunc]]: if ( - state.settings.min_version >= (3,) and len(node.targets) == 1 and isinstance(node.targets[0], ast.Tuple) and isinstance(node.value, ast.ListComp) and diff --git a/pyupgrade/_plugins/versioned_branches.py b/pyupgrade/_plugins/versioned_branches.py index eead85b6..20e76032 100644 --- a/pyupgrade/_plugins/versioned_branches.py +++ b/pyupgrade/_plugins/versioned_branches.py @@ -110,42 +110,40 @@ def visit_If( assert len(min_version) >= 2 if ( - min_version >= (3,) and ( - # if six.PY2: + # if six.PY2: + is_name_attr( + node.test, + state.from_imports, + ('six',), + ('PY2',), + ) or + # if not six.PY3: + ( + isinstance(node.test, ast.UnaryOp) and + isinstance(node.test.op, ast.Not) and is_name_attr( - node.test, + node.test.operand, state.from_imports, ('six',), - ('PY2',), - ) or - # if not six.PY3: - ( - isinstance(node.test, ast.UnaryOp) and - isinstance(node.test.op, ast.Not) and - is_name_attr( - node.test.operand, - state.from_imports, - ('six',), - ('PY3',), - ) - ) or - # sys.version_info == 2 or < (3,) - # or < (3, n) or <= (3, n) (with n= (3,) and ( - # if six.PY3: + # if six.PY3: + is_name_attr( + node.test, + state.from_imports, + ('six',), + ('PY3',), + ) or + # if not six.PY2: + ( + isinstance(node.test, ast.UnaryOp) and + isinstance(node.test.op, ast.Not) and is_name_attr( - node.test, + node.test.operand, state.from_imports, ('six',), - ('PY3',), - ) or - # if not six.PY2: - ( - isinstance(node.test, ast.UnaryOp) and - isinstance(node.test.op, ast.Not) and - is_name_attr( - node.test.operand, - state.from_imports, - ('six',), - ('PY2',), - ) - ) or - # sys.version_info == 3 or >= (3,) or > (3,) - # sys.version_info >= (3, n) (with n<=m) - # or sys.version_info > (3, n) (with n= (3,) or > (3,) + # sys.version_info >= (3, n) (with n<=m) + # or sys.version_info > (3, n) (with n=3.2.0 python_requires = >=3.7 [options.packages.find] diff --git a/testing/generate-imports b/testing/generate-imports index 6dcb94fc..5e53d8a5 100755 --- a/testing/generate-imports +++ b/testing/generate-imports @@ -44,9 +44,7 @@ def _removals() -> dict[tuple[int, ...], dict[str, set[str]]]: removals: dict[tuple[int, ...], dict[str, set[str]]] removals = collections.defaultdict(lambda: collections.defaultdict(set)) for k, v in reorder_python_imports.REMOVALS.items(): - if k < (2, 7): - k = (2, 7) - elif k <= (3, 6): + if k <= (3, 6): k = (3,) for s in v: match = FROM_IMPORT_RE.match(s) diff --git a/tests/features/binary_literals_test.py b/tests/features/binary_literals_test.py index 1238540f..37c9e6b1 100644 --- a/tests/features/binary_literals_test.py +++ b/tests/features/binary_literals_test.py @@ -27,7 +27,7 @@ ), ) def test_binary_literals_noop(s): - assert _fix_tokens(s, min_version=(2, 7)) == s + assert _fix_tokens(s) == s @pytest.mark.parametrize( @@ -50,18 +50,7 @@ def test_binary_literals_noop(s): ' b"bar"\n' ')\n', ), - ( - 'f(\n' - ' U"foo"\n' - ' ur"bar".encode()\n' - ')\n', - - 'f(\n' - ' b"foo"\n' - ' br"bar"\n' - ')\n', - ), ), ) def test_binary_literals(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected + assert _fix_tokens(s) == expected diff --git a/tests/features/collections_abc_test.py b/tests/features/collections_abc_test.py index 7e1bc571..ee1907de 100644 --- a/tests/features/collections_abc_test.py +++ b/tests/features/collections_abc_test.py @@ -8,7 +8,7 @@ def test_collections_abc_noop(): src = 'if isinstance(x, collections.defaultdict): pass\n' - assert _fix_plugins(src, settings=Settings(min_version=(3,))) == src + assert _fix_plugins(src, settings=Settings()) == src @pytest.mark.parametrize( @@ -24,4 +24,4 @@ def test_collections_abc_noop(): ), ) def test_collections_abc_rewrite(src, expected): - assert _fix_plugins(src, settings=Settings(min_version=(3,))) == expected + assert _fix_plugins(src, settings=Settings()) == expected diff --git a/tests/features/default_encoding_test.py b/tests/features/default_encoding_test.py index 62c54a89..d5cc1930 100644 --- a/tests/features/default_encoding_test.py +++ b/tests/features/default_encoding_test.py @@ -36,7 +36,7 @@ ), ) def test_fix_encode(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -56,4 +56,4 @@ def test_fix_encode(s, expected): ), ) def test_fix_encode_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s diff --git a/tests/features/encoding_cookie_test.py b/tests/features/encoding_cookie_test.py index 43a2ee9e..6067e98a 100644 --- a/tests/features/encoding_cookie_test.py +++ b/tests/features/encoding_cookie_test.py @@ -6,20 +6,16 @@ @pytest.mark.parametrize( - ('s', 'min_version'), + 's', ( pytest.param( - '# coding: utf-8\n', (2, 7), - id='cannot remove in py2', - ), - pytest.param( - '# line 1\n# line 2\n# coding: utf-8\n', (3,), + '# line 1\n# line 2\n# coding: utf-8\n', id='only on first two lines', ), ), ) -def test_noop(s, min_version): - assert _fix_tokens(s, min_version=min_version) == s +def test_noop(s): + assert _fix_tokens(s) == s @pytest.mark.parametrize( @@ -44,4 +40,4 @@ def test_noop(s, min_version): ), ) def test_rewrite(s, expected): - assert _fix_tokens(s, min_version=(3,)) == expected + assert _fix_tokens(s) == expected diff --git a/tests/features/escape_sequences_test.py b/tests/features/escape_sequences_test.py index 2c82e136..e487a830 100644 --- a/tests/features/escape_sequences_test.py +++ b/tests/features/escape_sequences_test.py @@ -27,7 +27,7 @@ ), ) def test_fix_escape_sequences_noop(s): - assert _fix_tokens(s, min_version=(2, 7)) == s + assert _fix_tokens(s) == s @pytest.mark.parametrize( @@ -37,8 +37,8 @@ def test_fix_escape_sequences_noop(s): (r'"\d"', r'r"\d"'), # when there are valid escape sequences, need to use backslashes (r'"\n\d"', r'"\n\\d"'), - # `ur` is not a valid string prefix in python3.x - (r'u"\d"', r'u"\\d"'), + # this gets un-u'd and raw'd + (r'u"\d"', r'r"\d"'), # `rb` is not a valid string prefix in python2.x (r'b"\d"', r'br"\d"'), # 8 and 9 aren't valid octal digits @@ -56,4 +56,4 @@ def test_fix_escape_sequences_noop(s): ), ) def test_fix_escape_sequences(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected + assert _fix_tokens(s) == expected diff --git a/tests/features/extra_parens_test.py b/tests/features/extra_parens_test.py index 80f3808b..9ce0ea3c 100644 --- a/tests/features/extra_parens_test.py +++ b/tests/features/extra_parens_test.py @@ -20,7 +20,7 @@ ), ) def test_fix_extra_parens_noop(s): - assert _fix_tokens(s, min_version=(2, 7)) == s + assert _fix_tokens(s) == s @pytest.mark.parametrize( @@ -61,4 +61,4 @@ def test_fix_extra_parens_noop(s): ), ) def test_fix_extra_parens(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected + assert _fix_tokens(s) == expected diff --git a/tests/features/format_literals_test.py b/tests/features/format_literals_test.py index 0dd9c22a..aaa6ef05 100644 --- a/tests/features/format_literals_test.py +++ b/tests/features/format_literals_test.py @@ -10,8 +10,7 @@ ( # Don't touch syntax errors '"{0}"format(1)', - # Don't touch py27 format strings - "'{}'.format(1)", + pytest.param("'{}'.format(1)", id='already upgraded'), # Don't touch invalid format strings "'{'.format(1)", "'}'.format(1)", # Don't touch non-format strings @@ -29,7 +28,7 @@ ), ) def test_format_literals_noop(s): - assert _fix_tokens(s, min_version=(2, 7)) == s + assert _fix_tokens(s) == s @pytest.mark.parametrize( @@ -82,4 +81,4 @@ def test_format_literals_noop(s): ), ) def test_format_literals(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected + assert _fix_tokens(s) == expected diff --git a/tests/features/import_removals_test.py b/tests/features/import_removals_test.py index 9f794ecd..3e07103e 100644 --- a/tests/features/import_removals_test.py +++ b/tests/features/import_removals_test.py @@ -13,9 +13,6 @@ ('from foo import bar', (3,)), ('from __future__ import unknown', (3,)), ('from __future__ import annotations', (3,)), - ('from __future__ import division', (2, 7)), - ('from six.moves import map', (2, 7)), - ('from builtins import str', (2, 7)), ('from six import *', (3,)), ('from six.moves import map as notmap', (3,)), ('from unrelated import queue as map', (3,)), @@ -34,11 +31,11 @@ def test_import_removals_noop(s, min_version): @pytest.mark.parametrize( ('s', 'min_version', 'expected'), ( - ('from __future__ import generators\n', (2, 7), ''), - ('from __future__ import generators', (2, 7), ''), + ('from __future__ import generators\n', (3,), ''), + ('from __future__ import generators', (3,), ''), ('from __future__ import division\n', (3,), ''), ('from __future__ import division\n', (3, 6), ''), - ('from __future__ import (generators,)', (2, 7), ''), + ('from __future__ import (generators,)', (3,), ''), ('from __future__ import print_function', (3, 8), ''), ('from builtins import map', (3,), ''), ('from builtins import *', (3,), ''), @@ -112,7 +109,7 @@ def test_import_removals_noop(s, min_version): 'from __future__ import with_statement\n' '\n' 'import os.path\n', - (2, 7), + (3,), 'import os.path\n', id='remove top-file whitespace', ), diff --git a/tests/features/import_replaces_test.py b/tests/features/import_replaces_test.py index 8b7f72ea..386afdbf 100644 --- a/tests/features/import_replaces_test.py +++ b/tests/features/import_replaces_test.py @@ -10,11 +10,6 @@ ('s', 'min_version'), ( pytest.param('from a import b', (3,), id='unrelated import'), - pytest.param( - 'from collections import Mapping\n', - (2, 7), - id='too old min version', - ), pytest.param( 'from .xml.etree.cElementTree import XML\n', (3,), @@ -63,7 +58,7 @@ def test_mock_noop_keep_mock(): '\n' 'patch("func")' ) - settings = Settings(min_version=(3,), keep_mock=True) + settings = Settings(keep_mock=True) assert _fix_plugins(s, settings=settings) == s diff --git a/tests/features/imports_future_test.py b/tests/features/imports_future_test.py deleted file mode 100644 index e116e5a6..00000000 --- a/tests/features/imports_future_test.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -import pytest - -from pyupgrade._main import _imports_future - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( - ('', False), - ('import x', False), - ('from foo import bar', False), - ('x = 5', False), - ('from __future__ import unicode_literals', True), - ( - '"""docstring"""\n' - 'from __future__ import unicode_literals', - True, - ), - ( - 'from __future__ import absolute_import\n' - 'from __future__ import unicode_literals\n', - True, - ), - ('from .__future__ import unicode_literals\n', False), - ), -) -def test_imports_future(s, expected): - assert _imports_future(s, 'unicode_literals') is expected - - -def test_imports_future_non_unicode_literals(): - src = 'from __future__ import with_statement' - assert _imports_future(src, 'with_statement') diff --git a/tests/features/io_open_test.py b/tests/features/io_open_test.py index 4f68e4a2..84bb12d8 100644 --- a/tests/features/io_open_test.py +++ b/tests/features/io_open_test.py @@ -16,7 +16,7 @@ def test_fix_io_open_noop(): with open("f.txt") as f: print(f.read()) ''' - ret = _fix_plugins(src, settings=Settings(min_version=(3,))) + ret = _fix_plugins(src, settings=Settings()) assert ret == expected @@ -35,5 +35,5 @@ def test_fix_io_open_noop(): ), ) def test_fix_io_open(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/long_literals_test.py b/tests/features/long_literals_test.py deleted file mode 100644 index c691eaa8..00000000 --- a/tests/features/long_literals_test.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -import pytest - -from pyupgrade._main import _fix_tokens - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( - ('5L', '5'), - ('5l', '5'), - ('123456789123456789123456789L', '123456789123456789123456789'), - ), -) -def test_long_literals(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected diff --git a/tests/features/metaclass_type_test.py b/tests/features/metaclass_type_test.py index 17b6dad2..c6bf3ec1 100644 --- a/tests/features/metaclass_type_test.py +++ b/tests/features/metaclass_type_test.py @@ -31,7 +31,7 @@ ), ) def test_metaclass_type_assignment_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -63,5 +63,5 @@ def test_metaclass_type_assignment_noop(s): ), ) def test_fix_metaclass_type_assignment(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/mock_test.py b/tests/features/mock_test.py index 66c9dcd7..83dcd092 100644 --- a/tests/features/mock_test.py +++ b/tests/features/mock_test.py @@ -34,4 +34,4 @@ ), ) def test_fix_mock(s, expected): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == expected + assert _fix_plugins(s, settings=Settings()) == expected diff --git a/tests/features/native_literals_test.py b/tests/features/native_literals_test.py index 944d8ea7..a60cdcc2 100644 --- a/tests/features/native_literals_test.py +++ b/tests/features/native_literals_test.py @@ -22,7 +22,7 @@ ), ) def test_fix_native_literals_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -49,5 +49,5 @@ def test_fix_native_literals_noop(s): ), ) def test_fix_native_literals(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/new_style_classes_test.py b/tests/features/new_style_classes_test.py index 41df387d..6569b5ea 100644 --- a/tests/features/new_style_classes_test.py +++ b/tests/features/new_style_classes_test.py @@ -16,7 +16,7 @@ ), ) def test_fix_classes_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -104,5 +104,5 @@ def test_fix_classes_noop(s): ), ) def test_fix_classes(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/octal_literals_test.py b/tests/features/octal_literals_test.py deleted file mode 100644 index 008d823a..00000000 --- a/tests/features/octal_literals_test.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -import pytest - -from pyupgrade._main import _fix_tokens - - -@pytest.mark.parametrize( - 's', - ( - # Any number of zeros is considered a legal token - '0', '00', - # Don't modify non octal literals - '1', '12345', '1.2345', '1_005', - ), -) -def test_noop_octal_literals(s): - assert _fix_tokens(s, min_version=(2, 7)) == s - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( - ('0755', '0o755'), - ('05', '5'), - ), -) -def test_fix_octal_literal(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected diff --git a/tests/features/open_mode_test.py b/tests/features/open_mode_test.py index 32a2fd12..c8064bfd 100644 --- a/tests/features/open_mode_test.py +++ b/tests/features/open_mode_test.py @@ -25,7 +25,7 @@ ), ) def test_fix_open_mode_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -73,5 +73,5 @@ def test_fix_open_mode_noop(s): ), ) def test_fix_open_mode(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/oserror_aliases_test.py b/tests/features/oserror_aliases_test.py index 981f2f2e..12798a65 100644 --- a/tests/features/oserror_aliases_test.py +++ b/tests/features/oserror_aliases_test.py @@ -8,21 +8,6 @@ from pyupgrade._plugins.oserror_aliases import ERROR_NAMES -@pytest.mark.parametrize( - 's', - ( - 'raise WindowsError("test")', - - 'try:\n' - ' pass\n' - 'except WindowsError:\n' - ' pass\n', - ), -) -def test_noop_in_python_2(s): - assert _fix_plugins(s, settings=Settings()) == s - - @pytest.mark.parametrize('alias', ERROR_NAMES) @pytest.mark.parametrize( ('tpl', 'expected'), @@ -101,13 +86,14 @@ def test_noop_in_python_2(s): ) def test_fix_oserror_aliases_try(alias, tpl, expected): s = tpl.format(alias=alias) - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @pytest.mark.parametrize( 's', ( + pytest.param('raise\n', id='empty raise'), # empty try-except 'try:\n' ' pass\n' @@ -151,7 +137,7 @@ def test_fix_oserror_aliases_try(alias, tpl, expected): ), ) def test_fix_oserror_aliases_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize('imp', ERROR_MODULES) @@ -171,7 +157,7 @@ def test_fix_oserror_aliases_noop(s): ) def test_fix_oserror_aliases_noop_tpl(imp, tpl): s = tpl.format(imp=imp) - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize('imp', ERROR_MODULES) @@ -406,7 +392,7 @@ def test_fix_oserror_aliases_noop_tpl(imp, tpl): ) def test_fix_oserror_complex_aliases_try(imp, tpl, expected_tpl): s, expected = tpl.format(imp=imp), expected_tpl.format(imp=imp) - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -432,7 +418,7 @@ def test_fix_oserror_complex_aliases_try(imp, tpl, expected_tpl): ) def test_fix_oserror_aliases_raise(alias, tpl, expected): s = tpl.format(alias=alias) - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -526,5 +512,5 @@ def test_fix_oserror_aliases_raise(alias, tpl, expected): ) def test_fix_oserror_complex_aliases_raise(imp, tpl, expected_tpl): s, expected = tpl.format(imp=imp), expected_tpl.format(imp=imp) - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/raw_unicode_literals_test.py b/tests/features/raw_unicode_literals_test.py deleted file mode 100644 index 129e21bd..00000000 --- a/tests/features/raw_unicode_literals_test.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -import pytest - -from pyupgrade._main import _fix_tokens - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( - pytest.param('ur"hi"', 'u"hi"', id='basic case'), - pytest.param('UR"hi"', 'U"hi"', id='upper case raw'), - pytest.param(r'ur"\s"', r'u"\\s"', id='with an escape'), - pytest.param('ur"\\u2603"', 'u"\\u2603"', id='with unicode escapes'), - pytest.param('ur"\\U0001f643"', 'u"\\U0001f643"', id='emoji'), - ), -) -def test_fix_ur_literals(s, expected): - assert _fix_tokens(s, min_version=(2, 7)) == expected - - -def test_fix_ur_literals_gets_fixed_before_u_removed(): - assert _fix_tokens("ur'\\s\\u2603'", min_version=(3,)) == "'\\\\s\\u2603'" diff --git a/tests/features/six_b_test.py b/tests/features/six_b_test.py index 5215ba14..4f3f56bf 100644 --- a/tests/features/six_b_test.py +++ b/tests/features/six_b_test.py @@ -18,7 +18,7 @@ ), ) def test_six_b_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -47,5 +47,5 @@ def test_six_b_noop(s): ), ) def test_six_b(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/six_remove_decorators_test.py b/tests/features/six_remove_decorators_test.py index 323e44b0..882588aa 100644 --- a/tests/features/six_remove_decorators_test.py +++ b/tests/features/six_remove_decorators_test.py @@ -42,5 +42,5 @@ ), ) def test_fix_six_remove_decorators(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/six_simple_test.py b/tests/features/six_simple_test.py index a9bcf1f8..a69b3d34 100644 --- a/tests/features/six_simple_test.py +++ b/tests/features/six_simple_test.py @@ -28,7 +28,7 @@ ), ) def test_six_simple_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -95,5 +95,5 @@ def test_six_simple_noop(s): ), ) def test_fix_six_simple(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/six_test.py b/tests/features/six_test.py index 4be08a44..04f2d437 100644 --- a/tests/features/six_test.py +++ b/tests/features/six_test.py @@ -42,7 +42,7 @@ ), ) def test_fix_six_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -390,7 +390,7 @@ def test_fix_six_noop(s): ), ) def test_fix_six(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -406,7 +406,7 @@ def test_fix_six(s, expected): ), ) def test_fix_six_py38_plus(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -458,5 +458,5 @@ def test_fix_six_py38_plus(s, expected): ), ) def test_fix_base_classes(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/super_test.py b/tests/features/super_test.py index e795526c..035131c3 100644 --- a/tests/features/super_test.py +++ b/tests/features/super_test.py @@ -74,7 +74,7 @@ ), ) def test_fix_super_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -160,4 +160,4 @@ def test_fix_super_noop(s): ), ) def test_fix_super(s, expected): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == expected + assert _fix_plugins(s, settings=Settings()) == expected diff --git a/tests/features/type_of_primitive_test.py b/tests/features/type_of_primitive_test.py index f14542ad..836d3363 100644 --- a/tests/features/type_of_primitive_test.py +++ b/tests/features/type_of_primitive_test.py @@ -7,28 +7,21 @@ @pytest.mark.parametrize( - ('s', 'version'), + 's', ( - pytest.param( - 'type("")\n', - (2, 7), - id='not python 3+', - ), pytest.param( 'type(None)\n', - (3,), id='NoneType', ), pytest.param( 'foo = "foo"\n' 'type(foo)\n', - (3,), id='String assigned to variable', ), ), ) -def test_fix_type_of_primitive_noop(s, version): - assert _fix_plugins(s, settings=Settings(min_version=version)) == s +def test_fix_type_of_primitive_noop(s): + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -72,5 +65,5 @@ def test_fix_type_of_primitive_noop(s, version): ), ) def test_fix_type_of_primitive(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/typing_pep563_test.py b/tests/features/typing_pep563_test.py index fecd6a54..e6ae8bcd 100644 --- a/tests/features/typing_pep563_test.py +++ b/tests/features/typing_pep563_test.py @@ -9,66 +9,57 @@ @pytest.mark.parametrize( - ('s', 'version'), + 's', ( pytest.param( 'from typing import Literal\n' 'x: "str"\n', - (2, 7), id='missing __future__ import', ), pytest.param( 'from __future__ import annotations\n' 'x: Literal["foo", "bar"]\n', - (3,), id='Literal', ), pytest.param( 'from __future__ import annotations\n' 'x = TypeVar("x", "str")\n', - (3,), id='TypeVar', ), pytest.param( 'from __future__ import annotations\n' 'x = cast(x, "str")\n', - (3,), id='cast', ), pytest.param( 'from __future__ import annotations\n' 'X = List["MyClass"]\n', - (3,), id='Alias', ), pytest.param( 'from __future__ import annotations\n' 'X: MyCallable("X")\n', - (3,), id='Custom callable', ), pytest.param( 'from __future__ import annotations\n' 'def foo(x, *args, **kwargs): ...\n', - (3,), id='Untyped', ), pytest.param( 'from __future__ import annotations\n' 'def foo(*, inplace): ...\n', - (3,), id='Kwonly, untyped', ), pytest.param( 'from __future__ import annotations\n' 'x: Annotated[1:2] = ...\n', - (3,), id='Annotated with invalid slice', ), ), ) -def test_fix_typing_pep563_noop(s, version): - assert _fix_plugins(s, settings=Settings(min_version=version)) == s +def test_fix_typing_pep563_noop(s): + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( diff --git a/tests/features/typing_pep585_test.py b/tests/features/typing_pep585_test.py index 932819f1..93ca79b2 100644 --- a/tests/features/typing_pep585_test.py +++ b/tests/features/typing_pep585_test.py @@ -45,8 +45,7 @@ def test_noop_keep_runtime_typing(): from typing import List def f(x: List[str]) -> None: ... ''' - settings = Settings(min_version=(3,), keep_runtime_typing=True) - assert _fix_plugins(s, settings=settings) == s + assert _fix_plugins(s, settings=Settings(keep_runtime_typing=True)) == s def test_keep_runtime_typing_ignored_in_py39(): @@ -138,5 +137,5 @@ def test_fix_generic_types(s, expected): ), ) def test_fix_generic_types_future_annotations(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/typing_pep604_test.py b/tests/features/typing_pep604_test.py index 6253ffc9..5c4f648e 100644 --- a/tests/features/typing_pep604_test.py +++ b/tests/features/typing_pep604_test.py @@ -74,8 +74,7 @@ def test_noop_keep_runtime_typing(): from typing import Union def f(x: Union[int, str]) -> None: ... ''' - settings = Settings(min_version=(3,), keep_runtime_typing=True) - assert _fix_plugins(s, settings=settings) == s + assert _fix_plugins(s, settings=Settings(keep_runtime_typing=True)) == s def test_keep_runtime_typing_ignored_in_py310(): @@ -241,7 +240,7 @@ def test_fix_pep604_types(s, expected): ), ) def test_fix_generic_types_future_annotations(s, expected): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == expected + assert _fix_plugins(s, settings=Settings()) == expected # TODO: test multi-line as well diff --git a/tests/features/typing_text_test.py b/tests/features/typing_text_test.py index 739ed935..f2bc3c38 100644 --- a/tests/features/typing_text_test.py +++ b/tests/features/typing_text_test.py @@ -7,24 +7,17 @@ @pytest.mark.parametrize( - ('s', 'version'), + 's', ( - pytest.param( - 'from typing import Text\n' - 'x: Text\n', - (2, 7), - id='not python 3+', - ), pytest.param( 'class Text: ...\n' 'text = Text()\n', - (3,), id='not a type annotation', ), ), ) -def test_fix_typing_text_noop(s, version): - assert _fix_plugins(s, settings=Settings(min_version=version)) == s +def test_fix_typing_text_noop(s): + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -58,5 +51,5 @@ def test_fix_typing_text_noop(s, version): ), ) def test_fix_typing_text(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/unicode_literals_test.py b/tests/features/unicode_literals_test.py index 8aadf55f..e6680f84 100644 --- a/tests/features/unicode_literals_test.py +++ b/tests/features/unicode_literals_test.py @@ -6,40 +6,27 @@ @pytest.mark.parametrize( - ('s', 'min_version'), + 's', ( - # Syntax errors are unchanged - ('(', (2, 7)), - # Without py3-plus, no replacements - ("u''", (2, 7)), + pytest.param('(', id='syntax errors are unchanged'), # Regression: string containing newline - ('"""with newline\n"""', (3,)), + pytest.param('"""with newline\n"""', id='string containing newline'), pytest.param( 'def f():\n' ' return"foo"\n', - (3,), id='Regression: no space between return and string', ), ), ) -def test_unicode_literals_noop(s, min_version): - assert _fix_tokens(s, min_version=min_version) == s +def test_unicode_literals_noop(s): + assert _fix_tokens(s) == s @pytest.mark.parametrize( - ('s', 'min_version', 'expected'), + ('s', 'expected'), ( - # With py3-plus, it removes u prefix - ("u''", (3,), "''"), - # Importing unicode_literals also cause it to remove it - ( - 'from __future__ import unicode_literals\n' - 'u""\n', - (2, 7), - 'from __future__ import unicode_literals\n' - '""\n', - ), + pytest.param("u''", "''", id='it removes u prefix'), ), ) -def test_unicode_literals(s, min_version, expected): - assert _fix_tokens(s, min_version=min_version) == expected +def test_unicode_literals(s, expected): + assert _fix_tokens(s) == expected diff --git a/tests/features/unittest_aliases_test.py b/tests/features/unittest_aliases_test.py index 0ae33a45..cc3124e9 100644 --- a/tests/features/unittest_aliases_test.py +++ b/tests/features/unittest_aliases_test.py @@ -15,16 +15,10 @@ ' self.assertEqual(1, 1)\n', id='not a deprecated alias', ), - pytest.param( - 'class ExampleTests:\n' - ' def test_something(self):\n' - ' self.assertNotEquals(1, 2)\n', - id='not python 3+', - ), ), ) def test_fix_unittest_aliases_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(2, 7))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -39,16 +33,6 @@ def test_fix_unittest_aliases_noop(s): ' def test_something(self):\n' ' self.assertEqual(1, 1)\n', ), - ), -) -def test_fix_unittest_aliases_py27(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(2, 7))) - assert ret == expected - - -@pytest.mark.parametrize( - ('s', 'expected'), - ( ( 'class ExampleTests:\n' ' def test_something(self):\n' @@ -60,8 +44,8 @@ def test_fix_unittest_aliases_py27(s, expected): ), ), ) -def test_fix_unittest_aliases_py3(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) +def test_fix_unittest_aliases(s, expected): + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/unpack_list_comprehension_test.py b/tests/features/unpack_list_comprehension_test.py index 267b8126..a5b63443 100644 --- a/tests/features/unpack_list_comprehension_test.py +++ b/tests/features/unpack_list_comprehension_test.py @@ -7,27 +7,20 @@ @pytest.mark.parametrize( - ('s', 'version'), + 's', ( - pytest.param( - 'foo, bar, baz = [fn(x) for x in items]\n', - (2, 7), - id='not python 3+', - ), pytest.param( 'foo = [fn(x) for x in items]', - (3,), id='assignment to single variable', ), pytest.param( 'x, = [await foo for foo in bar]', - (3,), id='async comprehension', ), ), ) -def test_fix_typing_text_noop(s, version): - assert _fix_plugins(s, settings=Settings(min_version=version)) == s +def test_fix_typing_text_noop(s): + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -63,5 +56,5 @@ def test_fix_typing_text_noop(s, version): ), ) def test_fix_typing_text(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/versioned_branches_test.py b/tests/features/versioned_branches_test.py index d88c2d63..068d125f 100644 --- a/tests/features/versioned_branches_test.py +++ b/tests/features/versioned_branches_test.py @@ -47,7 +47,7 @@ ), ) def test_fix_py2_block_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s @pytest.mark.parametrize( @@ -449,7 +449,7 @@ def test_fix_py2_block_noop(s): ), ) def test_fix_py2_blocks(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected @@ -466,7 +466,7 @@ def test_fix_py2_blocks(s, expected): ), ) def test_fix_py3_only_code(s, expected): - ret = _fix_plugins(s, settings=Settings(min_version=(3,))) + ret = _fix_plugins(s, settings=Settings()) assert ret == expected diff --git a/tests/features/yield_from_test.py b/tests/features/yield_from_test.py index 0cd27757..dbc4bd4b 100644 --- a/tests/features/yield_from_test.py +++ b/tests/features/yield_from_test.py @@ -145,7 +145,7 @@ ), ) def test_fix_yield_from(s, expected): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == expected + assert _fix_plugins(s, settings=Settings()) == expected @pytest.mark.parametrize( @@ -216,7 +216,7 @@ def test_fix_yield_from(s, expected): ), ) def test_fix_yield_from_noop(s): - assert _fix_plugins(s, settings=Settings(min_version=(3,))) == s + assert _fix_plugins(s, settings=Settings()) == s def test_targets_same(): diff --git a/tests/main_test.py b/tests/main_test.py index 3a2fd641..a254573a 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -40,7 +40,7 @@ def f(): def test_main_changes_a_file(tmpdir, capsys): f = tmpdir.join('f.py') f.write('x = set((1, 2, 3))\n') - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 out, err = capsys.readouterr() assert err == f'Rewriting {f.strpath}\n' assert f.read() == 'x = {1, 2, 3}\n' @@ -67,13 +67,6 @@ def test_main_non_utf8_bytes(tmpdir, capsys): assert out == f'{f.strpath} is non-utf-8 (not supported)\n' -def test_main_py27_syntaxerror_coding(tmpdir): - f = tmpdir.join('f.py') - f.write('# -*- coding: utf-8\nset((1, 2))\n') - assert main((f.strpath,)) == 1 - assert f.read() == '# -*- coding: utf-8\n{1, 2}\n' - - def test_keep_percent_format(tmpdir): f = tmpdir.join('f.py') f.write('"%s" % (1,)') @@ -86,18 +79,16 @@ def test_keep_percent_format(tmpdir): def test_keep_mock(tmpdir): f = tmpdir.join('f.py') f.write('from mock import patch\n') - assert main((f.strpath, '--py3-plus', '--keep-mock')) == 0 + assert main((f.strpath, '--keep-mock')) == 0 assert f.read() == 'from mock import patch\n' - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 assert f.read() == 'from unittest.mock import patch\n' def test_py3_plus_argument_unicode_literals(tmpdir): f = tmpdir.join('f.py') f.write('u""') - assert main((f.strpath,)) == 0 - assert f.read() == 'u""' - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 assert f.read() == '""' @@ -108,13 +99,7 @@ def test_py3_plus_super(tmpdir): ' def f(self):\n' ' super(C, self).f()\n', ) - assert main((f.strpath,)) == 0 - assert f.read() == ( - 'class C(Base):\n' - ' def f(self):\n' - ' super(C, self).f()\n' - ) - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 assert f.read() == ( 'class C(Base):\n' ' def f(self):\n' @@ -125,18 +110,14 @@ def test_py3_plus_super(tmpdir): def test_py3_plus_new_style_classes(tmpdir): f = tmpdir.join('f.py') f.write('class C(object): pass\n') - assert main((f.strpath,)) == 0 - assert f.read() == 'class C(object): pass\n' - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 assert f.read() == 'class C: pass\n' def test_py3_plus_oserror(tmpdir): f = tmpdir.join('f.py') f.write('raise EnvironmentError(1, 2)\n') - assert main((f.strpath,)) == 0 - assert f.read() == 'raise EnvironmentError(1, 2)\n' - assert main((f.strpath, '--py3-plus')) == 1 + assert main((f.strpath,)) == 1 assert f.read() == 'raise OSError(1, 2)\n' @@ -153,7 +134,6 @@ def test_py37_plus_removes_annotations(tmpdir): f = tmpdir.join('f.py') f.write('from __future__ import generator_stop\nx = 1\n') assert main((f.strpath,)) == 0 - assert main((f.strpath, '--py3-plus')) == 0 assert main((f.strpath, '--py36-plus')) == 0 assert main((f.strpath, '--py37-plus')) == 1 assert f.read() == 'x = 1\n' @@ -168,7 +148,6 @@ def test_py38_plus_removes_no_arg_decorators(tmpdir): ' ...', ) assert main((f.strpath,)) == 0 - assert main((f.strpath, '--py3-plus')) == 0 assert main((f.strpath, '--py36-plus')) == 0 assert main((f.strpath, '--py37-plus')) == 0 assert main((f.strpath, '--py38-plus')) == 1 @@ -217,11 +196,3 @@ def test_main_stdin_with_changes(capsys): assert main(('-',)) == 1 out, err = capsys.readouterr() assert out == '{1, 2}\n' - - -def test_main_py27_mode_warning(capsys, tmpdir): - f = tmpdir.join('t.py').ensure() - assert not main((str(f),)) - out, err = capsys.readouterr() - assert out == '' - assert err == 'WARNING: pyupgrade will default to --py3-plus in 3.x\n'