summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Crosley <timothy.crosley@gmail.com>2020-07-14 22:16:40 -0700
committerTimothy Crosley <timothy.crosley@gmail.com>2020-07-14 22:16:40 -0700
commit36d4cc056570bc83b0c457491dbca5e4c4f45ea3 (patch)
treeedd1a4297635bbeadb3d795cfd215f0c7ae6b740
parent413f8a0f8c1cba07b2a174fdd03c8bf279198d3b (diff)
downloadisort-36d4cc056570bc83b0c457491dbca5e4c4f45ea3.tar.gz
- Implemented experimental support for floating all imports to the top of a file (issue #1228)
-rw-r--r--CHANGELOG.md1
-rw-r--r--docs/configuration/options.md26
-rw-r--r--isort/api.py30
-rw-r--r--isort/main.py11
-rw-r--r--isort/settings.py1
-rw-r--r--tests/test_ticketed_features.py117
6 files changed, 172 insertions, 14 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21f1b725..6ce6172d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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.
diff --git a/docs/configuration/options.md b/docs/configuration/options.md
index 86ad6da4..fecc8347 100644
--- a/docs/configuration/options.md
+++ b/docs/configuration/options.md
@@ -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.
@@ -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.
@@ -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
diff --git a/isort/api.py b/isort/api.py
index 3aa25dc0..6f7230ed 100644
--- a/isort/api.py
+++ b/isort/api.py
@@ -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:
diff --git a/isort/main.py b/isort/main.py
index 589db60f..48da508a 100644
--- a/isort/main.py
+++ b/isort/main.py
@@ -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",
diff --git a/isort/settings.py b/isort/settings.py
index 437cca59..68f32a66 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -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
diff --git a/tests/test_ticketed_features.py b/tests/test_ticketed_features.py
index 2709a769..4e958781 100644
--- a/tests/test_ticketed_features.py
+++ b/tests/test_ticketed_features.py
@@ -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
+"""
+)