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

Fix multiline sorting with force-alphabetical-sort #395

Merged
merged 1 commit into from
Mar 27, 2016
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 46 additions & 65 deletions isort/isort.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,13 @@ def _at_end(self):
return self.index == self.number_of_lines

@staticmethod
def _module_key(module_name, config, sub_imports=False):
def _module_key(module_name, config, sub_imports=False, ignore_case=False):
prefix = ""
module_name = str(module_name)
if ignore_case:
module_name = str(module_name).lower()
else:
module_name = str(module_name)

if sub_imports and config['order_by_type']:
if module_name.isupper() and len(module_name) > 1:
prefix = "A"
Expand Down Expand Up @@ -332,14 +336,14 @@ def _add_straight_imports(self, straight_modules, section, section_output):
section_output.extend(comments_above)
section_output.append(self._add_comments(self.comments['straight'].get(module), import_definition))

def _add_from_imports(self, from_modules, section, section_output):
def _add_from_imports(self, from_modules, section, section_output, ignore_case):
for module in from_modules:
if module in self.remove_imports:
continue

import_start = "from {0} import ".format(module)
from_imports = list(self.imports[section]['from'][module])
from_imports = nsorted(from_imports, key=lambda key: self._module_key(key, self.config, True))
from_imports = nsorted(from_imports, key=lambda key: self._module_key(key, self.config, True, ignore_case))
if self.remove_imports:
from_imports = [line for line in from_imports if not "{0}.{1}".format(module, line) in
self.remove_imports]
Expand Down Expand Up @@ -441,67 +445,44 @@ def _add_formatted_imports(self):
(at the index of the first import) sorted alphabetically and split between groups

