Skip to content

Commit

Permalink
Merge pull request #1756 from bobwalker99/issue/1732/custom-sort
Browse files Browse the repository at this point in the history
1732 adds sort_order allowing pythonic sort as an option
  • Loading branch information
timothycrosley authored Jun 20, 2021
2 parents 4508b1a + 9bfcfa8 commit 3de1890
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 7 deletions.
11 changes: 11 additions & 0 deletions docs/configuration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,17 @@ Tells isort to overwrite in place using the same file handle.Comes at a performa

- --overwrite-in-place

## Sorting Order

Use natural language or pythonic sorting. Valid values "default"=natural "pythonic"=python default sorting.

**Type:** String
**Default:** `default`
**Python & Config File Name:** sort_order
**CLI Flags:**

- --sort-order

## Reverse Sort

Reverses the ordering of imports.
Expand Down
6 changes: 6 additions & 0 deletions isort/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,12 @@ def _build_arg_parser() -> argparse.ArgumentParser:
action="store_true",
help="Reverses the ordering of imports.",
)
output_group.add_argument(
"--sort-order",
dest="sort_order",
choices=["default", "pythonic"],
help="Use natural language or pythonic sorting.",
)
inline_args_group.add_argument(
"--sl",
"--force-single-line-imports",
Expand Down
18 changes: 11 additions & 7 deletions isort/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ def sorted_imports(
for section in sections:
straight_modules = parsed.imports[section]["straight"]
if not config.only_sections:
straight_modules = sorting.naturally(
straight_modules = sorting.sort(
config,
straight_modules,
key=lambda key: sorting.module_key(
key, config, section_name=section, straight_import=True
Expand All @@ -59,7 +60,8 @@ def sorted_imports(

from_modules = parsed.imports[section]["from"]
if not config.only_sections:
from_modules = sorting.naturally(
from_modules = sorting.sort(
config,
from_modules,
key=lambda key: sorting.module_key(key, config, section_name=section),
reverse=config.reverse_sort,
Expand Down Expand Up @@ -105,7 +107,8 @@ def sorted_imports(
else:
new_section_output.append(line)
# only_sections options is not imposed if force_sort_within_sections is True
new_section_output = sorting.naturally(
new_section_output = sorting.sort(
config,
new_section_output,
key=partial(sorting.section_key, config=config),
reverse=config.reverse_sort,
Expand Down Expand Up @@ -238,7 +241,8 @@ def _with_from_imports(
not config.no_inline_sort
or (config.force_single_line and module not in config.single_line_exclusions)
) and not config.only_sections:
from_imports = sorting.naturally(
from_imports = sorting.sort(
config,
from_imports,
key=lambda key: sorting.module_key(
key,
Expand Down Expand Up @@ -266,7 +270,7 @@ def _with_from_imports(
if not config.no_inline_sort:
for as_import in as_imports:
if not config.only_sections:
as_imports[as_import] = sorting.naturally(as_imports[as_import])
as_imports[as_import] = sorting.sort(config, as_imports[as_import])
for from_import in copy.copy(from_imports):
if from_import in as_imports:
idx = from_imports.index(from_import)
Expand Down Expand Up @@ -337,7 +341,7 @@ def _with_from_imports(
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
)
for as_import in sorting.naturally(as_imports[from_import])
for as_import in sorting.sort(config, as_imports[from_import])
)

else:
Expand All @@ -360,7 +364,7 @@ def _with_from_imports(
from_import = from_imports.pop(0)

if not config.only_sections:
as_imports[from_import] = sorting.naturally(as_imports[from_import])
as_imports[from_import] = sorting.sort(config, as_imports[from_import])
from_comments = (
parsed.categorized_comments["straight"].get(f"{module}.{from_import}") or []
)
Expand Down
1 change: 1 addition & 0 deletions isort/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ class _Config:
git_ignore: Dict[Path, Set[Path]] = field(default_factory=dict)
format_error: str = "{error}: {message}"
format_success: str = "{success}: {message}"
sort_order: str = "default"

def __post_init__(self) -> None:
py_version = self.py_version
Expand Down
12 changes: 12 additions & 0 deletions isort/sorting.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ def section_key(line: str, config: Config) -> str:
return f"{section}{len(line) if config.length_sort else ''}{line}"


def sort(
config: Config,
to_sort: Iterable[str],
key: Optional[Callable[[str], Any]] = None,
reverse: bool = False,
) -> List[str]:
sorting_func: Callable[..., List[str]] = naturally
if config.sort_order == "pythonic":
sorting_func = sorted
return sorting_func(to_sort, key=key, reverse=reverse)


def naturally(
to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None, reverse: bool = False
) -> List[str]:
Expand Down
19 changes: 19 additions & 0 deletions tests/unit/test_isort.py
Original file line number Diff line number Diff line change
Expand Up @@ -5236,3 +5236,22 @@ def seekable(self):
test_input = NonSeekableTestStream("import m2\n" "import m1\n" "not_import = 7")
identified_imports = list(map(str, api.find_imports_in_stream(test_input)))
assert identified_imports == [":1 import m2", ":2 import m1"]


def test_sort_pythonic() -> None:
""" Test a plugged-in default python sort with packages/modules containing numbers. """
test_input = (
"from bob2.apples2 import aardvark as aardvark2\n"
"from bob.apples import aardvark \n"
"import module9\n"
"import module10\n"
"import module200\n"
)
test_output = isort.code(test_input, sort_order="pythonic")
assert test_output == (
"import module10\n"
"import module200\n"
"import module9\n"
"from bob.apples import aardvark\n"
"from bob2.apples2 import aardvark as aardvark2\n"
)

0 comments on commit 3de1890

Please sign in to comment.