Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/1645 #1693

Merged
merged 4 commits into from Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -15,6 +15,7 @@ Find out more about isort's release policy [here](https://pycqa.github.io/isort/
- Implemented #1638 / #1644: Provide a flag `--overwrite-in-place` to ensure same file handle is used after sorting.
- Implemented #1684: Added support for extending skips with `--extend-skip` and `--extend-skip-glob`.
- Implemented #1688: Auto identification and skipping of some invalid import statements.
- Implemented #1645: Ability to reverse the import sorting order.
- Documented #1685: Skip doesn't support plain directory names, but skip_glob does.

### 5.7.0 December 30th 2020
Expand Down
6 changes: 6 additions & 0 deletions isort/main.py
Expand Up @@ -562,6 +562,12 @@ def _build_arg_parser() -> argparse.ArgumentParser:
action="store_true",
help="Reverse order of relative imports.",
)
output_group.add_argument(
"--reverse-sort",
dest="reverse_sort",
action="store_true",
help="Reverses the ordering of imports.",
)
inline_args_group.add_argument(
"--sl",
"--force-single-line-imports",
Expand Down
6 changes: 5 additions & 1 deletion isort/output.py
Expand Up @@ -54,12 +54,15 @@ def sorted_imports(
key=lambda key: sorting.module_key(
key, config, section_name=section, straight_import=True
),
reverse=config.reverse_sort,
)

from_modules = parsed.imports[section]["from"]
if not config.only_sections:
from_modules = sorting.naturally(
from_modules, key=lambda key: sorting.module_key(key, config, section_name=section)
from_modules,
key=lambda key: sorting.module_key(key, config, section_name=section),
reverse=config.reverse_sort,
)

straight_imports = _with_straight_imports(
Expand Down Expand Up @@ -233,6 +236,7 @@ def _with_from_imports(
config.force_alphabetical_sort_within_sections,
section_name=section,
),
reverse=config.reverse_sort,
)
if remove_imports:
from_imports = [
Expand Down
1 change: 1 addition & 0 deletions isort/settings.py
Expand Up @@ -210,6 +210,7 @@ class _Config:
honor_case_in_force_sorted_sections: bool = False
sort_relative_in_force_sorted_sections: bool = False
overwrite_in_place: bool = False
reverse_sort: bool = False

def __post_init__(self):
py_version = self.py_version
Expand Down
6 changes: 4 additions & 2 deletions isort/sorting.py
Expand Up @@ -96,7 +96,9 @@ def section_key(line: str, config: Config) -> str:
return f"{section}{len(line) if config.length_sort else ''}{line}"


def naturally(to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None) -> List[str]:
def naturally(
to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None, reverse: bool = False
) -> List[str]:
"""Returns a naturally sorted list"""
if key is None:
key_callback = _natural_keys
Expand All @@ -105,7 +107,7 @@ def naturally(to_sort: Iterable[str], key: Optional[Callable[[str], Any]] = None
def key_callback(text: str) -> List[Any]:
return _natural_keys(key(text)) # type: ignore

return sorted(to_sort, key=key_callback)
return sorted(to_sort, key=key_callback, reverse=reverse)


def _atoi(text: str) -> Any:
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/test_ticketed_features.py
Expand Up @@ -1029,3 +1029,33 @@ def test_isort_auto_detects_and_ignores_invalid_from_imports_issue_1688():
from package3 import also_ok
"""
)


def test_isort_allows_reversing_sort_order_issue_1645():
"""isort allows reversing the sort order for those who prefer Z or longer imports first.
see: https://github.com/PyCQA/isort/issues/1688
"""
assert (
isort.code(
"""
from xxx import (
g,
hi,
def,
abcd,
)
""",
profile="black",
reverse_sort=True,
length_sort=True,
line_length=20,
)
== """
from xxx import (
abcd,
def,
hi,
g,
)
"""
)