diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c9dca40..8454566 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,12 +23,12 @@ repos: rev: v2.6.0 hooks: - id: reorder-python-imports - args: [--py3-plus] + args: [--py37-plus, --add-import, 'from __future__ import annotations'] - repo: https://github.com/asottile/pyupgrade rev: v2.31.0 hooks: - id: pyupgrade - args: [--py36-plus] + args: [--py37-plus] - repo: https://github.com/asottile/add-trailing-comma rev: v2.2.1 hooks: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 61a5a11..131e765 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,10 +10,10 @@ resources: type: github endpoint: github name: asottile/azure-pipeline-templates - ref: refs/tags/v2.1.0 + ref: refs/tags/v2.4.0 jobs: - template: job--python-tox.yml@asottile parameters: - toxenvs: [pypy3, py36, py37, py38] + toxenvs: [py37, py38] os: linux diff --git a/reorder_python_imports.py b/reorder_python_imports.py index 5b462c5..e1c344e 100644 --- a/reorder_python_imports.py +++ b/reorder_python_imports.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import argparse import ast import collections @@ -10,16 +12,12 @@ import tokenize from typing import Any from typing import Callable -from typing import Dict from typing import Generator from typing import Iterable from typing import List from typing import NamedTuple -from typing import Optional from typing import Sequence -from typing import Set from typing import Tuple -from typing import Union from aspy.refactor_imports.import_obj import AbstractImportObj from aspy.refactor_imports.import_obj import import_obj_from_str @@ -44,9 +42,9 @@ class CodePartition(NamedTuple): class TopLevelImportVisitor(ast.NodeVisitor): def __init__(self) -> None: - self.top_level_import_line_numbers: List[int] = [] + self.top_level_import_line_numbers: list[int] = [] - def _visit_import(self, node: Union[ast.Import, ast.ImportFrom]) -> None: + def _visit_import(self, node: ast.Import | ast.ImportFrom) -> None: # If it's indented, we don't really care about the import. if node.col_offset == 0: self.top_level_import_line_numbers.append(node.lineno) @@ -54,7 +52,7 @@ def _visit_import(self, node: Union[ast.Import, ast.ImportFrom]) -> None: visit_Import = visit_ImportFrom = _visit_import -def get_line_offsets_by_line_no(src: str) -> List[int]: +def get_line_offsets_by_line_no(src: str) -> list[int]: # Padded so we can index with line number offsets = [0, 0] for line in src.splitlines(True): @@ -66,7 +64,7 @@ def _partitions_to_src(partitions: Iterable[CodePartition]) -> str: return ''.join(part.src for part in partitions) -def partition_source(src: str) -> List[CodePartition]: +def partition_source(src: str) -> list[CodePartition]: """Partitions source into a list of `CodePartition`s for import refactoring. """ @@ -144,7 +142,7 @@ def partition_source(src: str) -> List[CodePartition]: def combine_trailing_code_chunks( partitions: Iterable[CodePartition], -) -> List[CodePartition]: +) -> list[CodePartition]: chunks = list(partitions) NON_COMBINABLE = (CodeType.IMPORT, CodeType.PRE_IMPORT_CODE) @@ -159,7 +157,7 @@ def combine_trailing_code_chunks( def separate_comma_imports( partitions: Iterable[CodePartition], -) -> List[CodePartition]: +) -> list[CodePartition]: """Turns `import a, b` into `import a` and `import b`""" def _inner() -> Generator[CodePartition, None, None]: for partition in partitions: @@ -180,8 +178,8 @@ def _inner() -> Generator[CodePartition, None, None]: def add_imports( partitions: Iterable[CodePartition], - to_add: Tuple[str, ...] = (), -) -> List[CodePartition]: + to_add: tuple[str, ...] = (), +) -> list[CodePartition]: partitions = list(partitions) if not _partitions_to_src(partitions).strip(): return partitions @@ -198,9 +196,9 @@ def add_imports( def remove_imports( partitions: Iterable[CodePartition], - to_remove: Tuple[str, ...] = (), -) -> List[CodePartition]: - to_remove_imports: Set[AbstractImportObj] = set() + to_remove: tuple[str, ...] = (), +) -> list[CodePartition]: + to_remove_imports: set[AbstractImportObj] = set() for s in to_remove: to_remove_imports.update(import_obj_from_str(s).split_imports()) @@ -215,14 +213,14 @@ def _inner() -> Generator[CodePartition, None, None]: return list(_inner()) -def _mod_startswith(mod_parts: List[str], prefix_parts: List[str]) -> bool: +def _mod_startswith(mod_parts: list[str], prefix_parts: list[str]) -> bool: return mod_parts[:len(prefix_parts)] == prefix_parts def replace_imports( partitions: Iterable[CodePartition], to_replace: Iterable[ImportToReplace] = (), -) -> List[CodePartition]: +) -> list[CodePartition]: def _inner() -> Generator[CodePartition, None, None]: for partition in partitions: if partition.code_type is CodeType.IMPORT: @@ -276,9 +274,9 @@ def _module_to_base_modules(s: str) -> Generator[str, None, None]: def remove_duplicated_imports( partitions: Iterable[CodePartition], -) -> List[CodePartition]: - seen: Set[AbstractImportObj] = set() - seen_module_names: Set[str] = set() +) -> list[CodePartition]: + seen: set[AbstractImportObj] = set() + seen_module_names: set[str] = set() without_exact_duplicates = [] for partition in partitions: @@ -319,11 +317,11 @@ def apply_import_sorting( separate_relative: bool = False, separate_from_import: bool = False, **sort_kwargs: Any, -) -> List[CodePartition]: - pre_import_code: List[CodePartition] = [] - imports: List[CodePartition] = [] - trash: List[CodePartition] = [] - rest: List[CodePartition] = [] +) -> list[CodePartition]: + pre_import_code: list[CodePartition] = [] + imports: list[CodePartition] = [] + trash: list[CodePartition] = [] + rest: list[CodePartition] = [] for partition in partitions: { CodeType.PRE_IMPORT_CODE: pre_import_code, @@ -349,7 +347,7 @@ def apply_import_sorting( relative_imports = [] def _import_type_switches( - last_import_obj: Optional[AbstractImportObj], + last_import_obj: AbstractImportObj | None, import_obj: AbstractImportObj, ) -> bool: """Returns True if separate_from_import is True and `import_obj` is @@ -410,8 +408,8 @@ def _import_type_switches( def _get_steps( - imports_to_add: Tuple[str, ...], - imports_to_remove: Tuple[str, ...], + imports_to_add: tuple[str, ...], + imports_to_remove: tuple[str, ...], imports_to_replace: Iterable[ImportToReplace], **sort_kwargs: Any, ) -> Generator[Step, None, None]: @@ -437,8 +435,8 @@ def _most_common_line_ending(s: str) -> str: def fix_file_contents( contents: str, - imports_to_add: Tuple[str, ...] = (), - imports_to_remove: Tuple[str, ...] = (), + imports_to_add: tuple[str, ...] = (), + imports_to_remove: tuple[str, ...] = (), imports_to_replace: Iterable[ImportToReplace] = (), **sort_kwargs: Any, ) -> str: @@ -518,8 +516,8 @@ def _report_diff(contents: str, new_contents: str, filename: str) -> None: print(diff, end='') -REMOVALS: Dict[Tuple[int, ...], Set[str]] = collections.defaultdict(set) -REPLACES: Dict[Tuple[int, ...], Set[str]] = collections.defaultdict(set) +REMOVALS: dict[tuple[int, ...], set[str]] = collections.defaultdict(set) +REPLACES: dict[tuple[int, ...], set[str]] = collections.defaultdict(set) REMOVALS[(3,)].add('from io import open') @@ -795,7 +793,7 @@ def _validate_replace_import(s: str) -> ImportToReplace: return orig_mod.split('.'), new_mod.split('.'), attr -def main(argv: Optional[Sequence[str]] = None) -> int: +def main(argv: Sequence[str] | None = None) -> int: parser = argparse.ArgumentParser() parser.add_argument( 'filenames', nargs='*', diff --git a/setup.cfg b/setup.cfg index eba686a..4a5be09 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,7 +13,6 @@ classifiers = License :: OSI Approved :: MIT License Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 @@ -25,7 +24,7 @@ classifiers = py_modules = reorder_python_imports install_requires = aspy.refactor-imports>=2.1.0 -python_requires = >=3.6.1 +python_requires = >=3.7 [options.entry_points] console_scripts = diff --git a/setup.py b/setup.py index 8bf1ba9..3d93aef 100644 --- a/setup.py +++ b/setup.py @@ -1,2 +1,4 @@ +from __future__ import annotations + from setuptools import setup setup() diff --git a/testing/generate-future-info b/testing/generate-future-info index 8c6650b..4592268 100755 --- a/testing/generate-future-info +++ b/testing/generate-future-info @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -import __future__ +from __future__ import annotations +import __future__ # noreorder import collections import os.path import sys diff --git a/testing/generate-mock-info b/testing/generate-mock-info index 12daef5..430fa53 100755 --- a/testing/generate-mock-info +++ b/testing/generate-mock-info @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os import sys import unittest.mock diff --git a/testing/generate-python-future-info b/testing/generate-python-future-info index 23570fc..1ead33c 100755 --- a/testing/generate-python-future-info +++ b/testing/generate-python-future-info @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import builtins import os.path import sys diff --git a/testing/generate-six-info b/testing/generate-six-info index 5fac8d7..eabcf07 100755 --- a/testing/generate-six-info +++ b/testing/generate-six-info @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os.path import sys diff --git a/testing/generate-typing-pep585-rewrites b/testing/generate-typing-pep585-rewrites index 0ec7f02..3b38e48 100755 --- a/testing/generate-typing-pep585-rewrites +++ b/testing/generate-typing-pep585-rewrites @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os.path import sys import typing.re diff --git a/testing/generate-typing-rewrite-info b/testing/generate-typing-rewrite-info index 65c91c3..725e52c 100755 --- a/testing/generate-typing-rewrite-info +++ b/testing/generate-typing-rewrite-info @@ -1,11 +1,9 @@ #!/usr/bin/env python3 +from __future__ import annotations + import os import sys from collections import defaultdict -from typing import Dict -from typing import List -from typing import Set -from typing import Tuple import flake8_typing_imports import mypy_extensions @@ -30,7 +28,7 @@ def main() -> int: ) # some attrs are removed and then added back - min_contiguous_versions: Dict[str, flake8_typing_imports.Version] = {} + min_contiguous_versions: dict[str, flake8_typing_imports.Version] = {} for v, attrs in flake8_typing_imports.SYMBOLS: for removed in set(min_contiguous_versions) - attrs: del min_contiguous_versions[removed] @@ -38,27 +36,27 @@ def main() -> int: for attr in attrs: min_contiguous_versions.setdefault(attr, v) - symbols: Dict[flake8_typing_imports.Version, Set[str]] = defaultdict(set) + symbols: dict[flake8_typing_imports.Version, set[str]] = defaultdict(set) for a, v in min_contiguous_versions.items(): symbols[v].add(a) # --pyXX-plus assumes the min --pyXX so group symbols by their # rounded up major version - symbols_rounded_up: Dict[Tuple[int, int], Set[str]] = defaultdict(set) + symbols_rounded_up: dict[tuple[int, int], set[str]] = defaultdict(set) for v, attrs in sorted(symbols.items()): symbols_rounded_up[v.major, v.minor + int(v.patch != 0)] |= attrs - # combine 3.5 and 3.6 because this lib is 3.6.1+ + # combine 3.5 and 3.6 because this lib is 3.7+ symbols_rounded_up[(3, 6)] |= symbols_rounded_up.pop((3, 5)) - deltas: Dict[Tuple[int, int], Set[str]] = defaultdict(set) - prev: Set[str] = set() + deltas: dict[tuple[int, int], set[str]] = defaultdict(set) + prev: set[str] = set() for v, attrs in sorted(symbols_rounded_up.items()): deltas[v] = attrs - prev prev = attrs - mypy_extensions_added: Dict[Tuple[int, int], List[str]] = {} - typing_extensions_added: Dict[Tuple[int, int], List[str]] = {} + mypy_extensions_added: dict[tuple[int, int], list[str]] = {} + typing_extensions_added: dict[tuple[int, int], list[str]] = {} for v, attrs in deltas.items(): mypy_extensions_added[v] = sorted(attrs & mypy_extensions_all) typing_extensions_added[v] = sorted(attrs & typing_extensions_all) diff --git a/tests/reorder_python_imports_test.py b/tests/reorder_python_imports_test.py index 4802ee2..c15d62c 100644 --- a/tests/reorder_python_imports_test.py +++ b/tests/reorder_python_imports_test.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import ast import io import os diff --git a/tox.ini b/tox.ini index 143687a..5f66e9f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py36,py37,py38,pypy3,pre-commit +envlist = py37,py38,pypy3,pre-commit [testenv] deps = -rrequirements-dev.txt