summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniël van Noord <13665637+DanielNoord@users.noreply.github.com>2022-04-15 14:34:18 +0200
committerGitHub <noreply@github.com>2022-04-15 14:34:18 +0200
commit6efa821fb68bbc8263c3fcacb29db08a8944d60c (patch)
treed64b1f7831b8c8bff225b2a4520999425835eb63
parent17ce0efd099c45cb2e4ac8aa728805d3401b63a8 (diff)
downloadpylint-git-6efa821fb68bbc8263c3fcacb29db08a8944d60c.tar.gz
Add ``unrecognized-option`` message (#6330)
Co-authored-by: Pierre Sassoulas <pierre.sassoulas@gmail.com>
-rw-r--r--ChangeLog4
-rw-r--r--doc/data/messages/u/unrecognize-option/details.rst3
-rw-r--r--doc/whatsnew/2.14.rst4
-rw-r--r--pylint/config/arguments_manager.py17
-rw-r--r--pylint/config/config_initialization.py19
-rw-r--r--pylint/config/exceptions.py10
-rw-r--r--pylint/lint/pylinter.py5
-rw-r--r--pylintrc31
-rw-r--r--tests/config/functional/toml/toml_with_unknown_option.2.out2
-rw-r--r--tests/config/functional/toml/toml_with_unknown_option.result.json3
-rw-r--r--tests/config/functional/toml/toml_with_unknown_option.toml6
-rw-r--r--tests/config/test_config.py17
-rw-r--r--tests/regrtest_data/.pylintrc3
-rw-r--r--tests/test_self.py5
14 files changed, 86 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index ecc95aa5a..e9d96c796 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -64,6 +64,10 @@ Release date: TBA
Closes #5501
+* Added the ``unrecognized-option`` message. Raised if we encounter any unrecognized options.
+
+ Closes #5259
+
* Added new checker ``typevar-double-variance``: The "covariant" and "contravariant" keyword arguments
cannot both be set to "True" in a TypeVar.
diff --git a/doc/data/messages/u/unrecognize-option/details.rst b/doc/data/messages/u/unrecognize-option/details.rst
new file mode 100644
index 000000000..efa9a206c
--- /dev/null
+++ b/doc/data/messages/u/unrecognize-option/details.rst
@@ -0,0 +1,3 @@
+``Pylint`` warns about options it doesn't recognize both in configuration files
+and on the command-line. For example, this message would be raised when invoking
+pylint with ``pylint --unknown-option=yes test.py``.
diff --git a/doc/whatsnew/2.14.rst b/doc/whatsnew/2.14.rst
index 375a39321..a8eac1a4b 100644
--- a/doc/whatsnew/2.14.rst
+++ b/doc/whatsnew/2.14.rst
@@ -119,6 +119,10 @@ Other Changes
Closes #4324
+* Added the ``unrecognized-option`` message. Raised if we encounter any unrecognized options.
+
+ Closes #5259
+
* Fix false negative for ``bad-string-format-type`` if the value to be formatted is passed in
as a variable holding a constant.
diff --git a/pylint/config/arguments_manager.py b/pylint/config/arguments_manager.py
index 5f49cabbf..47241f14a 100644
--- a/pylint/config/arguments_manager.py
+++ b/pylint/config/arguments_manager.py
@@ -32,7 +32,10 @@ from pylint.config.argument import (
_StoreOldNamesArgument,
_StoreTrueArgument,
)
-from pylint.config.exceptions import UnrecognizedArgumentAction
+from pylint.config.exceptions import (
+ UnrecognizedArgumentAction,
+ _UnrecognizedOptionError,
+)
from pylint.config.help_formatter import _HelpFormatter
from pylint.config.option import Option
from pylint.config.option_parser import OptionParser
@@ -216,9 +219,15 @@ class _ArgumentsManager:
def _parse_configuration_file(self, arguments: list[str]) -> None:
"""Parse the arguments found in a configuration file into the namespace."""
- # pylint: disable-next=fixme
- # TODO: Optparse: This should parse_args instead of parse_known_args
- self.config = self._arg_parser.parse_known_args(arguments, self.config)[0]
+ self.config, parsed_args = self._arg_parser.parse_known_args(
+ arguments, self.config
+ )
+ unrecognized_options: list[str] = []
+ for opt in parsed_args:
+ if opt.startswith("--"):
+ unrecognized_options.append(opt[2:])
+ if unrecognized_options:
+ raise _UnrecognizedOptionError(options=unrecognized_options)
def _parse_command_line_configuration(
self, arguments: Sequence[str] | None = None
diff --git a/pylint/config/config_initialization.py b/pylint/config/config_initialization.py
index 644e724ba..78e540d83 100644
--- a/pylint/config/config_initialization.py
+++ b/pylint/config/config_initialization.py
@@ -9,6 +9,7 @@ from pathlib import Path
from typing import TYPE_CHECKING
from pylint import config, reporters
+from pylint.config.exceptions import _UnrecognizedOptionError
from pylint.utils import utils
if TYPE_CHECKING:
@@ -50,7 +51,11 @@ def _config_initialization(
linter.load_plugin_modules(utils._splitstrip(config_data["load-plugins"]))
# First we parse any options from a configuration file
- linter._parse_configuration_file(config_args)
+ try:
+ linter._parse_configuration_file(config_args)
+ except _UnrecognizedOptionError as exc:
+ msg = ", ".join(exc.options)
+ linter.add_message("unrecognized-option", line=0, args=msg)
# Then, if a custom reporter is provided as argument, it may be overridden
# by file parameters, so we re-set it here. We do this before command line
@@ -66,6 +71,18 @@ def _config_initialization(
# the configuration file
parsed_args_list = linter._parse_command_line_configuration(args_list)
+ # Check if there are any options that we do not recognize
+ unrecognized_options: list[str] = []
+ for opt in parsed_args_list:
+ if opt.startswith("--"):
+ unrecognized_options.append(opt[2:])
+ elif opt.startswith("-"):
+ unrecognized_options.append(opt[1:])
+ if unrecognized_options:
+ msg = ", ".join(unrecognized_options)
+ linter.add_message("unrecognized-option", line=0, args=msg)
+ raise _UnrecognizedOptionError(options=unrecognized_options)
+
# Set the current module to configuration as we don't know where
# the --load-plugins key is coming from
linter.set_current_module("Command line or configuration file")
diff --git a/pylint/config/exceptions.py b/pylint/config/exceptions.py
index 25de13910..886dc19dc 100644
--- a/pylint/config/exceptions.py
+++ b/pylint/config/exceptions.py
@@ -2,6 +2,8 @@
# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
# Copyright (c) https://github.com/PyCQA/pylint/blob/main/CONTRIBUTORS.txt
+from __future__ import annotations
+
class UnrecognizedArgumentAction(Exception):
"""Raised if an ArgumentManager instance tries to add an argument for which the action
@@ -9,5 +11,13 @@ class UnrecognizedArgumentAction(Exception):
"""
+class _UnrecognizedOptionError(Exception):
+ """Raised if an ArgumentManager instance tries to parse an option that is unknown."""
+
+ def __init__(self, options: list[str], *args: object) -> None:
+ self.options = options
+ super().__init__(*args)
+
+
class ArgumentPreprocessingError(Exception):
"""Raised if an error occurs during argument preprocessing."""
diff --git a/pylint/lint/pylinter.py b/pylint/lint/pylinter.py
index 0f40edb64..4d586c635 100644
--- a/pylint/lint/pylinter.py
+++ b/pylint/lint/pylinter.py
@@ -182,6 +182,11 @@ MSGS = {
"bad-configuration-section",
"Used when we detect a setting in the top level of a toml configuration that shouldn't be there.",
),
+ "E0015": (
+ "Unrecognized option found: %s",
+ "unrecognized-option",
+ "Used when we detect an option that we do not recognize.",
+ ),
}
diff --git a/pylintrc b/pylintrc
index 6599dae10..3253109f3 100644
--- a/pylintrc
+++ b/pylintrc
@@ -217,9 +217,6 @@ single-line-if-stmt=no
# contains single statement.
single-line-class-stmt=no
-# List of optional constructs for which whitespace checking is disabled
-no-space-check=trailing-comma,dict-separator
-
# Maximum number of lines in a module
max-module-lines=2000
@@ -263,54 +260,36 @@ function-naming-style=snake_case
# Regular expression matching correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
-# Naming hint for function names
-function-name-hint=[a-z_][a-z0-9_]{2,30}$
-
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
-# Naming hint for variable names
-variable-name-hint=[a-z_][a-z0-9_]{2,30}$
-
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-# Naming hint for constant names
-const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names
attr-rgx=[a-z_][a-z0-9_]{2,}$
-# Naming hint for attribute names
-attr-name-hint=[a-z_][a-z0-9_]{2,}$
-
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
-# Naming hint for argument names
-argument-name-hint=[a-z_][a-z0-9_]{2,30}$
-
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-# Naming hint for class attribute names
-class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
# Naming style matching correct class constant names.
class-const-naming-style=UPPER_CASE
@@ -324,17 +303,12 @@ inlinevar-naming-style=any
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-# Naming hint for inline iteration names
-inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
-
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
-# Naming hint for class names
-class-name-hint=[A-Z_][a-zA-Z0-9]+$
# Naming style matching correct module names.
module-naming-style=snake_case
@@ -342,8 +316,6 @@ module-naming-style=snake_case
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-# Naming hint for module names
-module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Naming style matching correct method names.
method-naming-style=snake_case
@@ -351,9 +323,6 @@ method-naming-style=snake_case
# Regular expression matching correct method names
method-rgx=[a-z_][a-z0-9_]{2,}$
-# Naming hint for method names
-method-name-hint=[a-z_][a-z0-9_]{2,}$
-
# Regular expression which can overwrite the naming style set by typevar-naming-style.
#typevar-rgx=
diff --git a/tests/config/functional/toml/toml_with_unknown_option.2.out b/tests/config/functional/toml/toml_with_unknown_option.2.out
new file mode 100644
index 000000000..d244629c0
--- /dev/null
+++ b/tests/config/functional/toml/toml_with_unknown_option.2.out
@@ -0,0 +1,2 @@
+************* Module {abspath}
+{relpath}:1:0: E0015: Unrecognized option found: unknown-option, another-unknown-option (unrecognized-option)
diff --git a/tests/config/functional/toml/toml_with_unknown_option.result.json b/tests/config/functional/toml/toml_with_unknown_option.result.json
new file mode 100644
index 000000000..86a7b52ed
--- /dev/null
+++ b/tests/config/functional/toml/toml_with_unknown_option.result.json
@@ -0,0 +1,3 @@
+{
+ "jobs": 10
+}
diff --git a/tests/config/functional/toml/toml_with_unknown_option.toml b/tests/config/functional/toml/toml_with_unknown_option.toml
new file mode 100644
index 000000000..f0924ebfa
--- /dev/null
+++ b/tests/config/functional/toml/toml_with_unknown_option.toml
@@ -0,0 +1,6 @@
+# Check that we handle unknown options correctly
+
+[tool.pylint]
+unknown-option = "yes"
+jobs = "10"
+another-unknown-option = "yes"
diff --git a/tests/config/test_config.py b/tests/config/test_config.py
index 10e3fa4c1..f91e6cbf4 100644
--- a/tests/config/test_config.py
+++ b/tests/config/test_config.py
@@ -10,6 +10,7 @@ from pathlib import Path
import pytest
from pytest import CaptureFixture
+from pylint.config.exceptions import _UnrecognizedOptionError
from pylint.lint import Run
from pylint.testutils.configuration_test import run_using_a_configuration_file
@@ -61,6 +62,22 @@ def test_unknown_message_id(capsys: CaptureFixture) -> None:
assert "Command line:1:0: E0012: Bad option value for --disable." in output.out
+def test_unknown_option_name(capsys: CaptureFixture) -> None:
+ """Check that we correctly raise a message on an unknown option."""
+ with pytest.raises(_UnrecognizedOptionError):
+ Run([str(EMPTY_MODULE), "--unknown-option=yes"], exit=False)
+ output = capsys.readouterr()
+ assert "E0015: Unrecognized option found: unknown-option=yes" in output.out
+
+
+def test_unknown_short_option_name(capsys: CaptureFixture) -> None:
+ """Check that we correctly raise a message on an unknown short option."""
+ with pytest.raises(_UnrecognizedOptionError):
+ Run([str(EMPTY_MODULE), "-Q"], exit=False)
+ output = capsys.readouterr()
+ assert "E0015: Unrecognized option found: Q" in output.out
+
+
def test_unknown_confidence(capsys: CaptureFixture) -> None:
"""Check that we correctly error an unknown confidence value."""
with pytest.raises(SystemExit):
diff --git a/tests/regrtest_data/.pylintrc b/tests/regrtest_data/.pylintrc
deleted file mode 100644
index f5130379c..000000000
--- a/tests/regrtest_data/.pylintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-[MASTER]
-
-optimize-ast=no
diff --git a/tests/test_self.py b/tests/test_self.py
index e2b859a21..54bbf142a 100644
--- a/tests/test_self.py
+++ b/tests/test_self.py
@@ -425,11 +425,8 @@ class TestRunTC:
def test_bom_marker(self) -> None:
path = join(HERE, "regrtest_data", "meta.py")
- config_path = join(HERE, "regrtest_data", ".pylintrc")
expected = "Your code has been rated at 10.00/10"
- self._test_output(
- [path, f"--rcfile={config_path}", "-rn"], expected_output=expected
- )
+ self._test_output([path, "-rn"], expected_output=expected)
def test_pylintrc_plugin_duplicate_options(self) -> None:
dummy_plugin_path = join(HERE, "regrtest_data", "dummy_plugin")