Emit an error when entry points are duplicated

This avoids flake8 silently ignoring one of the plugins and
fixes https://gitlab.com/pycqa/flake8/-/issues/634.
This commit is contained in:
Peter Law 2020-05-08 13:10:26 +01:00
parent 03c7dd3a8d
commit acced5f62a
4 changed files with 52 additions and 0 deletions

View file

@ -1,6 +1,10 @@
"""Exception classes for all of Flake8."""
from typing import Dict
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
from flake8.plugins.manager import Plugin
from flake8._compat import importlib_metadata
class Flake8Exception(Exception):
"""Plain Flake8 exception."""
@ -14,6 +18,33 @@ class ExecutionError(Flake8Exception):
"""Exception raised during execution of Flake8."""
class DuplicatePluginEntryPoint(Flake8Exception):
"""Exception raised when a plugin entry point is already taken."""
FORMAT = (
'Plugin entry point "%(entry_point)s" for "%(new)s" already taken by '
'"%(existing)s"'
)
def __init__(self, entry_point, existing_plugin):
# type: (importlib_metadata.EntryPoint, Plugin) -> None
"""Initialize our DuplicatePluginEntryPoint exception."""
self.entry_point = entry_point
self.existing_plugin = existing_plugin
super(DuplicatePluginEntryPoint, self).__init__(
entry_point,
existing_plugin,
)
def __str__(self): # type: () -> str
"""Format our exception message."""
return self.FORMAT % {
"entry_point": self.entry_point.name,
"new": self.entry_point.value,
"existing": self.existing_plugin.entry_point.value,
}
class FailedToLoadPlugin(Flake8Exception):
"""Exception raised when a plugin fails to load."""

View file

@ -273,6 +273,12 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
Is this a repo-local plugin?
"""
name = entry_point.name
if name in self.plugins:
raise exceptions.DuplicatePluginEntryPoint(
entry_point, self.plugins[name],
)
self.plugins[name] = Plugin(name, entry_point, local=local)
self.names.append(name)
LOG.debug('Loaded %r for plugin "%s".', self.plugins[name], name)

View file

@ -0,0 +1,4 @@
[flake8:local-plugins]
extension =
XE = aplugin:ExtensionTestPluginA
XE = aplugin:ExtensionTestPluginB

View file

@ -1,9 +1,13 @@
"""Integration tests for plugin loading."""
import pytest
from flake8.main import application
from flake8 import exceptions
LOCAL_PLUGIN_CONFIG = 'tests/fixtures/config_files/local-plugin.ini'
LOCAL_PLUGIN_PATH_CONFIG = 'tests/fixtures/config_files/local-plugin-path.ini'
LOCAL_PLUGIN_DUPLICATE_CONFIG = 'tests/fixtures/config_files/local-plugin-duplicate-entry-point.ini'
class ExtensionTestPlugin(object):
@ -61,3 +65,10 @@ def test_enable_local_plugin_at_non_installed_path():
app.initialize(['flake8', '--config', LOCAL_PLUGIN_PATH_CONFIG])
assert app.check_plugins['XE'].plugin.name == 'ExtensionTestPlugin2'
def test_reject_local_plugins_with_duplicate_entry_point():
"""Reject duplicate entry points in local-plugins config section."""
with pytest.raises(exceptions.DuplicatePluginEntryPoint):
app = application.Application()
app.initialize(['flake8', '--config', LOCAL_PLUGIN_DUPLICATE_CONFIG])