Repository: timothycrosley/isort
Pull request #642 (2018-01-24 23:10:32)

Fix606
Added parameter -k that will suppress default behavior of treating as imports (import Xxx as x) as superseding any other import of the same module, thereby removing it.   This parameter will keep all imports.

import os as _os
import os

By default, this will return:

import os as _os

With this parameter set, it will return

import os
import os as _os


Patch:
diff --git a/ACKNOWLEDGEMENTS.md b/ACKNOWLEDGEMENTS.md
index 69ea03a3..e59a24b1 100644
--- a/ACKNOWLEDGEMENTS.md
+++ b/ACKNOWLEDGEMENTS.md
@@ -71,8 +71,6 @@ Code Contributors
 - Adam Chainz (@adamchainz)
 - @Brightcells
 - Jonas Trappenberg (@teeberg)
-- Andrew Konstantaras (@akonsta)
-- Jason Brackman (@jasonbrackman) 
 
 Documenters
 ===================
diff --git a/isort/isort.py b/isort/isort.py
index 6040d60f..c952557d 100644
--- a/isort/isort.py
+++ b/isort/isort.py
@@ -278,9 +278,10 @@ class SortImports(object):
         stdlib_lib_prefix = os.path.normcase(sysconfig.get_paths()['stdlib'])
 
         for prefix in paths:
+            module_path = "/".join((prefix, module_name.replace(".", "/")))
             package_path = "/".join((prefix, module_name.split(".")[0]))
-            is_module = (exists_case_sensitive(package_path + ".py") or
-                         exists_case_sensitive(package_path + ".so"))
+            is_module = (exists_case_sensitive(module_path + ".py") or
+                         exists_case_sensitive(module_path + ".so"))
             is_package = exists_case_sensitive(package_path) and os.path.isdir(package_path)
             if is_module or is_package:
                 if ('site-packages' in prefix or 'dist-packages' in prefix or
@@ -390,7 +391,10 @@ class SortImports(object):
                 continue
 
             if module in self.as_map:
-                import_definition = "import {0} as {1}".format(module, self.as_map[module])
+                import_definition = ''
+                if self.config['keep_direct_and_as_imports']:
+                    import_definition = "import {0}\n".format(module)
+                import_definition += "import {0} as {1}".format(module, self.as_map[module])
             else:
                 import_definition = "import {0}".format(module)
 
diff --git a/isort/main.py b/isort/main.py
index c1d76619..b831a3ce 100755
--- a/isort/main.py
+++ b/isort/main.py
@@ -213,6 +213,8 @@ def create_parser():
                         dest='indent', type=str)
     parser.add_argument('-j', '--jobs', help='Number of files to process in parallel.',
                         dest='jobs', type=int)
+    parser.add_argument('-k', '--keep-direct-and-as', dest='keep_direct_and_as_imports', action='store_true',
+                        help="Turns off default behavior that removes direct imports when as imports exist.")
     parser.add_argument('-l', '--lines', help='[Deprecated] The max length of an import line (used for wrapping '
                         'long imports).',
                         dest='line_length', type=int)
diff --git a/isort/settings.py b/isort/settings.py
index c940726f..09feb5dc 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -124,6 +124,7 @@ default = {'force_to_top': [],
            'lines_between_types': 0,
            'combine_as_imports': False,
            'combine_star': False,
+           'keep_direct_and_as_imports': False,
            'include_trailing_comma': False,
            'from_first': False,
            'verbose': False,


Test patch:
diff --git a/test_isort.py b/test_isort.py
index bec4db00..feaf7ccb 100644
--- a/test_isort.py
+++ b/test_isort.py
@@ -1056,6 +1056,9 @@ def test_combined_from_and_as_imports():
                   "from translate.storage import base, factory\n"
                   "from translate.storage.placeables import general, parse as rich_parse\n")
     assert SortImports(file_contents=test_input, combine_as_imports=True).output == test_input
+    test_input = ("import os \nimport os as _os")
+    test_output = ("import os\nimport os as _os\n")
+    assert SortImports(file_contents=test_input, keep_direct_and_as_imports=True).output == test_output
 
 
 def test_as_imports_with_line_length():
@@ -1679,7 +1682,7 @@ def test_alphabetic_sorting():
     options = {'force_single_line': True,
                'force_alphabetical_sort_within_sections': True, }
 
-    output = SortImports(file_contents=test_input, known_first_party=['django'], **options).output
+    output = SortImports(file_contents=test_input, **options).output
     assert output == test_input
 
     test_input = ("# -*- coding: utf-8 -*-\n"
@@ -2290,27 +2293,3 @@ def test_no_inline_sort():
     )
     assert SortImports(file_contents=test_input, no_inline_sort=False, force_single_line=True).output == expected
     assert SortImports(file_contents=test_input, no_inline_sort=True, force_single_line=True).output == expected
-
-
-def test_relative_import_of_a_module():
-    """Imports can be dynamically created (PEP302) and is used by modules such as six.  This test ensures that
-    these types of imports are still sorted to the correct type instead of being categorized as local."""
-    test_input = ('from __future__ import absolute_import\n'
-                  '\n'
-                  'import itertools\n'
-                  '\n'
-                  'from six import add_metaclass\n'
-                  '\n'
-                  'from six.moves import asd\n'
-                  )
-
-    expected_results = ('from __future__ import absolute_import\n'
-                        '\n'
-                        'import itertools\n'
-                        '\n'
-                        'from six import add_metaclass\n'
-                        'from six.moves import asd\n'
-                        )
-
-    sorted_result = SortImports(file_contents=test_input, force_single_line=True).output
-    assert sorted_result == expected_results