summaryrefslogtreecommitdiff
path: root/pylint/lint
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2021-04-01 08:56:25 +0200
committerPierre Sassoulas <pierre.sassoulas@gmail.com>2021-04-03 22:49:21 +0200
commit63ca05977dc11efe4c51f64a08c02fd0fb0566fc (patch)
tree192c6555626d84b39d34d37c23e24baa7c846eb5 /pylint/lint
parent8b3b8e27c891c4678b2e239c899fb4e12714ab67 (diff)
downloadpylint-git-63ca05977dc11efe4c51f64a08c02fd0fb0566fc.tar.gz
Move utils.expand_module in its own file in lint
We never used it anywhere else than lint so it belong in lint.
Diffstat (limited to 'pylint/lint')
-rw-r--r--pylint/lint/expand_modules.py143
-rw-r--r--pylint/lint/pylinter.py3
-rw-r--r--pylint/lint/utils.py4
3 files changed, 147 insertions, 3 deletions
diff --git a/pylint/lint/expand_modules.py b/pylint/lint/expand_modules.py
new file mode 100644
index 000000000..dc52811b5
--- /dev/null
+++ b/pylint/lint/expand_modules.py
@@ -0,0 +1,143 @@
+import os
+import sys
+
+from astroid import modutils
+
+
+def _modpath_from_file(filename, is_namespace, path=None):
+ def _is_package_cb(path, parts):
+ return modutils.check_modpath_has_init(path, parts) or is_namespace
+
+ return modutils.modpath_from_file_with_callback(
+ filename, path=path, is_package_cb=_is_package_cb
+ )
+
+
+def get_python_path(filepath: str) -> str:
+ dirname = os.path.realpath(os.path.expanduser(filepath))
+ if not os.path.isdir(dirname):
+ dirname = os.path.dirname(dirname)
+ while True:
+ if not os.path.exists(os.path.join(dirname, "__init__.py")):
+ return dirname
+ old_dirname = dirname
+ dirname = os.path.dirname(dirname)
+ if old_dirname == dirname:
+ return os.getcwd()
+ return None
+
+
+def _basename_in_ignore_list_re(base_name, ignore_list_re):
+ """Determines if the basename is matched in a regex ignorelist
+
+ :param str base_name: The basename of the file
+ :param list ignore_list_re: A collection of regex patterns to match against.
+ Successful matches are ignored.
+
+ :returns: `True` if the basename is ignored, `False` otherwise.
+ :rtype: bool
+ """
+ for file_pattern in ignore_list_re:
+ if file_pattern.match(base_name):
+ return True
+ return False
+
+
+def expand_modules(files_or_modules, ignore_list, ignore_list_re):
+ """take a list of files/modules/packages and return the list of tuple
+ (file, module name) which have to be actually checked
+ """
+ result = []
+ errors = []
+ path = sys.path.copy()
+
+ for something in files_or_modules:
+ if os.path.basename(something) in ignore_list:
+ continue
+ if _basename_in_ignore_list_re(os.path.basename(something), ignore_list_re):
+ continue
+
+ module_path = get_python_path(something)
+ additional_search_path = [".", module_path] + path
+ if os.path.exists(something):
+ # this is a file or a directory
+ try:
+ modname = ".".join(
+ modutils.modpath_from_file(something, path=additional_search_path)
+ )
+ except ImportError:
+ modname = os.path.splitext(os.path.basename(something))[0]
+ if os.path.isdir(something):
+ filepath = os.path.join(something, "__init__.py")
+ else:
+ filepath = something
+ else:
+ # suppose it's a module or package
+ modname = something
+ try:
+ filepath = modutils.file_from_modpath(
+ modname.split("."), path=additional_search_path
+ )
+ if filepath is None:
+ continue
+ except (ImportError, SyntaxError) as ex:
+ # The SyntaxError is a Python bug and should be
+ # removed once we move away from imp.find_module: https://bugs.python.org/issue10588
+ errors.append({"key": "fatal", "mod": modname, "ex": ex})
+ continue
+
+ filepath = os.path.normpath(filepath)
+ modparts = (modname or something).split(".")
+
+ try:
+ spec = modutils.file_info_from_modpath(
+ modparts, path=additional_search_path
+ )
+ except ImportError:
+ # Might not be acceptable, don't crash.
+ is_namespace = False
+ is_directory = os.path.isdir(something)
+ else:
+ is_namespace = modutils.is_namespace(spec)
+ is_directory = modutils.is_directory(spec)
+
+ if not is_namespace:
+ result.append(
+ {
+ "path": filepath,
+ "name": modname,
+ "isarg": True,
+ "basepath": filepath,
+ "basename": modname,
+ }
+ )
+
+ has_init = (
+ not (modname.endswith(".__init__") or modname == "__init__")
+ and os.path.basename(filepath) == "__init__.py"
+ )
+ if has_init or is_namespace or is_directory:
+ for subfilepath in modutils.get_module_files(
+ os.path.dirname(filepath), ignore_list, list_all=is_namespace
+ ):
+ if filepath == subfilepath:
+ continue
+ if _basename_in_ignore_list_re(
+ os.path.basename(subfilepath), ignore_list_re
+ ):
+ continue
+
+ modpath = _modpath_from_file(
+ subfilepath, is_namespace, path=additional_search_path
+ )
+ submodname = ".".join(modpath)
+ result.append(
+ {
+ "path": subfilepath,
+ "name": submodname,
+ "isarg": False,
+ "basepath": filepath,
+ "basename": modname,
+ }
+ )
+ return result, errors
diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py
index 5a662a079..e199b5437 100644
--- a/pylint/lint/pylinter.py
+++ b/pylint/lint/pylinter.py
@@ -16,6 +16,7 @@ import astroid
from pylint import checkers, config, exceptions, interfaces, reporters
from pylint.constants import MAIN_CHECKER_NAME, MSG_TYPES
+from pylint.lint.expand_modules import expand_modules
from pylint.lint.parallel import check_parallel
from pylint.lint.report_functions import (
report_messages_by_module_stats,
@@ -970,7 +971,7 @@ class PyLinter(
def _expand_files(self, modules):
"""get modules and errors from a list of modules and handle errors"""
- result, errors = utils.expand_modules(
+ result, errors = expand_modules(
modules, self.config.black_list, self.config.black_list_re
)
for error in errors:
diff --git a/pylint/lint/utils.py b/pylint/lint/utils.py
index 1f4d58bfe..3d17f3b38 100644
--- a/pylint/lint/utils.py
+++ b/pylint/lint/utils.py
@@ -4,7 +4,7 @@
import contextlib
import sys
-from pylint.utils import utils
+from pylint.lint.expand_modules import get_python_path
class ArgumentPreprocessingError(Exception):
@@ -51,7 +51,7 @@ def _patch_sys_path(args):
changes = []
seen = set()
for arg in args:
- path = utils.get_python_path(arg)
+ path = get_python_path(arg)
if path not in seen:
changes.append(path)
seen.add(path)