Skip to content

Commit 4d71f32

Browse files
committed
Add order_by_qualified_sort option
Add support for hackings preferred sort order. Instead of from foo import baz from foo.bar import wow order by fully qualified paths: from foo.bar import wow from foo import baz Signed-off-by: Stephen Finucane <stephen@that.guru>
1 parent a333737 commit 4d71f32

4 files changed

Lines changed: 41 additions & 1 deletion

File tree

docs/configuration/options.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,16 @@ Order imports by type, which is determined by case, in addition to alphabeticall
803803
- --ot
804804
- --order-by-type
805805

806+
## Order By Qualified Name
807+
808+
Order imports by their full module path. That is, `from foo.bar import wow` would be ordered before `from foo import baz` (since `foo.bar.wow` < `foo.baz`).
809+
810+
**Type:** Bool
811+
**Default:** `False`
812+
**Config default:** `false`
813+
**Python & Config File Name:** order_by_qualified_name
814+
**CLI Flags:** **Not Supported**
815+
806816
## Atomic
807817

808818
Ensures the output doesn't save if the resulting file contains syntax errors.

isort/output.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,13 @@ def sorted_imports(
6666
from_modules = sorting.sort(
6767
config,
6868
from_modules,
69-
key=lambda key: sorting.module_key(key, config, section_name=section),
69+
key=lambda key: sorting.module_key(
70+
f"{key}.{min(from_modules[key])}"
71+
if config.order_by_qualified_name and from_modules[key]
72+
else key,
73+
config,
74+
section_name=section,
75+
),
7076
reverse=config.reverse_sort,
7177
)
7278

isort/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class _Config:
173173
balanced_wrapping: bool = False
174174
use_parentheses: bool = False
175175
order_by_type: bool = True
176+
order_by_qualified_name: bool = False
176177
atomic: bool = False
177178
lines_before_imports: int = -1
178179
lines_after_imports: int = -1

tests/unit/test_isort.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,6 +1676,29 @@ def test_order_by_type() -> None:
16761676
)
16771677

16781678

1679+
def test_order_by_qualified_name() -> None:
1680+
# Without option: sorted by module name ("foo" < "foo.bar")
1681+
test_input = "from foo.bar import wow\nfrom foo import baz\n"
1682+
assert isort.code(test_input, order_by_qualified_name=False) == (
1683+
"from foo import baz\nfrom foo.bar import wow\n"
1684+
)
1685+
# With option: sorted by fully qualified path ("foo.bar.wow" < "foo.baz")
1686+
assert isort.code(test_input, order_by_qualified_name=True) == (
1687+
"from foo.bar import wow\nfrom foo import baz\n"
1688+
)
1689+
# Multiple imports from the same module use the first alphabetically
1690+
test_input = "from foo import zebra\nfrom foo.bar import wow\n"
1691+
assert isort.code(test_input, order_by_qualified_name=True) == (
1692+
"from foo.bar import wow\nfrom foo import zebra\n"
1693+
)
1694+
# Multiple imports on one line: key uses the first import name alphabetically
1695+
# "from foo import qux, zebra" -> key "foo.qux" > "foo.bar.wow"
1696+
test_input = "from foo import qux, zebra\nfrom foo.bar import wow\n"
1697+
assert isort.code(test_input, order_by_qualified_name=True) == (
1698+
"from foo.bar import wow\nfrom foo import qux, zebra\n"
1699+
)
1700+
1701+
16791702
@pytest.mark.parametrize("has_body", [True, False])
16801703
def test_custom_lines_before_import_section(has_body: bool) -> None:
16811704
"""Test the case where the number of lines to output before imports has been explicitly set."""

0 commit comments

Comments
 (0)