Skip to content

Commit

Permalink
No crash on bad plugin provided in configuration file
Browse files Browse the repository at this point in the history
Raise an error 'bad-plugin-value' instead.
See #4555
  • Loading branch information
Pierre-Sassoulas committed Jun 17, 2021
1 parent 4dfaddf commit cbd3cc0
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 8 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Expand Up @@ -110,6 +110,11 @@ modules are added.

Closes #585

* Fix a crash when a plugin from the configuration could not be loaded and raise an error
'bad-plugin-value' instead

Closes #4555

* Added handling of floating point values when parsing configuration from pyproject.toml

Closes #4518
Expand Down
21 changes: 16 additions & 5 deletions pylint/lint/pylinter.py
Expand Up @@ -128,6 +128,11 @@ def _load_reporter_by_class(reporter_class: str) -> type:
"bad-option-value",
"Used when a bad value for an inline option is encountered.",
),
"E0013": (
"Plugin '%s' is impossible to load, is it installed ? ('%s')",
"bad-plugin-value",
"Used when a bad value is used in 'load-plugins'.",
),
}


Expand Down Expand Up @@ -531,8 +536,11 @@ def load_plugin_modules(self, modnames):
if modname in self._dynamic_plugins:
continue
self._dynamic_plugins.add(modname)
module = astroid.modutils.load_module_from_name(modname)
module.register(self)
try:
module = astroid.modutils.load_module_from_name(modname)
module.register(self)
except ModuleNotFoundError:
pass

def load_plugin_configuration(self):
"""Call the configuration hook for plugins
Expand All @@ -542,9 +550,12 @@ def load_plugin_configuration(self):
settings.
"""
for modname in self._dynamic_plugins:
module = astroid.modutils.load_module_from_name(modname)
if hasattr(module, "load_configuration"):
module.load_configuration(self)
try:
module = astroid.modutils.load_module_from_name(modname)
if hasattr(module, "load_configuration"):
module.load_configuration(self)
except ModuleNotFoundError as e:
self.add_message("bad-plugin-value", args=(modname, e), line=0)

def _load_reporters(self) -> None:
sub_reporters = []
Expand Down
16 changes: 15 additions & 1 deletion pylint/message/message_handler_mix_in.py
Expand Up @@ -274,6 +274,17 @@ def add_one_message(
# update stats
msg_cat = MSG_TYPES[message_definition.msgid[0]]
self.msg_status |= MSG_TYPES_STATUS[message_definition.msgid[0]]
if self.stats is None:
# pylint: disable=fixme
# TODO self.stats should make sense,
# class should make sense as soon as instantiated
# This is not true for Linter and Reporter at least
# pylint: enable=fixme
self.stats = {

This comment has been minimized.

Copy link
@Ark-kun

Ark-kun Feb 26, 2022

This initialization seems to only run once, but add_one_message can be called multiple times for different values of msg_cat.

This comment has been minimized.

Copy link
@Pierre-Sassoulas

Pierre-Sassoulas Feb 26, 2022

Author Member

I think you're right but we never had a key error in self.stats[msg_cat] += 1 so it's probably done in an underhanded way somewhere else.

This comment has been minimized.

Copy link
@Ark-kun

Ark-kun Mar 4, 2022

we never had a key error in self.stats[msg_cat] += 1

Well, the reason I found this place was because I just cannot make pylint==2.11.1 (+astroid 2.8.6) work. One project is using this specific pylint version as presubmit hook and fails if I use any other version.

Traceback (most recent call last):
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/lint/pylinter.py", line 577, in load_plugin_configuration
    module = astroid.modutils.load_module_from_name(modname)
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/astroid/modutils.py", line 218, in load_module_from_name
    return importlib.import_module(dotted_name)
  File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 984, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'pylint_plugins'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/google/home/avolkov/.local/bin/pylint", line 8, in <module>
    sys.exit(run_pylint())
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/__init__.py", line 24, in run_pylint
    PylintRun(sys.argv[1:])
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/lint/run.py", line 359, in __init__
    linter.load_plugin_configuration()
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/lint/pylinter.py", line 581, in load_plugin_configuration
    self.add_message("bad-plugin-value", args=(modname, e), line=0)
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/message/message_handler_mix_in.py", line 244, in add_message
    self.add_one_message(
  File "/usr/local/google/home/avolkov/.local/lib/python3.9/site-packages/pylint/message/message_handler_mix_in.py", line 306, in add_one_message
    self.stats[msg_cat] += 1
KeyError: 'error'

This comment has been minimized.

Copy link
@Pierre-Sassoulas

Pierre-Sassoulas Mar 4, 2022

Author Member

OK, I don't know how it happens exactly but let me open an issue for this and let's fix it.

This comment has been minimized.

Copy link
@Pierre-Sassoulas

Pierre-Sassoulas Mar 4, 2022

Author Member
msg_cat: 0,
"by_module": {self.current_name: {msg_cat: 0}},
"by_msg": {},
}
self.stats[msg_cat] += 1
self.stats["by_module"][self.current_name][msg_cat] += 1
try:
Expand All @@ -291,7 +302,10 @@ def add_one_message(
else:
module, obj = get_module_and_frameid(node)
abspath = node.root().file
path = abspath.replace(self.reporter.path_strip_prefix, "", 1)
if abspath is not None:
path = abspath.replace(self.reporter.path_strip_prefix, "", 1)
else:
path = "configuration"
# add the message
self.reporter.handle_message(
Message(
Expand Down
4 changes: 2 additions & 2 deletions pylint/reporters/text.py
Expand Up @@ -133,10 +133,10 @@ class TextReporter(BaseReporter):
def __init__(self, output=None):
BaseReporter.__init__(self, output)
self._modules = set()
self._template = None
self._template = self.line_format

def on_set_current_module(self, module, filepath):
self._template = str(self.linter.config.msg_template or self.line_format)
self._template = str(self.linter.config.msg_template or self._template)

def write_message(self, msg):
"""Convenience method to write a formatted message with class default template"""
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions tests/functional/p/plugin_does_not_exists.py
@@ -0,0 +1,5 @@
# pylint: disable=missing-docstring

from shadok import ShadokInteger # [import-error]

ShadokInteger("Buga ZoMeu")
3 changes: 3 additions & 0 deletions tests/functional/p/plugin_does_not_exists.rc
@@ -0,0 +1,3 @@
[master]
load-plugins=
pylint.extensions.check_does_not_exists_in_venv,
1 change: 1 addition & 0 deletions tests/functional/p/plugin_does_not_exists.txt
@@ -0,0 +1 @@
import-error:3:0::Unable to import 'shadok':HIGH

0 comments on commit cbd3cc0

Please sign in to comment.