Skip to content

Commit

Permalink
- Implemented experimental support for floating all imports to the to…
Browse files Browse the repository at this point in the history
…p of a file (issue #1228)
  • Loading branch information
timothycrosley committed Jul 15, 2020
1 parent 413f8a0 commit 36d4cc0
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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).
- Implemented experimental support for floating all imports to the top of a file (issue #1228)
- Fixed #1178: support for semicolons in decorators.
- Fixed #1315: Extra newline before comment with -n + --fss.
- Fixed #1192: `-k` or `--keep-direct-and-as-imports` option has been deprecated as it is now always on.
Expand Down
26 changes: 13 additions & 13 deletions docs/configuration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,18 +468,6 @@ Ensures that if a star import is present, nothing else is imported from that nam
- --cs
- --combine-star

## Keep Direct And As Imports

Turns off default behavior that removes direct imports when as imports exist.

**Type:** Bool
**Default:** `True`
**Python & Config File Name:** keep_direct_and_as_imports
**CLI Flags:**

- -k
- --keep-direct-and-as

## Include Trailing Comma

Includes a trailing comma on multi line imports that include parentheses.
Expand Down Expand Up @@ -762,6 +750,17 @@ Tells isort to remove redundant aliases from imports, such as `import os as os`.

- --remove-redundant-aliases

## Float To Top

Causes all non indented imports to float to the top of the file having its imports sorted. *NOTE*: This is a **beta** feature. It currently doesn't work with cimports and is gauranteed to run much slower and use much more memory than the default. Still it can be a great shortcut for collecting imports every once in a while when you put them in the middle of a file.

**Type:** Bool
**Default:** `False`
**Python & Config File Name:** float_to_top
**CLI Flags:**

- --float-to-top

## Check

Checks the file for unsorted / unformatted imports and prints them to the command line without modifying the file.
Expand Down Expand Up @@ -923,4 +922,5 @@ See isort's determined config, as well as sources of config options.
**Python & Config File Name:** **Not Supported**
**CLI Flags:**

- --apply
- -k
- --keep-direct-and-as
30 changes: 30 additions & 0 deletions isort/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,36 @@ def _sort_imports(
cimports: bool = False
made_changes: bool = False

if config.float_to_top:
new_input = ""
current = ""
isort_off = False
for line in chain(input_stream, (None,)):
if isort_off and line is not None:
if line == "# isort: on\n":
isort_off = False
new_input += line
elif line in ("# isort: split\n", "# isort: off\n", None):
if line == "# isort: off\n":
isort_off = True
if current:
parsed = parse.file_contents(current, config=config)
extra_space = ""
while current[-1] == "\n":
extra_space += "\n"
current = current[:-1]
extra_space = extra_space.replace("\n", "", 1)
new_input += output.sorted_imports(
parsed, config, extension, import_type="import"
)
new_input += extra_space
current = ""
new_input += line or ""
else:
current += line or ""

input_stream = StringIO(new_input)

for index, line in enumerate(chain(input_stream, (None,))):
if line is None:
if index == 0 and not config.force_adds:
Expand Down
11 changes: 10 additions & 1 deletion isort/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,16 @@ def _build_arg_parser() -> argparse.ArgumentParser:
" aliases to signify intent and change behaviour."
),
)

parser.add_argument(
"--float-to-top",
dest="float_to_top",
action="store_true",
help="Causes all non indented imports to float to the top of the file having its imports "
"sorted. *NOTE*: This is a **beta** feature. It currently doesn't work with cimports and "
"is gauranteed to run much slower and use much more memory than the default. Still it "
"can be a great shortcut for collecting imports every once in a while when you put them "
"in the middle of a file.",
)
# deprecated options
parser.add_argument(
"--recursive",
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:
src_paths: FrozenSet[Path] = frozenset()
old_finders: bool = False
remove_redundant_aliases: bool = False
float_to_top: bool = False

def __post_init__(self):
py_version = self.py_version
Expand Down
117 changes: 117 additions & 0 deletions tests/test_ticketed_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,120 @@ def test_isort_automatically_removes_duplicate_aliases_issue_1193():
)
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"


def test_isort_enables_floating_imports_to_top_of_module_issue_1228():
"""Test to ensure isort will allow floating all non-indented imports to the top of a file.
See: https://github.com/timothycrosley/isort/issues/1228.
"""
assert (
isort.code(
"""
import os
def my_function_1():
pass
import sys
def my_function_2():
pass
""",
float_to_top=True,
)
== """
import os
import sys
def my_function_1():
pass
def my_function_2():
pass
"""
)

assert (
isort.code(
"""
import os
def my_function_1():
pass
# isort: split
import sys
def my_function_2():
pass
""",
float_to_top=True,
)
== """
import os
def my_function_1():
pass
# isort: split
import sys
def my_function_2():
pass
"""
)


assert (
isort.code(
"""
import os
def my_function_1():
pass
# isort: off
import b
import a
def y():
pass
# isort: on
import b
def my_function_2():
pass
import a
""",
float_to_top=True,
)
== """
import os
def my_function_1():
pass
# isort: off
import b
import a
def y():
pass
# isort: on
import a
import b
def my_function_2():
pass
"""
)

0 comments on commit 36d4cc0

Please sign in to comment.