mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-16 09:09:52 +00:00
Make Plugin.load_plugin raise a Flake8 exception
Let's catch exceptions, log them, and re-raise as a FailedToLoad exception. This also refactors the actually loading of plugins into a private method on the Plugin class.
This commit is contained in:
parent
6546cf41d4
commit
3b64ff2a1f
3 changed files with 62 additions and 12 deletions
25
flake8/exceptions.py
Normal file
25
flake8/exceptions.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"""Exception classes for all of Flake8."""
|
||||||
|
|
||||||
|
|
||||||
|
class Flake8Exception(Exception):
|
||||||
|
"""Plain Flake8 exception."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FailedToLoadPlugin(Flake8Exception):
|
||||||
|
"""Exception raised when a plugin fails to load."""
|
||||||
|
|
||||||
|
FORMAT = 'Flake8 failed to load plugin "%(name)s" due to %(exc)s.'
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Initialize our FailedToLoadPlugin exception."""
|
||||||
|
self.plugin = kwargs.pop('plugin')
|
||||||
|
self.ep_name = self.plugin.name
|
||||||
|
self.original_exception = kwargs.pop('exception')
|
||||||
|
super(FailedToLoadPlugin, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""Return a nice string for our exception."""
|
||||||
|
return self.FORMAT % {'name': self.ep_name,
|
||||||
|
'exc': self.original_exception}
|
||||||
|
|
@ -5,6 +5,7 @@ import logging
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
|
|
||||||
from flake8 import _trie
|
from flake8 import _trie
|
||||||
|
from flake8 import exceptions
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -58,6 +59,21 @@ class Plugin(object):
|
||||||
r"""Call the plugin with \*args and \*\*kwargs."""
|
r"""Call the plugin with \*args and \*\*kwargs."""
|
||||||
return self.plugin(*args, **kwargs)
|
return self.plugin(*args, **kwargs)
|
||||||
|
|
||||||
|
def _load(self, verify_requirements):
|
||||||
|
# Avoid relying on hasattr() here.
|
||||||
|
resolve = getattr(self.entry_point, 'resolve', None)
|
||||||
|
require = getattr(self.entry_point, 'require', None)
|
||||||
|
if resolve and require:
|
||||||
|
if verify_requirements:
|
||||||
|
LOG.debug('Verifying plugin "%s"\'s requirements.',
|
||||||
|
self.name)
|
||||||
|
require()
|
||||||
|
self._plugin = resolve()
|
||||||
|
else:
|
||||||
|
self._plugin = self.entry_point.load(
|
||||||
|
require=verify_requirements
|
||||||
|
)
|
||||||
|
|
||||||
def load_plugin(self, verify_requirements=False):
|
def load_plugin(self, verify_requirements=False):
|
||||||
"""Retrieve the plugin for this entry-point.
|
"""Retrieve the plugin for this entry-point.
|
||||||
|
|
||||||
|
|
@ -73,19 +89,16 @@ class Plugin(object):
|
||||||
"""
|
"""
|
||||||
if self._plugin is None:
|
if self._plugin is None:
|
||||||
LOG.debug('Loading plugin "%s" from entry-point.', self.name)
|
LOG.debug('Loading plugin "%s" from entry-point.', self.name)
|
||||||
# Avoid relying on hasattr() here.
|
try:
|
||||||
resolve = getattr(self.entry_point, 'resolve', None)
|
self._load(verify_requirements)
|
||||||
require = getattr(self.entry_point, 'require', None)
|
except Exception as load_exception:
|
||||||
if resolve and require:
|
LOG.exception(load_exception, exc_info=True)
|
||||||
if verify_requirements:
|
failed_to_load = exceptions.FailedToLoadPlugin(
|
||||||
LOG.debug('Verifying plugin "%s"\'s requirements.',
|
plugin=self,
|
||||||
self.name)
|
exception=load_exception,
|
||||||
require()
|
|
||||||
self._plugin = resolve()
|
|
||||||
else:
|
|
||||||
self._plugin = self.entry_point.load(
|
|
||||||
require=verify_requirements
|
|
||||||
)
|
)
|
||||||
|
LOG.critical(str(failed_to_load))
|
||||||
|
raise failed_to_load
|
||||||
|
|
||||||
def provide_options(self, optmanager, options, extra_args):
|
def provide_options(self, optmanager, options, extra_args):
|
||||||
"""Pass the parsed options and extra arguments to the plugin."""
|
"""Pass the parsed options and extra arguments to the plugin."""
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
"""Tests for flake8.plugins.manager.Plugin."""
|
"""Tests for flake8.plugins.manager.Plugin."""
|
||||||
import mock
|
import mock
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from flake8 import exceptions
|
||||||
from flake8.plugins import manager
|
from flake8.plugins import manager
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,6 +50,16 @@ def test_load_plugin_only_calls_require_when_verifying_requirements():
|
||||||
entry_point.resolve.assert_called_once_with()
|
entry_point.resolve.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_plugin_catches_and_reraises_exceptions():
|
||||||
|
"""Verify we raise our own FailedToLoadPlugin."""
|
||||||
|
entry_point = mock.Mock(spec=['require', 'resolve'])
|
||||||
|
entry_point.resolve.side_effect = ValueError('Test failure')
|
||||||
|
plugin = manager.Plugin('T000', entry_point)
|
||||||
|
|
||||||
|
with pytest.raises(exceptions.FailedToLoadPlugin):
|
||||||
|
plugin.load_plugin()
|
||||||
|
|
||||||
|
|
||||||
def test_plugin_property_loads_plugin_on_first_use():
|
def test_plugin_property_loads_plugin_on_first_use():
|
||||||
"""Verify that we load our plugin when we first try to use it."""
|
"""Verify that we load our plugin when we first try to use it."""
|
||||||
entry_point = mock.Mock(spec=['require', 'resolve', 'load'])
|
entry_point = mock.Mock(spec=['require', 'resolve', 'load'])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue