reorder_python_imports
Tool for automatically reordering python imports. Similar to isort
but uses static analysis more.
Installation
pip install reorder-python-imports
Console scripts
Consult reorder-python-imports --help
for the full set of options.
reorder-python-imports
takes filenames as positional arguments
Common options:
--py##-plus
: see below.--add-import
/--remove-import
: see below.--replace-import
: see below.--application-directories
: by default,reorder-python-imports
assumes your project is rooted at.
. If this isn't true, tell it where your import roots live. For example, when using the popular./src
layout you'd use--application-directories=.:src
(note: multiple paths are separated using a:
).--unclassifiable-application-module
: (may be specified multiple times) modules names that are considered application modules. this setting is intended to be used for things like C modules which may not always appear on the filesystem.
As a pre-commit hook
See pre-commit for instructions
Sample .pre-commit-config.yaml
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.6.0
hooks:
- id: reorder-python-imports
What does it do?
Separates imports into three sections
import sys
import pyramid
import reorder_python_imports
becomes (stdlib, third party, first party)
import sys
import pyramid
import reorder_python_imports
import
imports before from
imports
from os import path
import sys
becomes
import sys
from os import path
from
imports
Splits from os.path import abspath, exists
becomes
from os.path import abspath
from os.path import exists
Removes duplicate imports
import os
import os.path
import sys
import sys
becomes
import os.path
import sys
# noreorder
Using Lines containing and after lines which contain a # noreorder
comment will be ignored. Additionally any imports that appear after non-whitespace non-comment lines will be ignored.
For instance, these will not be changed:
import sys
try: # not import, not whitespace
import foo
except ImportError:
pass
import sys
import reorder_python_imports
import matplotlib # noreorder
matplotlib.use('Agg')
import matplotlib.pyplot as plt
# noreorder
import sys
import pyramid
import reorder_python_imports
why this style?
The style chosen by reorder-python-imports
has a single aim: reduce merge conflicts.
By having a single import per line, multiple contributors can add / remove imports from a single module without resulting in a conflict.
Consider the following example which causes a merge conflict:
# developer 1
-from typing import Dict, List
+from typing import Any, Dict, List
# developer 2
-from typing import Dict, List
+from typing import Dict, List, Tuple
no conflict with the style enforced by reorder-python-imports
:
+from typing import Any
from typing import Dict
from typing import List
+from typing import Tuple
Adding / Removing Imports
Let's say I want to enforce absolute_import
across my codebase. I can use: --add-import 'from __future__ import absolute_import'
.
$ cat test.py
print('Hello world')
$ reorder-python-imports --add-import 'from __future__ import absolute_import' test.py
Reordering imports in test.py
$ cat test.py
from __future__ import absolute_import
print('Hello world')
Let's say I no longer care about supporting Python 2.5, I can remove from __future__ import with_statement
with --remove-import 'from __future__ import with_statement'
$ cat test.py
from __future__ import with_statement
with open('foo.txt', 'w') as foo_f:
foo_f.write('hello world')
$ reorder-python-imports --remove-import 'from __future__ import with_statement' test.py
Reordering imports in test.py
$ cat test.py
with open('foo.txt', 'w') as foo_f:
foo_f.write('hello world')
Replacing imports
Imports can be replaced with others automatically (if they provide the same names). This can be useful for factoring out compatibility libraries such as six
(see below for automated six
rewriting).
This rewrite avoids NameError
s as such it only occurs when:
- the imported symbol is the same before and after
- the import is a
from
import
The argument is specified as orig.mod=new.mod
or with an optional checked attribute orig.mod=new.mod:attr
. The checked attribute is useful for renaming some imports from a module instead of a full module.
For example:
# full module move
--replace-import six.moves.queue=queue
# specific attribute move
--replace-import six.moves=io:StringIO
__future__
imports
Removing obsolete The cli provides a few options to help "burn the bridges" with old python versions by removing __future__
imports automatically. Each option implies all older versions.
--py22-plus
:nested_scopes
--py23-plus
:generators
--py26-plus
:with_statement
--py3-plus
:division
,absolute_import
,print_function
,unicode_literals
--py37-plus
:generator_stop
six
imports
Removing / rewriting obsolete With --py3-plus
, reorder-python-imports
will also remove / rewrite imports from six
. Rewrites follow the same rules as replacing imports above.
For example:
+import queue
+from io import StringIO
+from urllib.parse import quote_plus
+
import six.moves.urllib.parse
-from six.moves import queue
-from six.moves import range
-from six.moves import StringIO
-from six.moves.urllib.parse import quote_plus
Rewriting mock imports
With --py3-plus
, reorder-python-imports
will also rewrite various mock
imports:
-from mock import patch
+from unittest.mock import patch
mypy_extensions
and typing_extension
imports
Rewriting With --py36-plus
and higher, reorder-python-imports
will also rewrite mypy_extensions
and typing_extensions
imports ported to typing
.
-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.
-from typing import Sequence
+from collections.abc import Sequence