"""
if self.config.get('force_alphabetical_sort', False):
from_output = []
straight_output = []
for section in itertools.chain(self.sections, self.config['forced_separate']):
straight_modules = list(self.imports[section]['straight'])
from_modules = list(self.imports[section]['from'].keys())

self._add_from_imports(from_modules, section, from_output)
self._add_straight_imports(straight_modules, section, straight_output)

new_from_output = []
new_straight_output = []
for line in from_output:
for element in line.split('\n'):
new_from_output.append(element)
for line in straight_output:
for element in line.split('\n'):
new_straight_output.append(element)


sorted_from = sorted(new_from_output, key=lambda import_string: import_string.lower())
sorted_straight = sorted(new_straight_output, key=lambda import_string: import_string.lower())
output = (sorted_from + [''] + sorted_straight) if (sorted_from and sorted_straight) else \
(sorted_from or sorted_straight)
else:
output = []
for section in itertools.chain(self.sections, self.config['forced_separate']):
straight_modules = list(self.imports[section]['straight'])
straight_modules = nsorted(straight_modules, key=lambda key: self._module_key(key, self.config))
from_modules = sorted(list(self.imports[section]['from'].keys()))
from_modules = nsorted(from_modules, key=lambda key: self._module_key(key, self.config, ))

section_output = []
if self.config.get('from_first', False):
self._add_from_imports(from_modules, section, section_output)
self._add_straight_imports(straight_modules, section, section_output)
else:
self._add_straight_imports(straight_modules, section, section_output)
self._add_from_imports(from_modules, section, section_output)

if self.config.get('force_sort_within_sections', False):
def by_module(line):
line = re.sub('^from ', '', line)
line = re.sub('^import ', '', line)
if not self.config['order_by_type']:
line = line.lower()
return line
section_output = nsorted(section_output, key=by_module)

if section_output:
section_name = section
if section_name in self.place_imports:
self.place_imports[section_name] = section_output
continue

section_title = self.config.get('import_heading_' + str(section_name).lower(), '')
if section_title:
section_comment = "# {0}".format(section_title)
if not section_comment in self.out_lines[0:1]:
section_output.insert(0, section_comment)
output += section_output + ([''] * self.config['lines_between_sections'])
sort_ignore_case = self.config.get('force_alphabetical_sort', False)

output = []
for section in itertools.chain(self.sections, self.config['forced_separate']):
straight_modules = list(self.imports[section]['straight'])
straight_modules = nsorted(straight_modules, key=lambda key: self._module_key(key, self.config))
from_modules = sorted(list(self.imports[section]['from'].keys()))
from_modules = nsorted(from_modules, key=lambda key: self._module_key(key, self.config, ))

section_output = []
if self.config.get('from_first', False):
self._add_from_imports(from_modules, section, section_output, sort_ignore_case)
self._add_straight_imports(straight_modules, section, section_output)
else:
self._add_straight_imports(straight_modules, section, section_output)
self._add_from_imports(from_modules, section, section_output, sort_ignore_case)

if self.config.get('force_sort_within_sections', False):
def by_module(line):
line = re.sub('^from ', '', line)
line = re.sub('^import ', '', line)
if not self.config['order_by_type']:
line = line.lower()
return line
section_output = nsorted(section_output, key=by_module)

if section_output:
section_name = section
if section_name in self.place_imports:
self.place_imports[section_name] = section_output
continue

section_title = self.config.get('import_heading_' + str(section_name).lower(), '')
if section_title:
section_comment = "# {0}".format(section_title)
if not section_comment in self.out_lines[0:1]:
section_output.insert(0, section_comment)
output += section_output + ([''] * self.config['lines_between_sections'])

while [character.strip() for character in output[-1:]] == [""]:
output.pop()
Expand Down
29 changes: 20 additions & 9 deletions test_isort.py
Original file line number Diff line number Diff line change
Expand Up @@ -1494,24 +1494,35 @@ def test_comment_at_top_of_file():

def test_alphabetic_sorting():
"""Test to ensure isort correctly handles top of file comments"""
test_input = ("from django.contrib.gis.geos import GEOSException\n"
test_input = ("import unittest\n"
"\n"
"import ABC\n"
"import Zope\n"
"from django.contrib.gis.geos import GEOSException\n"
"from plone.app.testing import getRoles\n"
"from plone.app.testing import ManageRoles\n"
"from plone.app.testing import setRoles\n"
"from Products.CMFPlone import utils\n"
"\n"
"import ABC\n"
"import unittest\n"
"import Zope\n")
)
options = {'force_single_line': True,
'force_alphabetical_sort': True, }
assert SortImports(file_contents=test_input, **options).output == test_input

output = SortImports(file_contents=test_input, **options).output
assert output == test_input

test_input = ("# -*- coding: utf-8 -*-\n"
"from django.db import models\n")
assert SortImports(file_contents=test_input).output == test_input


def test_alphabetic_sorting_multi_line():
"""Test to ensure isort correctly handles multiline import see: issue 364"""
test_input = ("from a import (CONSTANT_A, cONSTANT_B, CONSTANT_C, CONSTANT_D, CONSTANT_E,\n"
" CONSTANT_F, CONSTANT_G, CONSTANT_H, CONSTANT_I, CONSTANT_J)\n")
options = {'force_alphabetical_sort': True, }
assert SortImports(file_contents=test_input, **options).output == test_input


def test_comments_not_duplicated():
"""Test to ensure comments aren't duplicated: issue 303"""
test_input = ('from flask import url_for\n'
Expand Down Expand Up @@ -1596,11 +1607,11 @@ def test_alphabetic_sorting_no_newlines():
test_output = SortImports(file_contents=test_input,force_alphabetical_sort=True).output
assert test_input == test_output

test_input = ('from a import b\n'
'\n'
'import os\n'
test_input = ('import os\n'
'import unittest\n'
'\n'
'from a import b\n'
'\n'
'\n'
'print(1)\n')
test_output = SortImports(file_contents=test_input,force_alphabetical_sort=True, lines_after_imports=2).output
Expand Down