From 846455bfd90e0b6d46f1d95ed943b13eee2db85c Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 15 Jan 2021 15:07:30 -0800 Subject: [PATCH] rewrite pep 585 imports with --py39-plus --- README.md | 16 +++++++++-- reorder_python_imports.py | 36 +++++++++++++++++++++++++ testing/generate-typing-pep585-rewrites | 35 ++++++++++++++++++++++++ tests/reorder_python_imports_test.py | 7 +++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100755 testing/generate-typing-pep585-rewrites diff --git a/README.md b/README.md index d7cd72a..f7cffe6 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,7 @@ all older versions. - `--py3-plus`: `division`, `absolute_import`, `print_function`, `unicode_literals` - `--py37-plus`: `generator_stop` +- `--py310-plus`: `annotations` ## Removing / rewriting obsolete `six` imports @@ -277,10 +278,21 @@ With `--py3-plus`, `reorder-python-imports` will also rewrite various `mock` imp ## Rewriting `mypy_extensions` and `typing_extension` imports With `--py36-plus` and higher, `reorder-python-imports` will also rewrite -`mypy_extensions` and `typing_extensions` imports ported to `typing`. Each option -implies all older versions. +`mypy_extensions` and `typing_extensions` imports ported to `typing`. ```diff -from mypy_extensions import TypedDict +from typing import TypedDict ``` + +## Rewriting pep 585 typing imports + +With `--py39-plus` and higher, `reorder-python-imports` will replace imports +which were moved out of the typing module in [pep 585]. + +```diff +-from typing import Sequence ++from collections.abc import Sequence +``` + +[pep 585]: https://www.python.org/dev/peps/pep-0585/ diff --git a/reorder_python_imports.py b/reorder_python_imports.py index e9f8012..7f558c1 100644 --- a/reorder_python_imports.py +++ b/reorder_python_imports.py @@ -583,6 +583,42 @@ def _report_diff(contents: str, new_contents: str, filename: str) -> None: )) # END GENERATED +# GENERATED VIA generate-typing-pep585-rewrites +REPLACES[(3, 9)].update(( + 'typing=collections.abc:AsyncGenerator', + 'typing=collections.abc:AsyncIterable', + 'typing=collections.abc:AsyncIterator', + 'typing=collections.abc:Awaitable', + 'typing=collections.abc:ByteString', + 'typing=collections.abc:Callable', + 'typing=collections.abc:Collection', + 'typing=collections.abc:Container', + 'typing=collections.abc:Coroutine', + 'typing=collections.abc:Generator', + 'typing=collections.abc:Hashable', + 'typing=collections.abc:ItemsView', + 'typing=collections.abc:Iterable', + 'typing=collections.abc:Iterator', + 'typing=collections.abc:KeysView', + 'typing=collections.abc:Mapping', + 'typing=collections.abc:MappingView', + 'typing=collections.abc:MutableMapping', + 'typing=collections.abc:MutableSequence', + 'typing=collections.abc:MutableSet', + 'typing=collections.abc:Reversible', + 'typing=collections.abc:Sequence', + 'typing=collections.abc:Sized', + 'typing=collections.abc:ValuesView', + 'typing=collections:ChainMap', + 'typing=collections:Counter', + 'typing=collections:OrderedDict', + 'typing=re:Match', + 'typing=re:Pattern', + 'typing.re=re:Match', + 'typing.re=re:Pattern', +)) +# END GENERATED + # GENERATED VIA generate-python-future-info # Using future==0.18.2 REMOVALS[(3,)].update(( diff --git a/testing/generate-typing-pep585-rewrites b/testing/generate-typing-pep585-rewrites new file mode 100755 index 0000000..983352d --- /dev/null +++ b/testing/generate-typing-pep585-rewrites @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +import os.path +import sys +import typing.re + + +def main() -> int: + assert sys.version_info[:2] == (3, 9), sys.version_info + + renames = [ + f'typing={value.__origin__.__module__}:{name}' + for name, value in vars(typing).items() + if hasattr(value, '__origin__') + # TODO: still can't support symbol renaming + if value.__origin__.__name__ == name + ] + [ + f'typing.re={value.__origin__.__module__}:{name}' + for name, value in vars(typing.re).items() + if hasattr(value, '__origin__') + # TODO: still can't support symbol renaming + if value.__origin__.__name__ == name + ] + + print(f'# GENERATED VIA {os.path.basename(sys.argv[0])}') + print('REPLACES[(3, 9)].update((') + for rename in sorted(renames, key=lambda s: s.split('=')): + print(f' {rename!r},') + print('))') + print('# END GENERATED') + + return 0 + + +if __name__ == '__main__': + exit(main()) diff --git a/tests/reorder_python_imports_test.py b/tests/reorder_python_imports_test.py index 67979c5..fedc0fc 100644 --- a/tests/reorder_python_imports_test.py +++ b/tests/reorder_python_imports_test.py @@ -1057,6 +1057,13 @@ def test_py38_plus_rewrites_mypy_extensions_import(tmpdir): assert f.read() == 'from typing import TypedDict\n' +def test_py39_plus_rewrites_pep585_imports(tmpdir): + f = tmpdir.join('f.py') + f.write('from typing import Sequence\n') + assert main((str(f), '--py39-plus')) + assert f.read() == 'from collections.abc import Sequence\n' + + @pytest.mark.parametrize('opt', ('--add-import', '--remove-import')) @pytest.mark.parametrize('s', ('syntax error', '"import os"')) def test_invalid_add_remove_syntaxes(tmpdir, capsys, opt, s):