Skip to content

Commit 9bc9bdf

Browse files
dbatyPierre-Sassoulas
authored andcommitted
Support both isort 4 and isort 5
The API of isort 5 (released on 2020-07-04) is completely different. We must still support isort 4 because isort 5 dropped the compatibility with Python 3.5, which pylint still supports. Note about the `known-standard-library` option: it has been included in pylint for years. Until now, it was mapped with the option of the same name in isort. However, isort 5 has changed the meaning of this option (see https://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/#known_standard_library). Most users of pylint want the meaning of the new `extra-standard-library` option. To avoid a breaking change in pylint, the `known-standard-library` pylint option is now mapped to `known-standard-library` in isort 4, and `extra-standard-library` in isort 5. Users that really want the _new_ meaning of `known-standard-library` in isort 4 must disable the `wrong-import-order` check in pylint and run isort manually, outside of pylint. Fix #3722.
1 parent 707fc46 commit 9bc9bdf

File tree

10 files changed

+61
-14
lines changed

10 files changed

+61
-14
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Release date: TBA
4747

4848
* Add `raise-missing-from` check for exceptions that should have a cause.
4949

50+
* Support both isort 4 and isort 5. If you have pinned isort 4 in your projet requirements, nothing changes. If you use isort 5, though, note that the `known-standard-library` option is not interpreted the same in isort 4 and isort 5 (see the migration guide in isort documentation for further details). For compatibility's sake for most pylint users, the `known-standard-library` option in pylint now maps to `extra-standard-library` in isort 5. If you really want what `known-standard-library` now means in isort 5, you must disable the `wrong-import-order` check in pylint and run isort manually with a proper isort configuration file.
51+
52+
Close #3722
53+
5054

5155
What's New in Pylint 2.5.4?
5256
===========================

doc/whatsnew/2.6.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ Other Changes
2727
* `mixed-indentation` has been removed, it is no longer useful since TabError is included directly in python3
2828

2929
* Fix superfluous-parens false-positive for the walrus operator
30+
31+
* Add support for both isort 4 and isort 5. If you have pinned isort 4 in your projet requirements, nothing changes. If you use isort 5, though, note that the `known-standard-library` option is not interpreted the same in isort 4 and isort 5 (see `the migration guide in isort documentation`_ for further details). For compatibility's sake for most pylint users, the `known-standard-library` option in pylint now maps to `extra-standard-library` in isort 5. If you really want what `known-standard-library` now means in isort 5, you must disable the `wrong-import-order` check in pylint and run isort manually with a proper isort configuration file.
32+
33+
.. _the migration guide in isort documentation: https://timothycrosley.github.io/isort/docs/upgrade_guides/5.0.0/#known_standard_library

man/pylint.1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Create a graph of external dependencies in the given file (report RP0402 must no
209209
.IP "--int-import-graph=<file.dot>"
210210
Create a graph of internal dependencies in the given file (report RP0402 must not be disabled). [default: none]
211211
.IP "--known-standard-library=<modules>"
212-
Force import order to recognize a module as part of the standard compatibility libraries. [default: none]
212+
Force import order to recognize a module as part of the standard compatibility libraries.
213213
.IP "--known-third-party=<modules>"
214214
Force import order to recognize a module as part of a third party library. [default: enchant]
215215
.IP "--allow-any-import-level=<modules>"

pylint/__pkginfo__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
install_requires = [
4040
"astroid>=2.4.0,<=2.5",
41-
"isort>=4.2.5,<5",
41+
"isort>=4.2.5,<6",
4242
"mccabe>=0.6,<0.7",
4343
"toml>=0.7.1",
4444
]

pylint/checkers/imports.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
from distutils import sysconfig
4747

4848
import astroid
49-
import isort
5049
from astroid import modutils
5150
from astroid.decorators import cached
5251

@@ -60,7 +59,7 @@
6059
from pylint.graph import DotBackend, get_cycles
6160
from pylint.interfaces import IAstroidChecker
6261
from pylint.reporters.ureports.nodes import Paragraph, VerbatimText
63-
from pylint.utils import get_global_option
62+
from pylint.utils import IsortDriver, get_global_option
6463

6564

6665
def _qualified_names(modname):
@@ -709,11 +708,7 @@ def _check_imports_order(self, _module_node):
709708
third_party_not_ignored = []
710709
first_party_not_ignored = []
711710
local_not_ignored = []
712-
isort_obj = isort.SortImports(
713-
file_contents="",
714-
known_third_party=self.config.known_third_party,
715-
known_standard_library=self.config.known_standard_library,
716-
)
711+
isort_driver = IsortDriver(self.config)
717712
for node, modname in self._imports_stack:
718713
if modname.startswith("."):
719714
package = "." + modname.split(".")[1]
@@ -723,7 +718,7 @@ def _check_imports_order(self, _module_node):
723718
ignore_for_import_order = not self.linter.is_message_enabled(
724719
"wrong-import-order", node.fromlineno
725720
)
726-
import_category = isort_obj.place_module(package)
721+
import_category = isort_driver.place_module(package)
727722
node_and_package_import = (node, package)
728723
if import_category in ("FUTURE", "STDLIB"):
729724
std_imports.append(node_and_package_import)

pylint/utils/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
from pylint.utils.ast_walker import ASTWalker
4747
from pylint.utils.file_state import FileState
4848
from pylint.utils.utils import (
49+
HAS_ISORT_5,
50+
IsortDriver,
4951
_basename_in_blacklist_re,
5052
_check_csv,
5153
_format_option_value,

pylint/utils/utils.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22
# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
33

4+
try:
5+
import isort.api
6+
7+
HAS_ISORT_5 = True
8+
except ImportError: # isort < 5
9+
import isort
10+
11+
HAS_ISORT_5 = False
12+
413
import codecs
514
import os
615
import re
@@ -398,3 +407,29 @@ def _ini_format(stream, options):
398407
# remove trailing ',' from last element of the list
399408
value = value[:-1]
400409
print("%s=%s" % (optname, value), file=stream)
410+
411+
412+
class IsortDriver:
413+
"""A wrapper around isort API that changed between versions 4 and 5."""
414+
415+
def __init__(self, config):
416+
if HAS_ISORT_5:
417+
self.isort5_config = isort.api.Config(
418+
# There is not typo here. EXTRA_standard_library is
419+
# what most users want. The option has been named
420+
# KNOWN_standard_library for ages in pylint and we
421+
# don't want to break compatibility.
422+
extra_standard_library=config.known_standard_library,
423+
known_third_party=config.known_third_party,
424+
)
425+
else:
426+
self.isort4_obj = isort.SortImports( # pylint: disable=no-member
427+
file_contents="",
428+
known_standard_library=config.known_standard_library,
429+
known_third_party=config.known_third_party,
430+
)
431+
432+
def place_module(self, package):
433+
if HAS_ISORT_5:
434+
return isort.api.place_module(package, self.isort5_config)
435+
return self.isort4_obj.place_module(package)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
wrong-import-order:12::standard import "import os.path" should be placed before "import six"
22
wrong-import-order:14::standard import "import sys" should be placed before "import six"
33
wrong-import-order:15::standard import "import datetime" should be placed before "import six"
4-
wrong-import-order:18::first party import "import totally_missing" should be placed before "from .package import Class"
5-
wrong-import-order:20::third party import "import astroid" should be placed before "import unused_import"
6-
wrong-import-order:24::third party import "from six.moves.urllib.parse import quote" should be placed before "import unused_import"
4+
wrong-import-order:18::third party import "import totally_missing" should be placed before "from .package import Class"
5+
wrong-import-order:20::third party import "import astroid" should be placed before "from .package import Class"
6+
wrong-import-order:24::third party import "from six.moves.urllib.parse import quote" should be placed before "from .package import Class"

tests/test_functional.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import pytest
2929

3030
from pylint import testutils
31+
from pylint.utils import HAS_ISORT_5
3132

3233

3334
class test_dialect(csv.excel):
@@ -77,6 +78,10 @@ def get_tests():
7778
continue
7879
for filename in filenames:
7980
if filename != "__init__.py" and filename.endswith(".py"):
81+
# isort 5 has slightly different rules as isort 4. Testing
82+
# both would be hard: test with isort 5 only.
83+
if filename == "wrong_import_order.py" and not HAS_ISORT_5:
84+
continue
8085
suite.append(testutils.FunctionalTestFile(dirpath, filename))
8186
return suite
8287

tox.ini

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ commands =
3737
basepython = python3
3838
deps =
3939
black==19.10b0
40-
isort==4.3.21
40+
isort==5.4.2
4141
commands =
4242
black --check . --exclude="tests/functional/|tests/input|tests/extensions/data|tests/regrtest_data/|tests/data/|venv|astroid|.tox"
4343
isort -rc . --check-only
@@ -58,6 +58,8 @@ deps =
5858
coverage<5.0
5959
isort
6060
mccabe
61+
# isort 5 is not compatible with Python 3.5
62+
py35: isort>=4.2.5,<5
6163
pytest
6264
pytest-xdist
6365
pytest-benchmark

0 commit comments

Comments
 (0)