summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pyenchant_pylint_custom_dict.txt1
-rw-r--r--doc/user_guide/usage/run.rst7
-rw-r--r--doc/whatsnew/fragments/8310.feature3
-rw-r--r--pylint/config/config_initialization.py14
-rw-r--r--tests/lint/unittest_lint.py15
-rw-r--r--tests/test_self.py7
6 files changed, 43 insertions, 4 deletions
diff --git a/.pyenchant_pylint_custom_dict.txt b/.pyenchant_pylint_custom_dict.txt
index d3cce63e2..5969ff639 100644
--- a/.pyenchant_pylint_custom_dict.txt
+++ b/.pyenchant_pylint_custom_dict.txt
@@ -128,6 +128,7 @@ functools
genexpr
getattr
globals
+globbing
GPL
graphname
graphviz
diff --git a/doc/user_guide/usage/run.rst b/doc/user_guide/usage/run.rst
index 006327f40..b9dfedc88 100644
--- a/doc/user_guide/usage/run.rst
+++ b/doc/user_guide/usage/run.rst
@@ -52,6 +52,13 @@ If the analyzed sources use implicit namespace packages (PEP 420), the source ro
be specified using the ``--source-roots`` option. Otherwise, the package names are
detected incorrectly, since implicit namespace packages don't contain an ``__init__.py``.
+Globbing support
+----------------
+
+It is also possible to specify both directories and files using globbing patterns::
+
+ pylint [options] packages/*/src
+
Command line options
--------------------
diff --git a/doc/whatsnew/fragments/8310.feature b/doc/whatsnew/fragments/8310.feature
new file mode 100644
index 000000000..a835be097
--- /dev/null
+++ b/doc/whatsnew/fragments/8310.feature
@@ -0,0 +1,3 @@
+Support globbing pattern when defining which file/directory/module to lint.
+
+Closes #8310
diff --git a/pylint/config/config_initialization.py b/pylint/config/config_initialization.py
index d26f0e8c5..b9ac18b4d 100644
--- a/pylint/config/config_initialization.py
+++ b/pylint/config/config_initialization.py
@@ -5,6 +5,8 @@
from __future__ import annotations
import sys
+from glob import glob
+from itertools import chain
from pathlib import Path
from typing import TYPE_CHECKING
@@ -118,6 +120,14 @@ def _config_initialization(
# Link the base Namespace object on the current directory
linter._directory_namespaces[Path(".").resolve()] = (linter.config, {})
- # parsed_args_list should now only be a list of files/directories to lint.
+ # parsed_args_list should now only be a list of inputs to lint.
# All other options have been removed from the list.
- return parsed_args_list
+ return list(
+ chain.from_iterable(
+ # NOTE: 'or [arg]' is needed in the case the input file or directory does not exist and 'glob(arg)' cannot
+ # find anything. Without this we would not be able to output the fatal import error for this module later
+ # on, as it would get silently ignored.
+ glob(arg, recursive=True) or [arg]
+ for arg in parsed_args_list
+ )
+ )
diff --git a/tests/lint/unittest_lint.py b/tests/lint/unittest_lint.py
index 5aa08572f..d3faa5453 100644
--- a/tests/lint/unittest_lint.py
+++ b/tests/lint/unittest_lint.py
@@ -1234,8 +1234,6 @@ def test_recursive_implicit_namespace() -> None:
],
exit=False,
)
- run.linter.set_reporter(testutils.GenericTestReporter())
- run.linter.check([join(REGRTEST_DATA_DIR, "pep420", "basic")])
assert run.linter.file_state.base_name == "namespace.package"
@@ -1255,6 +1253,19 @@ def test_recursive_implicit_namespace_wrapper() -> None:
assert run.linter.reporter.messages == []
+def test_globbing() -> None:
+ run = Run(
+ [
+ "--verbose",
+ "--source-roots",
+ join(REGRTEST_DATA_DIR, "pep420", "basic", "project"),
+ join(REGRTEST_DATA_DIR, "pep420", "basic", "project", "**", "__init__.py"),
+ ],
+ exit=False,
+ )
+ assert run.linter.file_state.base_name == "namespace.package.__init__"
+
+
def test_relative_imports(initialized_linter: PyLinter) -> None:
"""Regression test for https://github.com/PyCQA/pylint/issues/3651"""
linter = initialized_linter
diff --git a/tests/test_self.py b/tests/test_self.py
index 07c2a2f0b..e40dd7a4d 100644
--- a/tests/test_self.py
+++ b/tests/test_self.py
@@ -1158,6 +1158,13 @@ a.py:1:4: E0001: Parsing failed: 'invalid syntax (<unknown>, line 1)' (syntax-er
code=0,
)
+ def test_recursive_globbing(self) -> None:
+ """Tests if running linter over directory using --recursive=y and globbing"""
+ self._runtest(
+ [join(HERE, "regrtest_data", "d?rectory", "subd*"), "--recursive=y"],
+ code=0,
+ )
+
@pytest.mark.parametrize("ignore_value", ["ignored_subdirectory", "failing.py"])
def test_ignore_recursive(self, ignore_value: str) -> None:
"""Tests recursive run of linter ignoring directory using --ignore parameter.