Skip to content

Commit ee034d0

Browse files
Merge branch 'release/4.2.4'
2 parents 2282150 + 51516fc commit ee034d0

File tree

8 files changed

+77
-12
lines changed

8 files changed

+77
-12
lines changed

ACKNOWLEDGEMENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Notable Bug Reporters
1414
- Chris Adams (@acdha)
1515
- @OddBloke
1616
- Martin Geisler (@mgeisler)
17+
- Tim Heap (@timheap)
1718

1819
Code Contributors
1920
===================

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,10 @@ Changelog
4848

4949
### 4.2.3
5050
- Fixed a large number of priority bugs - bug fix only release
51+
52+
### 4.2.4
53+
- Fixed an issue that caused module that contained functions before doc strings, to incorrectly place imports
54+
- Fixed regression in how `force_alphabetical_sort` was being interpretted (issue #409)
55+
- Fixed stray print statement printing skipped files (issue #411)
56+
- Added option for forcing imports into a single bucket: `no_sections`
57+
- Added option for new lines between import types (from, straight): `lines_between_sections`

isort/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@
2525
from . import settings
2626
from .isort import SortImports
2727

28-
__version__ = "4.2.3"
28+
__version__ = "4.2.4"

isort/isort.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ def __init__(self, file_path=None, file_contents=None, write_to_stdout=False, ch
7474
else:
7575
self.config[key] = value
7676

77+
if self.config.get('force_alphabetical_sort', False):
78+
self.config.update({'force_alphabetical_sort_within_sections': True,
79+
'no_sections': True,
80+
'lines_between_types': 1,
81+
'from_first': True})
82+
7783
indent = str(self.config['indent'])
7884
if indent.isdigit():
7985
indent = " " * int(indent)
@@ -451,10 +457,19 @@ def _add_formatted_imports(self):
451457
(at the index of the first import) sorted alphabetically and split between groups
452458
453459
"""
454-
sort_ignore_case = self.config.get('force_alphabetical_sort', False)
460+
sort_ignore_case = self.config.get('force_alphabetical_sort_within_sections', False)
461+
sections = itertools.chain(self.sections, self.config['forced_separate'])
462+
463+
sections = itertools.chain(self.sections, self.config['forced_separate'])
464+
if self.config.get('no_sections', False):
465+
self.imports['no_sections'] = {'straight': [], 'from': {}}
466+
for section in sections:
467+
self.imports['no_sections']['straight'].extend(self.imports[section].get('straight', []))
468+
self.imports['no_sections']['from'].update(self.imports[section].get('from', {}))
469+
sections = ('no_sections', )
455470

456471
output = []
457-
for section in itertools.chain(self.sections, self.config['forced_separate']):
472+
for section in sections:
458473
straight_modules = list(self.imports[section]['straight'])
459474
straight_modules = nsorted(straight_modules, key=lambda key: self._module_key(key, self.config))
460475
from_modules = sorted(list(self.imports[section]['from'].keys()))
@@ -463,9 +478,13 @@ def _add_formatted_imports(self):
463478
section_output = []
464479
if self.config.get('from_first', False):
465480
self._add_from_imports(from_modules, section, section_output, sort_ignore_case)
481+
if self.config.get('lines_between_types', 0) and from_modules and straight_modules:
482+
section_output.extend([''] * self.config['lines_between_types'])
466483
self._add_straight_imports(straight_modules, section, section_output)
467484
else:
468485
self._add_straight_imports(straight_modules, section, section_output)
486+
if self.config.get('lines_between_types', 0) and from_modules and straight_modules:
487+
section_output.extend([''] * self.config['lines_between_types'])
469488
self._add_from_imports(from_modules, section, section_output, sort_ignore_case)
470489

471490
if self.config.get('force_sort_within_sections', False):
@@ -658,7 +677,7 @@ def _skip_line(self, line):
658677

659678
if '"' in line or "'" in line:
660679
index = 0
661-
if self._first_comment_index_start == -1:
680+
if self._first_comment_index_start == -1 and (line.startswith('"') or line.startswith("'")):
662681
self._first_comment_index_start = self.index
663682
while index < len(line):
664683
if line[index] == "\\":

isort/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ def create_parser():
185185
help='Forces all from imports to appear on their own line')
186186
parser.add_argument('--force_single_line_imports', dest='force_single_line', action='store_true',
187187
help=argparse.SUPPRESS)
188+
parser.add_argument('-ds', '--no-sections', help='Put all imports into the same section bucket', dest='no_sections',
189+
action='store_true')
188190
parser.add_argument('-sd', '--section-default', dest='default_section',
189191
help='Sets the default section for imports (by default FIRSTPARTY) options: ' +
190192
str(DEFAULT_SECTIONS))
@@ -220,11 +222,14 @@ def create_parser():
220222
help="Specifies how long lines that are wrapped should be, if not set line_length is used.")
221223
parser.add_argument('-fgw', '--force-grid-wrap', action='store_true', dest="force_grid_wrap",
222224
help='Force from imports to be grid wrapped regardless of line length')
225+
parser.add_argument('-fass', '--force-alphabetical-sort-within-sections', action='store_true',
226+
dest="force_alphabetical_sort", help='Force all imports to be sorted alphabetically within a '
227+
'section')
223228
parser.add_argument('-fas', '--force-alphabetical-sort', action='store_true', dest="force_alphabetical_sort",
224229
help='Force all imports to be sorted as a single section')
225230
parser.add_argument('-fss', '--force-sort-within-sections', action='store_true', dest="force_sort_within_sections",
226231
help='Force imports to be sorted by module, independent of import_type')
227-
232+
parser.add_argument('-lbt', '--lines-between-types', dest='lines_between_types', type=int)
228233

229234
arguments = dict((key, value) for (key, value) in itemsview(vars(parser.parse_args())) if value)
230235
if 'dont_order_by_type' in arguments:

isort/settings.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
'line_length': 79,
4949
'wrap_length': 0,
5050
'sections': DEFAULT_SECTIONS,
51+
'no_sections': False,
5152
'known_future_library': ['__future__'],
5253
'known_standard_library': ["abc", "anydbm", "argparse", "array", "asynchat", "asyncore", "atexit", "base64",
5354
"BaseHTTPServer", "bisect", "bz2", "calendar", "cgitb", "cmd", "codecs",
@@ -90,13 +91,15 @@
9091
'atomic': False,
9192
'lines_after_imports': -1,
9293
'lines_between_sections': 1,
94+
'lines_between_types': 0,
9395
'combine_as_imports': False,
9496
'combine_star': False,
9597
'include_trailing_comma': False,
9698
'from_first': False,
9799
'verbose': False,
98100
'quiet': False,
99101
'force_adds': False,
102+
'force_alphabetical_sort_within_sections': False,
100103
'force_alphabetical_sort': False,
101104
'force_grid_wrap': False,
102105
'force_sort_within_sections': False,
@@ -203,7 +206,6 @@ def should_skip(filename, config, path='/'):
203206
"""Returns True if the file should be skipped based on the passed in settings."""
204207
for skip_path in config['skip']:
205208
if os.path.join(path, filename).endswith('/' + skip_path.lstrip('/')):
206-
print(skip_path)
207209
return True
208210

209211
position = os.path.split(filename)

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ def run(self):
3939
readme = f.read()
4040

4141
setup(name='isort',
42-
version='4.2.3',
42+
version='4.2.4',
4343
description='A Python utility / library to sort Python imports.',
4444
long_description=readme,
4545
author='Timothy Crosley',
4646
author_email='[email protected]',
4747
url='https://github.com/timothycrosley/isort',
48-
download_url='https://github.com/timothycrosley/isort/archive/4.2.3.tar.gz',
48+
download_url='https://github.com/timothycrosley/isort/archive/4.2.4.tar.gz',
4949
license="MIT",
5050
entry_points={
5151
'console_scripts': [

test_isort.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1509,7 +1509,7 @@ def test_alphabetic_sorting():
15091509
"from Products.CMFPlone import utils\n"
15101510
)
15111511
options = {'force_single_line': True,
1512-
'force_alphabetical_sort': True, }
1512+
'force_alphabetical_sort_within_sections': True, }
15131513

15141514
output = SortImports(file_contents=test_input, **options).output
15151515
assert output == test_input
@@ -1523,7 +1523,7 @@ def test_alphabetic_sorting_multi_line():
15231523
"""Test to ensure isort correctly handles multiline import see: issue 364"""
15241524
test_input = ("from a import (CONSTANT_A, cONSTANT_B, CONSTANT_C, CONSTANT_D, CONSTANT_E,\n"
15251525
" CONSTANT_F, CONSTANT_G, CONSTANT_H, CONSTANT_I, CONSTANT_J)\n")
1526-
options = {'force_alphabetical_sort': True, }
1526+
options = {'force_alphabetical_sort_within_sections': True, }
15271527
assert SortImports(file_contents=test_input, **options).output == test_input
15281528

15291529

@@ -1608,7 +1608,7 @@ def test_sections_parsed_correct():
16081608
def test_alphabetic_sorting_no_newlines():
16091609
'''Test to ensure that alphabetical sort does not erroneously introduce new lines (issue #328)'''
16101610
test_input = "import os\n"
1611-
test_output = SortImports(file_contents=test_input,force_alphabetical_sort=True).output
1611+
test_output = SortImports(file_contents=test_input,force_alphabetical_sort_within_sections=True).output
16121612
assert test_input == test_output
16131613

16141614
test_input = ('import os\n'
@@ -1618,7 +1618,7 @@ def test_alphabetic_sorting_no_newlines():
16181618
'\n'
16191619
'\n'
16201620
'print(1)\n')
1621-
test_output = SortImports(file_contents=test_input,force_alphabetical_sort=True, lines_after_imports=2).output
1621+
test_output = SortImports(file_contents=test_input,force_alphabetical_sort_within_sections=True, lines_after_imports=2).output
16221622
assert test_input == test_output
16231623

16241624

@@ -1751,3 +1751,34 @@ def test_import_by_paren_issue_375():
17511751
' Bar,\n'
17521752
')\n')
17531753
assert SortImports(file_contents=test_input).output == 'from .models import Bar, Foo\n'
1754+
1755+
1756+
def test_function_with_docstring():
1757+
"""Test to ensure isort can correctly sort imports when the first found content is a function with a docstring"""
1758+
add_imports = ['from __future__ import unicode_literals']
1759+
test_input = ('def foo():\n'
1760+
' """ Single line triple quoted doctring """\n'
1761+
' pass\n')
1762+
expected_output = ('from __future__ import unicode_literals\n'
1763+
'\n'
1764+
'\n'
1765+
'def foo():\n'
1766+
' """ Single line triple quoted doctring """\n'
1767+
' pass\n')
1768+
assert SortImports(file_contents=test_input, add_imports=add_imports).output == expected_output
1769+
1770+
1771+
def test_plone_style():
1772+
"""Test to ensure isort correctly plone style imports"""
1773+
test_input = ("from django.contrib.gis.geos import GEOSException\n"
1774+
"from plone.app.testing import getRoles\n"
1775+
"from plone.app.testing import ManageRoles\n"
1776+
"from plone.app.testing import setRoles\n"
1777+
"from Products.CMFPlone import utils\n"
1778+
"\n"
1779+
"import ABC\n"
1780+
"import unittest\n"
1781+
"import Zope\n")
1782+
options = {'force_single_line': True,
1783+
'force_alphabetical_sort': True}
1784+
assert SortImports(file_contents=test_input, **options).output == test_input

0 commit comments

Comments
 (0)