Skip to content

Commit

Permalink
Implemented support for automatic redundant alias removal (issue #1281).
Browse files Browse the repository at this point in the history
  • Loading branch information
timothycrosley committed Jul 14, 2020
1 parent 95dab39 commit 56baaee
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ NOTE: isort follows the [semver](https://semver.org/) versioning standard.

### 5.1.0 July TBD, 2020
- isort now throws an exception if an invalid settings path is given (issue #1174).
- Implemented support for automatic redundant alias removal (issue #1281).
- Fixed #1178: support for semicolons in decorators.
- Fixed #1315: Extra newline before comment with -n + --fss.

**Formatting changes implied:**
- Fixed #1280: rewrite of as imports changes the behavior of the imports.

Expand Down
8 changes: 4 additions & 4 deletions isort/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ def git_hook(strict: bool = False, modify: bool = False) -> int:
staged_contents = get_output(staged_cmd)

try:
if not api.check_code_string(staged_contents,
file_path=Path(filename),
config=config):
if not api.check_code_string(
staged_contents, file_path=Path(filename), config=config
):
errors += 1
if modify:
api.sort_file(filename, config=config)
except exceptions.FileSkipComment:
except exceptions.FileSkipped: # pragma: no cover
pass

return errors if strict else 0
10 changes: 10 additions & 0 deletions isort/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,16 @@ def _build_arg_parser() -> argparse.ArgumentParser:
action="store_true",
help="Tells isort to honor noqa comments to enforce skipping those comments.",
)
parser.add_argument(
"--remove-redundant-aliases",
dest="remove_redundant_aliases",
action="store_true",
help=(
"Tells isort to remove redundant aliases from imports, such as import os as os."
" This defaults to false simply because some projects use these seemingly useless alias"
" to signify intent and change behaviour."
),
)

# deprecated options
parser.add_argument(
Expand Down
11 changes: 8 additions & 3 deletions isort/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,19 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
while "as" in just_imports:
as_index = just_imports.index("as")
if type_of_import == "from":
module = just_imports[0] + "." + just_imports[as_index - 1]
nested_module = just_imports[as_index - 1]
module = just_imports[0] + "." + nested_module
as_name = just_imports[as_index + 1]
if as_name not in as_map["from"][module]:
if nested_module == as_name and config.remove_redundant_aliases:
pass
elif as_name not in as_map["from"][module]:
as_map["from"][module].append(as_name)
else:
module = just_imports[as_index - 1]
as_name = just_imports[as_index + 1]
if as_name not in as_map["straight"][module]:
if module == as_name and config.remove_redundant_aliases:
pass
elif as_name not in as_map["straight"][module]:
as_map["straight"][module].append(as_name)
if not config.combine_as_imports:
categorized_comments["straight"][module] = comments
Expand Down
1 change: 1 addition & 0 deletions isort/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class _Config:
honor_noqa: bool = False
src_paths: FrozenSet[Path] = frozenset()
old_finders: bool = False
remove_redundant_aliases: bool = False

def __post_init__(self):
py_version = self.py_version
Expand Down
14 changes: 13 additions & 1 deletion tests/test_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from io import BytesIO
from unittest.mock import MagicMock, patch

from isort import hooks
from isort import exceptions, hooks


def test_git_hook(src_dir):
Expand All @@ -26,3 +26,15 @@ class FakeProcessResponse(object):
with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock:
with patch("isort.api", MagicMock(return_value=False)):
hooks.git_hook(modify=True)

# Test with skipped file returned from git
with patch(
"isort.hooks.get_lines", MagicMock(return_value=[os.path.join(src_dir, "main.py")])
) as run_mock:

class FakeProcessResponse(object):
stdout = b"# isort: skip-file\nimport b\nimport a\n"

with patch("subprocess.run", MagicMock(return_value=FakeProcessResponse())) as run_mock:
with patch("isort.api", MagicMock(side_effect=exceptions.FileSkipped("", ""))):
hooks.git_hook(modify=True)
13 changes: 13 additions & 0 deletions tests/test_ticketed_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,16 @@ def test_thing(): pass
""",
show_diff=True,
)


def test_isort_automatically_removes_duplicate_aliases_issue_1193():
"""Test to ensure isort can automatically remove duplicate aliases.
See: https://github.com/timothycrosley/isort/issues/1281
"""
assert isort.check_code("from urllib import parse as parse\n", show_diff=True)
assert (
isort.code("from urllib import parse as parse", remove_redundant_aliases=True)
== "from urllib import parse\n"
)
assert isort.check_code("import os as os\n", show_diff=True)
assert isort.code("import os as os", remove_redundant_aliases=True) == "import os\n"

0 comments on commit 56baaee

Please sign in to comment.