summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Grayson <pete@jpgrayson.net>2019-03-01 16:00:08 -0500
committerPeter Grayson <pete@jpgrayson.net>2019-03-01 16:00:08 -0500
commite60c651a3e7847f406c0ee8a8eb36c96bfe24cb7 (patch)
tree1ee3993051c67f2cb7075f8dcb9cccafa39b1bcb
parentf0badf18389935b0275660f8f3ef9899dc4c4f49 (diff)
downloadisort-e60c651a3e7847f406c0ee8a8eb36c96bfe24cb7.tar.gz
Add -rr/--reverse-relative option (issue #417)
This new option changes the sort order of relative imports. The new default sort order is from furthest to closest (most dots to least dots): from ... import a from ...foo import x from .. import b from ..bar import y from . import c from .baz import z With the new -rr/--reverse-relative option, the order of the relative import *levels* (inter-order) is reversed, but the ordering within each relative import level (intra-order) remains the same (i.e. normal lexical order). from . import c from .baz import z from .. import b from ..bar import y from ... import a from ...foo import x Signed-off-by: Peter Grayson <pete@jpgrayson.net>
-rw-r--r--isort/isort.py11
-rw-r--r--isort/main.py2
-rw-r--r--isort/settings.py1
-rw-r--r--test_isort.py20
4 files changed, 26 insertions, 8 deletions
diff --git a/isort/isort.py b/isort/isort.py
index ca28d56d..a763c92c 100644
--- a/isort/isort.py
+++ b/isort/isort.py
@@ -283,13 +283,10 @@ class SortImports(object):
ignore_case: bool = False,
section_name: Optional[Any] = None
) -> str:
- dots = 0
- while module_name.startswith('.'):
- dots += 1
- module_name = module_name[1:]
-
- if dots:
- module_name = '{} {}'.format(('.' * dots), module_name)
+ match = re.match(r'^(\.+)\s*(.*)', module_name)
+ if match:
+ sep = ' ' if config['reverse_relative'] else '_'
+ module_name = sep.join(match.groups())
prefix = ""
if ignore_case:
diff --git a/isort/main.py b/isort/main.py
index a2d4b935..80dbc712 100644
--- a/isort/main.py
+++ b/isort/main.py
@@ -253,6 +253,8 @@ def parse_args(argv: Optional[Sequence[str]] = None) -> Dict[str, Any]:
parser.add_argument('-r', dest='ambiguous_r_flag', action='store_true')
parser.add_argument('-rm', '--remove-import', dest='remove_imports', action='append',
help='Removes the specified import from all files.')
+ parser.add_argument('-rr', '--reverse-relative', dest='reverse_relative', action='store_true',
+ help='Reverse order of relative imports.')
parser.add_argument('-rc', '--recursive', dest='recursive', action='store_true',
help='Recursively look for Python files of which to sort imports')
parser.add_argument('-s', '--skip', help='Files that sort imports should skip over. If you want to skip multiple '
diff --git a/isort/settings.py b/isort/settings.py
index c1d17802..815ed0a7 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -135,6 +135,7 @@ default = {'force_to_top': [],
'length_sort': False,
'add_imports': [],
'remove_imports': [],
+ 'reverse_relative': False,
'force_single_line': False,
'default_section': 'FIRSTPARTY',
'import_heading_future': '',
diff --git a/test_isort.py b/test_isort.py
index b35d6cdd..cbc0ba00 100644
--- a/test_isort.py
+++ b/test_isort.py
@@ -2729,7 +2729,7 @@ def test_comments_not_removed_issue_576():
assert SortImports(file_contents=test_input).output == test_input
-def test_inconsistent_relative_imports_issue_577():
+def test_reverse_relative_imports_issue_417():
test_input = ('from . import ipsum\n'
'from . import lorem\n'
'from .dolor import consecteur\n'
@@ -2742,6 +2742,24 @@ def test_inconsistent_relative_imports_issue_577():
'from ... import dui\n'
'from ...eu import dignissim\n'
'from ...ex import metus\n')
+ assert SortImports(file_contents=test_input,
+ force_single_line=True,
+ reverse_relative=True).output == test_input
+
+
+def test_inconsistent_relative_imports_issue_577():
+ test_input = ('from ... import diam\n'
+ 'from ... import dui\n'
+ 'from ...eu import dignissim\n'
+ 'from ...ex import metus\n'
+ 'from .. import donec\n'
+ 'from .. import euismod\n'
+ 'from ..mi import iaculis\n'
+ 'from ..nec import tempor\n'
+ 'from . import ipsum\n'
+ 'from . import lorem\n'
+ 'from .dolor import consecteur\n'
+ 'from .sit import apidiscing\n')
assert SortImports(file_contents=test_input, force_single_line=True).output == test_input