summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--setup.cfg2
-rw-r--r--src/flake8/_compat.py14
-rw-r--r--src/flake8/exceptions.py15
-rw-r--r--src/flake8/main/application.py4
-rw-r--r--src/flake8/main/debug.py7
-rw-r--r--src/flake8/plugins/manager.py14
-rw-r--r--src/flake8/style_guide.py8
-rw-r--r--tests/integration/test_checker.py7
-rw-r--r--tests/unit/test_debug.py8
-rw-r--r--tests/unit/test_exceptions.py8
-rw-r--r--tests/unit/test_plugin_manager.py58
-rw-r--r--tests/unit/test_plugin_type_manager.py2
12 files changed, 71 insertions, 76 deletions
diff --git a/setup.cfg b/setup.cfg
index a83dce8..f482ec0 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -41,7 +41,6 @@ install_requires=
# http://flake8.pycqa.org/en/latest/faq.html#why-does-flake8-use-ranges-for-its-dependencies
# And in which releases we will update those ranges here:
# http://flake8.pycqa.org/en/latest/internal/releases.html#releasing-flake8
- entrypoints >= 0.3.0, < 0.4.0
pyflakes >= 2.1.0, < 2.2.0
pycodestyle >= 2.5.0, < 2.6.0
mccabe >= 0.6.0, < 0.7.0
@@ -49,6 +48,7 @@ install_requires=
typing; python_version<"3.5"
configparser; python_version<"3.2"
functools32; python_version<"3.2"
+ importlib-metadata; python_version<"3.8"
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
diff --git a/src/flake8/_compat.py b/src/flake8/_compat.py
new file mode 100644
index 0000000..85af0a3
--- /dev/null
+++ b/src/flake8/_compat.py
@@ -0,0 +1,14 @@
+"""Expose backports in a single place."""
+import sys
+
+if sys.version_info >= (3,): # pragma: no cover (PY3+)
+ from functools import lru_cache
+else: # pragma: no cover (<PY3)
+ from functools32 import lru_cache
+
+if sys.version_info >= (3, 8): # pragma: no cover (PY38+)
+ import importlib.metadata as importlib_metadata
+else: # pragma: no cover (<PY38)
+ import importlib_metadata
+
+__all__ = ("lru_cache", "importlib_metadata")
diff --git a/src/flake8/exceptions.py b/src/flake8/exceptions.py
index 53ca4b7..bef6f4b 100644
--- a/src/flake8/exceptions.py
+++ b/src/flake8/exceptions.py
@@ -1,10 +1,6 @@
"""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
-
class Flake8Exception(Exception):
"""Plain Flake8 exception."""
@@ -23,18 +19,17 @@ class FailedToLoadPlugin(Flake8Exception):
FORMAT = 'Flake8 failed to load plugin "%(name)s" due to %(exc)s.'
- def __init__(self, plugin, exception):
- # type: (Plugin, Exception) -> None
+ def __init__(self, plugin_name, exception):
+ # type: (str, Exception) -> None
"""Initialize our FailedToLoadPlugin exception."""
- self.plugin = plugin
- self.ep_name = self.plugin.name
+ self.plugin_name = plugin_name
self.original_exception = exception
- super(FailedToLoadPlugin, self).__init__(plugin, exception)
+ super(FailedToLoadPlugin, self).__init__(plugin_name, exception)
def __str__(self): # type: () -> str
"""Format our exception message."""
return self.FORMAT % {
- "name": self.ep_name,
+ "name": self.plugin_name,
"exc": self.original_exception,
}
diff --git a/src/flake8/main/application.py b/src/flake8/main/application.py
index 42e365f..a20c1d4 100644
--- a/src/flake8/main/application.py
+++ b/src/flake8/main/application.py
@@ -168,9 +168,7 @@ class Application(object):
sys.path.extend(local_plugins.paths)
- self.check_plugins = plugin_manager.Checkers(
- local_plugins.extension
- )
+ self.check_plugins = plugin_manager.Checkers(local_plugins.extension)
self.formatting_plugins = plugin_manager.ReportFormatters(
local_plugins.report
diff --git a/src/flake8/main/debug.py b/src/flake8/main/debug.py
index 1d56189..83a5a11 100644
--- a/src/flake8/main/debug.py
+++ b/src/flake8/main/debug.py
@@ -4,8 +4,7 @@ from __future__ import print_function
import argparse
import json
import platform
-
-import entrypoints
+from typing import Dict, List
class DebugAction(argparse.Action):
@@ -61,6 +60,6 @@ def plugins_from(option_manager):
]
-def dependencies():
+def dependencies(): # type: () -> List[Dict[str, str]]
"""Generate the list of dependencies we care about."""
- return [{"dependency": "entrypoints", "version": entrypoints.__version__}]
+ return []
diff --git a/src/flake8/plugins/manager.py b/src/flake8/plugins/manager.py
index 75cc1ab..903a130 100644
--- a/src/flake8/plugins/manager.py
+++ b/src/flake8/plugins/manager.py
@@ -2,10 +2,9 @@
import logging
from typing import Any, Dict, List, Optional, Set
-import entrypoints
-
from flake8 import exceptions
from flake8 import utils
+from flake8._compat import importlib_metadata
LOG = logging.getLogger(__name__)
@@ -159,7 +158,7 @@ class Plugin(object):
except Exception as load_exception:
LOG.exception(load_exception)
failed_to_load = exceptions.FailedToLoadPlugin(
- plugin=self, exception=load_exception
+ plugin_name=self.name, exception=load_exception
)
LOG.critical(str(failed_to_load))
raise failed_to_load
@@ -224,6 +223,7 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
"""Find and manage plugins consistently."""
def __init__(self, namespace, local_plugins=None):
+ # type: (str, Optional[List[str]]) -> None
"""Initialize the manager.
:param str namespace:
@@ -246,12 +246,16 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
for plugin_str in local_plugins:
name, _, entry_str = plugin_str.partition("=")
name, entry_str = name.strip(), entry_str.strip()
- entry_point = entrypoints.EntryPoint.from_string(entry_str, name)
+ entry_point = importlib_metadata.EntryPoint(name, entry_str, None)
self._load_plugin_from_entrypoint(entry_point, local=True)
def _load_entrypoint_plugins(self):
LOG.info('Loading entry-points for "%s".', self.namespace)
- for entry_point in entrypoints.get_group_all(self.namespace):
+ eps = importlib_metadata.entry_points().get(self.namespace, ())
+ # python2.7 occasionally gives duplicate results due to redundant
+ # `local/lib` -> `../lib` symlink on linux in virtualenvs so we
+ # eliminate duplicates here
+ for entry_point in sorted(frozenset(eps)):
if entry_point.name == "per-file-ignores":
LOG.warning(
"flake8-per-file-ignores plugin is incompatible with "
diff --git a/src/flake8/style_guide.py b/src/flake8/style_guide.py
index ef9c6e9..9be0fe8 100644
--- a/src/flake8/style_guide.py
+++ b/src/flake8/style_guide.py
@@ -7,13 +7,13 @@ import enum
import itertools
import linecache
import logging
-import sys
from typing import Dict, Generator, List, Match, Optional, Sequence, Set
from typing import Tuple, Union
from flake8 import defaults
from flake8 import statistics
from flake8 import utils
+from flake8._compat import lru_cache
from flake8.formatting import base as base_formatter
__all__ = ("StyleGuide",)
@@ -21,12 +21,6 @@ __all__ = ("StyleGuide",)
LOG = logging.getLogger(__name__)
-if sys.version_info < (3, 2):
- from functools32 import lru_cache
-else:
- from functools import lru_cache
-
-
class Selected(enum.Enum):
"""Enum representing an explicitly or implicitly selected code."""
diff --git a/tests/integration/test_checker.py b/tests/integration/test_checker.py
index ca3ed4f..0c14474 100644
--- a/tests/integration/test_checker.py
+++ b/tests/integration/test_checker.py
@@ -3,6 +3,7 @@ import mock
import pytest
from flake8 import checker
+from flake8._compat import importlib_metadata
from flake8.plugins import manager
PHYSICAL_LINE = "# Physical line content"
@@ -100,7 +101,11 @@ def mock_file_checker_with_plugin(plugin_target):
entry_point.load.return_value = plugin_target
# Load the checker plugins using the entry point mock
- with mock.patch('entrypoints.get_group_all', return_value=[entry_point]):
+ with mock.patch.object(
+ importlib_metadata,
+ 'entry_points',
+ return_value={'flake8.extension': [entry_point]},
+ ):
checks = manager.Checkers()
# Prevent it from reading lines from stdin or somewhere else
diff --git a/tests/unit/test_debug.py b/tests/unit/test_debug.py
index c973abb..6398cf9 100644
--- a/tests/unit/test_debug.py
+++ b/tests/unit/test_debug.py
@@ -1,5 +1,4 @@
"""Tests for our debugging module."""
-import entrypoints
import mock
import pytest
@@ -9,9 +8,7 @@ from flake8.options import manager
def test_dependencies():
"""Verify that we format our dependencies appropriately."""
- expected = [{'dependency': 'entrypoints',
- 'version': entrypoints.__version__}]
- assert expected == debug.dependencies()
+ assert [] == debug.dependencies()
@pytest.mark.parametrize('plugins, expected', [
@@ -46,8 +43,7 @@ def test_information(system, pyversion, pyimpl):
'is_local': False},
{'plugin': 'pycodestyle', 'version': '2.0.0',
'is_local': False}],
- 'dependencies': [{'dependency': 'entrypoints',
- 'version': entrypoints.__version__}],
+ 'dependencies': [],
'platform': {
'python_implementation': 'CPython',
'python_version': '3.5.3',
diff --git a/tests/unit/test_exceptions.py b/tests/unit/test_exceptions.py
index 4766b78..0254cb2 100644
--- a/tests/unit/test_exceptions.py
+++ b/tests/unit/test_exceptions.py
@@ -1,10 +1,7 @@
"""Tests for the flake8.exceptions module."""
import pickle
-import entrypoints
-
from flake8 import exceptions
-from flake8.plugins import manager as plugins_manager
class _ExceptionTest:
@@ -22,10 +19,7 @@ class TestFailedToLoadPlugin(_ExceptionTest):
"""Tests for the FailedToLoadPlugin exception."""
err = exceptions.FailedToLoadPlugin(
- plugin=plugins_manager.Plugin(
- 'plugin_name',
- entrypoints.EntryPoint('plugin_name', 'os.path', None),
- ),
+ plugin_name='plugin_name',
exception=ValueError('boom!'),
)
diff --git a/tests/unit/test_plugin_manager.py b/tests/unit/test_plugin_manager.py
index 72959b0..9ad6aba 100644
--- a/tests/unit/test_plugin_manager.py
+++ b/tests/unit/test_plugin_manager.py
@@ -1,62 +1,58 @@
"""Tests for flake8.plugins.manager.PluginManager."""
import mock
+from flake8._compat import importlib_metadata
from flake8.plugins import manager
-def create_entry_point_mock(name):
- """Create a mocked EntryPoint."""
- ep = mock.Mock(spec=['name'])
- ep.name = name
- return ep
-
-
-@mock.patch('entrypoints.get_group_all')
-def test_calls_entrypoints_on_instantiation(get_group_all):
- """Verify that we call get_group_all when we create a manager."""
- get_group_all.return_value = []
+@mock.patch.object(importlib_metadata, 'entry_points')
+def test_calls_entrypoints_on_instantiation(entry_points_mck):
+ """Verify that we call entry_points() when we create a manager."""
+ entry_points_mck.return_value = {}
manager.PluginManager(namespace='testing.entrypoints')
-
- get_group_all.assert_called_once_with('testing.entrypoints')
+ entry_points_mck.assert_called_once_with()
-@mock.patch('entrypoints.get_group_all')
-def test_calls_entrypoints_creates_plugins_automaticaly(get_group_all):
+@mock.patch.object(importlib_metadata, 'entry_points')
+def test_calls_entrypoints_creates_plugins_automaticaly(entry_points_mck):
"""Verify that we create Plugins on instantiation."""
- get_group_all.return_value = [
- create_entry_point_mock('T100'),
- create_entry_point_mock('T200'),
- ]
+ entry_points_mck.return_value = {
+ 'testing.entrypoints': [
+ importlib_metadata.EntryPoint('T100', '', None),
+ importlib_metadata.EntryPoint('T200', '', None),
+ ],
+ }
plugin_mgr = manager.PluginManager(namespace='testing.entrypoints')
- get_group_all.assert_called_once_with('testing.entrypoints')
+ entry_points_mck.assert_called_once_with()
assert 'T100' in plugin_mgr.plugins
assert 'T200' in plugin_mgr.plugins
assert isinstance(plugin_mgr.plugins['T100'], manager.Plugin)
assert isinstance(plugin_mgr.plugins['T200'], manager.Plugin)
-@mock.patch('entrypoints.get_group_all')
-def test_handles_mapping_functions_across_plugins(get_group_all):
+@mock.patch.object(importlib_metadata, 'entry_points')
+def test_handles_mapping_functions_across_plugins(entry_points_mck):
"""Verify we can use the PluginManager call functions on all plugins."""
- entry_point_mocks = [
- create_entry_point_mock('T100'),
- create_entry_point_mock('T200'),
- ]
- get_group_all.return_value = entry_point_mocks
+ entry_points_mck.return_value = {
+ 'testing.entrypoints': [
+ importlib_metadata.EntryPoint('T100', '', None),
+ importlib_metadata.EntryPoint('T200', '', None),
+ ],
+ }
plugin_mgr = manager.PluginManager(namespace='testing.entrypoints')
plugins = [plugin_mgr.plugins[name] for name in plugin_mgr.names]
assert list(plugin_mgr.map(lambda x: x)) == plugins
-@mock.patch('entrypoints.get_group_all')
-def test_local_plugins(get_group_all):
+@mock.patch.object(importlib_metadata, 'entry_points')
+def test_local_plugins(entry_points_mck):
"""Verify PluginManager can load given local plugins."""
- get_group_all.return_value = []
+ entry_points_mck.return_value = {}
plugin_mgr = manager.PluginManager(
namespace='testing.entrypoints',
local_plugins=['X = path.to:Plugin']
)
- assert plugin_mgr.plugins['X'].entry_point.module_name == 'path.to'
+ assert plugin_mgr.plugins['X'].entry_point.value == 'path.to:Plugin'
diff --git a/tests/unit/test_plugin_type_manager.py b/tests/unit/test_plugin_type_manager.py
index 4174c58..939aa8c 100644
--- a/tests/unit/test_plugin_type_manager.py
+++ b/tests/unit/test_plugin_type_manager.py
@@ -13,7 +13,7 @@ def create_plugin_mock(raise_exception=False):
plugin = mock.create_autospec(manager.Plugin, instance=True)
if raise_exception:
plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin(
- plugin=mock.Mock(name='T101'),
+ plugin_name='T101',
exception=ValueError('Test failure'),
)
return plugin