Skip to content

Commit 6e70374

Browse files
committed
More sane handling of site-packages detection
Previously there were some issues with the computation of site-packages, since it was considering any module that started with sys.prefix or sys.real_prefix as a module that could have been installed in site-packages. The patch properly builds the paths, by calling get_python_lib with each prefix. We're also handling Debian's derivatives, which installs third-party libraries into /usr/local/lib/python/dist-packages.
1 parent f63bacb commit 6e70374

File tree

2 files changed

+28
-9
lines changed

2 files changed

+28
-9
lines changed

pylint/checkers/imports.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
"""imports checkers for Python code"""
1717

1818
import collections
19+
from distutils import sysconfig
1920
import os
21+
import platform
2022
import sys
2123

2224
import six
2325

2426
import astroid
2527
from astroid import are_exclusive
26-
from astroid.modutils import (EXT_LIB_DIR, get_module_part, is_standard_module,
28+
from astroid.modutils import (get_module_part, is_standard_module,
2729
file_from_modpath)
2830

2931
from pylint.interfaces import IAstroidChecker
@@ -265,7 +267,6 @@ class ImportsChecker(BaseChecker):
265267
given file (report RP0402 must not be disabled)'}
266268
),
267269
)
268-
ext_lib_dir = os.path.normcase(os.path.abspath(EXT_LIB_DIR))
269270

270271
def __init__(self, linter=None):
271272
BaseChecker.__init__(self, linter)
@@ -280,6 +281,28 @@ def __init__(self, linter=None):
280281
self._report_dependencies_graph),
281282
)
282283

284+
self._site_packages = self._compute_site_packages()
285+
286+
def _compute_site_packages(self):
287+
def _normalized_path(path):
288+
return os.path.normcase(os.path.abspath(path))
289+
290+
paths = set()
291+
real_prefix = getattr(sys, 'real_prefix', None)
292+
for prefix in filter(None, (real_prefix, sys.prefix)):
293+
path = sysconfig.get_python_lib(prefix=prefix)
294+
path = _normalized_path(path)
295+
paths.add(path)
296+
297+
# Handle Debian's derivatives /usr/local.
298+
if os.path.isfile("/etc/debian_version"):
299+
for prefix in filter(None, (real_prefix, sys.prefix)):
300+
libpython = os.path.join(prefix, "local", "lib",
301+
"python" + sysconfig.get_python_version(),
302+
"dist-packages")
303+
paths.add(libpython)
304+
return paths
305+
283306
def open(self):
284307
"""called before visiting project (i.e set of modules)"""
285308
self.linter.add_stats(dependencies={})
@@ -449,10 +472,6 @@ def _check_imports_order(self, node):
449472
extern_imports = []
450473
local_imports = []
451474
std_imports = []
452-
stdlib_paths = [sys.prefix, self.ext_lib_dir]
453-
real_prefix = getattr(sys, 'real_prefix', None)
454-
if real_prefix is not None:
455-
stdlib_paths.append(real_prefix)
456475

457476
for node, modname in self._imports_stack:
458477
package = modname.split('.')[0]
@@ -468,13 +487,12 @@ def _check_imports_order(self, node):
468487
try:
469488
filename = file_from_modpath([package])
470489
except ImportError:
471-
extern_imports.append((node, package))
472490
continue
473491
if not filename:
474-
extern_imports.append((node, package))
475492
continue
493+
476494
filename = os.path.normcase(os.path.abspath(filename))
477-
if not any(filename.startswith(path) for path in stdlib_paths):
495+
if not any(filename.startswith(path) for path in self._site_packages):
478496
local_imports.append((node, package))
479497
continue
480498
extern_imports.append((node, package))

pylint/test/functional/wrong_import_order.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
import sys # [wrong-import-order]
88
import datetime # [wrong-import-order]
99
import unused_import
10+
import totally_missing
1011
import astroid

0 commit comments

Comments
 (0)