rework plugin loading

This commit is contained in:
Anthony Sottile 2021-12-31 13:11:00 -08:00
parent 38c5eceda9
commit 50d69150c1
36 changed files with 1277 additions and 1505 deletions

View file

@ -1,22 +0,0 @@
About this directory
====================
The files in this directory are test fixtures for unit and integration tests.
Their purpose is described below. Please note the list of file names that can
not be created as they are already used by tests.
New fixtures are preferred over updating existing features unless existing
tests will fail.
Files that should not be created
--------------------------------
- ``tests/fixtures/config_files/missing.ini``
Purposes of existing fixtures
-----------------------------
``tests/fixtures/config_files/local-plugin.ini``
This is for testing configuring a plugin via flake8 config file instead of
setuptools entry-point.

View file

@ -1,5 +0,0 @@
[flake8:local-plugins]
extension =
XE = aplugin:ExtensionTestPlugin2
paths =
../../integration/subdir/

View file

@ -1,5 +0,0 @@
[flake8:local-plugins]
extension =
XE = tests.integration.test_plugins:ExtensionTestPlugin
report =
XR = tests.integration.test_plugins:ReportTestPlugin

View file

@ -4,9 +4,6 @@
class ExtensionTestPlugin2:
"""Extension test plugin in its own directory."""
name = "ExtensionTestPlugin2"
version = "1.0.0"
def __init__(self, tree):
"""Construct an instance of test plugin."""

View file

@ -6,28 +6,19 @@ import pytest
from flake8 import checker
from flake8._compat import importlib_metadata
from flake8.plugins import manager
from flake8.plugins import finder
from flake8.processor import FileProcessor
PHYSICAL_LINE = "# Physical line content"
EXPECTED_REPORT = (1, 1, "T000 Expected Message")
EXPECTED_REPORT_PHYSICAL_LINE = (1, "T000 Expected Message")
EXPECTED_RESULT_PHYSICAL_LINE = (
"T000",
0,
1,
"Expected Message",
None,
)
EXPECTED_RESULT_PHYSICAL_LINE = ("T000", 0, 1, "Expected Message", None)
class PluginClass:
"""Simple file plugin class yielding the expected report."""
name = "test"
version = "1.0.0"
def __init__(self, tree):
"""Construct a dummy object to provide mandatory parameter."""
pass
@ -37,87 +28,78 @@ class PluginClass:
yield EXPECTED_REPORT + (type(self),)
def plugin_func(func):
"""Decorate file plugins which are implemented as functions."""
func.name = "test"
func.version = "1.0.0"
return func
@plugin_func
def plugin_func_gen(tree):
"""Yield the expected report."""
yield EXPECTED_REPORT + (type(plugin_func_gen),)
@plugin_func
def plugin_func_list(tree):
"""Return a list of expected reports."""
return [EXPECTED_REPORT + (type(plugin_func_list),)]
@plugin_func
def plugin_func_physical_ret(physical_line):
"""Expect report from a physical_line. Single return."""
return EXPECTED_REPORT_PHYSICAL_LINE
@plugin_func
def plugin_func_physical_none(physical_line):
"""Expect report from a physical_line. No results."""
return None
@plugin_func
def plugin_func_physical_list_single(physical_line):
"""Expect report from a physical_line. List of single result."""
return [EXPECTED_REPORT_PHYSICAL_LINE]
@plugin_func
def plugin_func_physical_list_multiple(physical_line):
"""Expect report from a physical_line. List of multiple results."""
return [EXPECTED_REPORT_PHYSICAL_LINE] * 2
@plugin_func
def plugin_func_physical_gen_single(physical_line):
"""Expect report from a physical_line. Generator of single result."""
yield EXPECTED_REPORT_PHYSICAL_LINE
@plugin_func
def plugin_func_physical_gen_multiple(physical_line):
"""Expect report from a physical_line. Generator of multiple results."""
for _ in range(3):
yield EXPECTED_REPORT_PHYSICAL_LINE
def plugin_func_out_of_bounds(logical_line):
"""This produces an error out of bounds."""
yield 10000, "L100 test"
def mock_file_checker_with_plugin(plugin_target):
"""Get a mock FileChecker class with plugin_target registered.
Useful as a starting point for mocking reports/results.
"""
# Mock an entry point returning the plugin target
entry_point = mock.Mock(spec=["load"])
entry_point.name = plugin_target.name
entry_point.load.return_value = plugin_target
entry_point.value = "mocked:value"
# Load the checker plugins using the entry point mock
with mock.patch.object(
importlib_metadata,
"entry_points",
return_value={"flake8.extension": [entry_point]},
):
checks = manager.Checkers()
to_load = [
finder.Plugin(
"flake-package",
"9001",
importlib_metadata.EntryPoint(
"Q",
f"{plugin_target.__module__}:{plugin_target.__name__}",
"flake8.extension",
),
),
]
plugins = finder.load_plugins(to_load, [])
# Prevent it from reading lines from stdin or somewhere else
with mock.patch(
"flake8.processor.FileProcessor.read_lines", return_value=["Line 1"]
):
file_checker = checker.FileChecker(
"-", checks.to_dictionary(), mock.MagicMock()
filename="-",
plugins=plugins.checkers,
options=mock.MagicMock(),
)
return file_checker
@ -173,11 +155,7 @@ def test_line_check_results(plugin_target, len_results):
def test_logical_line_offset_out_of_bounds():
"""Ensure that logical line offsets that are out of bounds do not crash."""
@plugin_func
def _logical_line_out_of_bounds(logical_line):
yield 10000, "L100 test"
file_checker = mock_file_checker_with_plugin(_logical_line_out_of_bounds)
file_checker = mock_file_checker_with_plugin(plugin_func_out_of_bounds)
logical_ret = (
"",
@ -293,7 +271,7 @@ def test_report_order(results, expected_order):
# Create a placeholder manager without arguments or plugins
# Just add one custom file checker which just provides the results
manager = checker.Manager(style_guide, [])
manager = checker.Manager(style_guide, finder.Checkers([], [], []))
manager.checkers = manager._all_checkers = [file_checker]
# _handle_results is the first place which gets the sorted result
@ -357,6 +335,10 @@ def test_handling_syntaxerrors_across_pythons():
"invalid syntax", ("<unknown>", 2, 1, "bad python:\n", 2, 11)
)
expected = (2, 1)
file_checker = checker.FileChecker("-", {}, mock.MagicMock())
file_checker = checker.FileChecker(
filename="-",
plugins=finder.Checkers([], [], []),
options=mock.MagicMock(),
)
actual = file_checker._extract_syntax_information(err)
assert actual == expected

View file

@ -1,17 +1,18 @@
"""Integration tests for plugin loading."""
from flake8.main import application
from flake8.main.cli import main
import pytest
LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.ini"
LOCAL_PLUGIN_PATH_CONFIG = "tests/fixtures/config_files/local-plugin-path.ini"
from flake8.main.cli import main
from flake8.main.options import register_default_options
from flake8.main.options import stage1_arg_parser
from flake8.options import aggregator
from flake8.options import config
from flake8.options.manager import OptionManager
from flake8.plugins import finder
class ExtensionTestPlugin:
"""Extension test plugin."""
name = "ExtensionTestPlugin"
version = "1.0.0"
def __init__(self, tree):
"""Construct an instance of test plugin."""
@ -27,9 +28,6 @@ class ExtensionTestPlugin:
class ReportTestPlugin:
"""Report test plugin."""
name = "ReportTestPlugin"
version = "1.0.0"
def __init__(self, tree):
"""Construct an instance of test plugin."""
@ -37,41 +35,69 @@ class ReportTestPlugin:
"""Do nothing."""
def test_enable_local_plugin_from_config():
@pytest.fixture
def local_config(tmp_path):
cfg_s = f"""\
[flake8:local-plugins]
extension =
XE = {ExtensionTestPlugin.__module__}:{ExtensionTestPlugin.__name__}
report =
XR = {ReportTestPlugin.__module__}:{ReportTestPlugin.__name__}
"""
cfg = tmp_path.joinpath("tox.ini")
cfg.write_text(cfg_s)
return str(cfg)
def test_enable_local_plugin_from_config(local_config):
"""App can load a local plugin from config file."""
app = application.Application()
app.initialize(["flake8", "--config", LOCAL_PLUGIN_CONFIG])
cfg, cfg_dir = config.load_config(local_config, [], isolated=False)
plugins = finder.find_plugins(cfg)
plugin_paths = finder.find_local_plugin_paths(cfg, cfg_dir)
loaded_plugins = finder.load_plugins(plugins, plugin_paths)
assert app.check_plugins is not None
assert app.check_plugins["XE"].plugin is ExtensionTestPlugin
assert app.formatting_plugins is not None
assert app.formatting_plugins["XR"].plugin is ReportTestPlugin
(custom_extension,) = (
loaded
for loaded in loaded_plugins.checkers.tree
if loaded.entry_name == "XE"
)
custom_report = loaded_plugins.reporters["XR"]
assert custom_extension.obj is ExtensionTestPlugin
assert custom_report.obj is ReportTestPlugin
def test_local_plugin_can_add_option():
def test_local_plugin_can_add_option(local_config):
"""A local plugin can add a CLI option."""
app = application.Application()
app.initialize(
["flake8", "--config", LOCAL_PLUGIN_CONFIG, "--anopt", "foo"]
argv = ["--config", local_config, "--anopt", "foo"]
stage1_parser = stage1_arg_parser()
stage1_args, rest = stage1_parser.parse_known_args(argv)
cfg, cfg_dir = config.load_config(
config=stage1_args.config, extra=[], isolated=False
)
assert app.options is not None
assert app.options.anopt == "foo"
plugins = finder.find_plugins(cfg)
plugin_paths = finder.find_local_plugin_paths(cfg, cfg_dir)
loaded_plugins = finder.load_plugins(plugins, plugin_paths)
option_manager = OptionManager(
version="123",
plugin_versions="",
parents=[stage1_parser],
)
register_default_options(option_manager)
option_manager.register_plugins(loaded_plugins)
def test_enable_local_plugin_at_non_installed_path():
"""Can add a paths option in local-plugins config section for finding."""
app = application.Application()
app.initialize(["flake8", "--config", LOCAL_PLUGIN_PATH_CONFIG])
args = aggregator.aggregate_options(option_manager, cfg, cfg_dir, argv)
assert app.check_plugins is not None
assert app.check_plugins["XE"].plugin.name == "ExtensionTestPlugin2"
assert args.anopt == "foo"
class AlwaysErrors:
name = "AlwaysError"
version = "1"
def __init__(self, tree):
pass

View file

View file

@ -0,0 +1,610 @@
import configparser
import sys
from unittest import mock
import pytest
from flake8._compat import importlib_metadata
from flake8.exceptions import FailedToLoadPlugin
from flake8.plugins import finder
from flake8.plugins.pyflakes import FlakesChecker
def _ep(name="X", value="dne:dne", group="flake8.extension"):
return importlib_metadata.EntryPoint(name, value, group)
def _plugin(package="local", version="local", ep=None):
if ep is None:
ep = _ep()
return finder.Plugin(package, version, ep)
def _loaded(plugin=None, obj=None, parameters=None):
if plugin is None:
plugin = _plugin()
if parameters is None:
parameters = {"tree": True}
return finder.LoadedPlugin(plugin, obj, parameters)
def test_loaded_plugin_entry_name_vs_display_name():
loaded = _loaded(_plugin(package="package-name", ep=_ep(name="Q")))
assert loaded.entry_name == "Q"
assert loaded.display_name == "package-name[Q]"
def test_plugins_all_plugins():
tree_plugin = _loaded(parameters={"tree": True})
logical_line_plugin = _loaded(parameters={"logical_line": True})
physical_line_plugin = _loaded(parameters={"physical_line": True})
report_plugin = _loaded(
plugin=_plugin(ep=_ep(name="R", group="flake8.report"))
)
plugins = finder.Plugins(
checkers=finder.Checkers(
tree=[tree_plugin],
logical_line=[logical_line_plugin],
physical_line=[physical_line_plugin],
),
reporters={"R": report_plugin},
)
assert tuple(plugins.all_plugins()) == (
tree_plugin,
logical_line_plugin,
physical_line_plugin,
report_plugin,
)
def test_plugins_versions_str():
plugins = finder.Plugins(
checkers=finder.Checkers(
tree=[_loaded(_plugin(package="pkg1", version="1"))],
logical_line=[_loaded(_plugin(package="pkg2", version="2"))],
physical_line=[_loaded(_plugin(package="pkg1", version="1"))],
),
reporters={
# ignore flake8 builtin plugins
"default": _loaded(_plugin(package="flake8")),
# ignore local plugins
"custom": _loaded(_plugin(package="local")),
},
)
assert plugins.versions_str() == "pkg1: 1, pkg2: 2"
@pytest.fixture
def pyflakes_dist(tmp_path):
metadata = """\
Metadata-Version: 2.1
Name: pyflakes
Version: 9000.1.0
"""
d = tmp_path.joinpath("pyflakes.dist-info")
d.mkdir()
d.joinpath("METADATA").write_text(metadata)
return importlib_metadata.PathDistribution(d)
@pytest.fixture
def pycodestyle_dist(tmp_path):
metadata = """\
Metadata-Version: 2.1
Name: pycodestyle
Version: 9000.2.0
"""
d = tmp_path.joinpath("pycodestyle.dist-info")
d.mkdir()
d.joinpath("METADATA").write_text(metadata)
return importlib_metadata.PathDistribution(d)
@pytest.fixture
def flake8_dist(tmp_path):
metadata = """\
Metadata-Version: 2.1
Name: flake8
Version: 9001
"""
entry_points = """\
[console_scripts]
flake8 = flake8.main.cli:main
[flake8.extension]
F = flake8.plugins.pyflakes:FlakesChecker
pycodestyle.bare_except = pycodestyle:bare_except
pycodestyle.blank_lines = pycodestyle:blank_lines
[flake8.report]
default = flake8.formatting.default:Default
pylint = flake8.formatting.default:Pylint
"""
d = tmp_path.joinpath("flake8.dist-info")
d.mkdir()
d.joinpath("METADATA").write_text(metadata)
d.joinpath("entry_points.txt").write_text(entry_points)
return importlib_metadata.PathDistribution(d)
@pytest.fixture
def flake8_foo_dist(tmp_path):
metadata = """\
Metadata-Version: 2.1
Name: flake8-foo
Version: 1.2.3
"""
eps = """\
[console_scripts]
foo = flake8_foo:main
[flake8.extension]
Q = flake8_foo:Plugin
[flake8.report]
foo = flake8_foo:Formatter
"""
d = tmp_path.joinpath("flake8_foo.dist-info")
d.mkdir()
d.joinpath("METADATA").write_text(metadata)
d.joinpath("entry_points.txt").write_text(eps)
return importlib_metadata.PathDistribution(d)
@pytest.fixture
def mock_distribution(pyflakes_dist, pycodestyle_dist):
dists = {"pyflakes": pyflakes_dist, "pycodestyle": pycodestyle_dist}
with mock.patch.object(importlib_metadata, "distribution", dists.get):
yield
def test_flake8_plugins(flake8_dist, mock_distribution):
"""Ensure entrypoints for flake8 are parsed specially."""
eps = flake8_dist.entry_points
ret = set(finder._flake8_plugins(eps, "flake8", "9001"))
assert ret == {
finder.Plugin(
"pyflakes",
"9000.1.0",
importlib_metadata.EntryPoint(
"F",
"flake8.plugins.pyflakes:FlakesChecker",
"flake8.extension",
),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.bare_except",
"pycodestyle:bare_except",
"flake8.extension",
),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.blank_lines",
"pycodestyle:blank_lines",
"flake8.extension",
),
),
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"default", "flake8.formatting.default:Default", "flake8.report"
),
),
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
),
),
}
def test_importlib_plugins(
tmp_path,
flake8_dist,
flake8_foo_dist,
mock_distribution,
caplog,
):
"""Ensure we can load plugins from importlib_metadata."""
# make sure flake8-colors is skipped
flake8_colors_metadata = """\
Metadata-Version: 2.1
Name: flake8-colors
Version: 1.2.3
"""
flake8_colors_eps = """\
[flake8.extension]
flake8-colors = flake8_colors:ColorFormatter
"""
flake8_colors_d = tmp_path.joinpath("flake8_colors.dist-info")
flake8_colors_d.mkdir()
flake8_colors_d.joinpath("METADATA").write_text(flake8_colors_metadata)
flake8_colors_d.joinpath("entry_points.txt").write_text(flake8_colors_eps)
flake8_colors_dist = importlib_metadata.PathDistribution(flake8_colors_d)
unrelated_metadata = """\
Metadata-Version: 2.1
Name: unrelated
Version: 4.5.6
"""
unrelated_eps = """\
[console_scripts]
unrelated = unrelated:main
"""
unrelated_d = tmp_path.joinpath("unrelated.dist-info")
unrelated_d.mkdir()
unrelated_d.joinpath("METADATA").write_text(unrelated_metadata)
unrelated_d.joinpath("entry_points.txt").write_text(unrelated_eps)
unrelated_dist = importlib_metadata.PathDistribution(unrelated_d)
with mock.patch.object(
importlib_metadata,
"distributions",
return_value=[
flake8_dist,
flake8_colors_dist,
flake8_foo_dist,
unrelated_dist,
],
):
ret = set(finder._find_importlib_plugins())
assert ret == {
finder.Plugin(
"flake8-foo",
"1.2.3",
importlib_metadata.EntryPoint(
"Q", "flake8_foo:Plugin", "flake8.extension"
),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.bare_except",
"pycodestyle:bare_except",
"flake8.extension",
),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.blank_lines",
"pycodestyle:blank_lines",
"flake8.extension",
),
),
finder.Plugin(
"pyflakes",
"9000.1.0",
importlib_metadata.EntryPoint(
"F",
"flake8.plugins.pyflakes:FlakesChecker",
"flake8.extension",
),
),
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"default", "flake8.formatting.default:Default", "flake8.report"
),
),
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
),
),
finder.Plugin(
"flake8-foo",
"1.2.3",
importlib_metadata.EntryPoint(
"foo", "flake8_foo:Formatter", "flake8.report"
),
),
}
assert caplog.record_tuples == [
(
"flake8.plugins.finder",
30,
"flake8-colors plugin is obsolete in flake8>=4.1",
),
]
def test_find_local_plugins_nothing():
cfg = configparser.RawConfigParser()
assert set(finder._find_local_plugins(cfg)) == set()
@pytest.fixture
def local_plugin_cfg():
cfg = configparser.RawConfigParser()
cfg.add_section("flake8:local-plugins")
cfg.set("flake8:local-plugins", "extension", "Y=mod2:attr, X = mod:attr")
cfg.set("flake8:local-plugins", "report", "Z=mod3:attr")
return cfg
def test_find_local_plugins(local_plugin_cfg):
ret = set(finder._find_local_plugins(local_plugin_cfg))
assert ret == {
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint(
"X",
"mod:attr",
"flake8.extension",
),
),
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint(
"Y",
"mod2:attr",
"flake8.extension",
),
),
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint(
"Z",
"mod3:attr",
"flake8.report",
),
),
}
def test_find_plugins(
tmp_path,
flake8_dist,
flake8_foo_dist,
mock_distribution,
local_plugin_cfg,
):
with mock.patch.object(
importlib_metadata,
"distributions",
return_value=[flake8_dist, flake8_foo_dist],
):
ret = finder.find_plugins(local_plugin_cfg)
assert ret == [
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"default", "flake8.formatting.default:Default", "flake8.report"
),
),
finder.Plugin(
"flake8",
"9001",
importlib_metadata.EntryPoint(
"pylint", "flake8.formatting.default:Pylint", "flake8.report"
),
),
finder.Plugin(
"flake8-foo",
"1.2.3",
importlib_metadata.EntryPoint(
"Q", "flake8_foo:Plugin", "flake8.extension"
),
),
finder.Plugin(
"flake8-foo",
"1.2.3",
importlib_metadata.EntryPoint(
"foo", "flake8_foo:Formatter", "flake8.report"
),
),
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint("X", "mod:attr", "flake8.extension"),
),
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint(
"Y", "mod2:attr", "flake8.extension"
),
),
finder.Plugin(
"local",
"local",
importlib_metadata.EntryPoint("Z", "mod3:attr", "flake8.report"),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.bare_except",
"pycodestyle:bare_except",
"flake8.extension",
),
),
finder.Plugin(
"pycodestyle",
"9000.2.0",
importlib_metadata.EntryPoint(
"pycodestyle.blank_lines",
"pycodestyle:blank_lines",
"flake8.extension",
),
),
finder.Plugin(
"pyflakes",
"9000.1.0",
importlib_metadata.EntryPoint(
"F",
"flake8.plugins.pyflakes:FlakesChecker",
"flake8.extension",
),
),
]
def test_find_local_plugin_paths_missing(tmp_path):
cfg = configparser.RawConfigParser()
assert finder.find_local_plugin_paths(cfg, str(tmp_path)) == []
def test_find_local_plugin_paths(tmp_path):
cfg = configparser.RawConfigParser()
cfg.add_section("flake8:local-plugins")
cfg.set("flake8:local-plugins", "paths", "./a, ./b")
ret = finder.find_local_plugin_paths(cfg, str(tmp_path))
assert ret == [str(tmp_path.joinpath("a")), str(tmp_path.joinpath("b"))]
def test_parameters_for_class_plugin():
"""Verify that we can retrieve the parameters for a class plugin."""
class FakeCheck:
def __init__(self, tree):
raise NotImplementedError
assert finder._parameters_for(FakeCheck) == {"tree": True}
def test_parameters_for_function_plugin():
"""Verify that we retrieve the parameters for a function plugin."""
def fake_plugin(physical_line, self, tree, optional=None):
raise NotImplementedError
assert finder._parameters_for(fake_plugin) == {
"physical_line": True,
"self": True,
"tree": True,
"optional": False,
}
def test_load_plugin_import_error():
plugin = _plugin(ep=_ep(value="dne:dne"))
with pytest.raises(FailedToLoadPlugin) as excinfo:
finder._load_plugin(plugin)
pkg, e = excinfo.value.args
assert pkg == "local"
assert isinstance(e, ModuleNotFoundError)
def test_load_plugin_not_callable():
plugin = _plugin(ep=_ep(value="os:curdir"))
with pytest.raises(FailedToLoadPlugin) as excinfo:
finder._load_plugin(plugin)
pkg, e = excinfo.value.args
assert pkg == "local"
assert isinstance(e, TypeError)
assert e.args == ("expected loaded plugin to be callable",)
def test_load_plugin_ok():
plugin = _plugin(ep=_ep(value="flake8.plugins.pyflakes:FlakesChecker"))
loaded = finder._load_plugin(plugin)
assert loaded == finder.LoadedPlugin(
plugin,
FlakesChecker,
{"tree": True, "file_tokens": True, "filename": True},
)
@pytest.fixture
def reset_sys():
orig_path = sys.path[:]
orig_modules = sys.modules.copy()
yield
sys.path[:] = orig_path
sys.modules.clear()
sys.modules.update(orig_modules)
@pytest.mark.usefixtures("reset_sys")
def test_import_plugins_extends_sys_path():
plugin = _plugin(ep=_ep(value="aplugin:ExtensionTestPlugin2"))
ret = finder._import_plugins([plugin], ["tests/integration/subdir"])
import aplugin
assert ret == [
finder.LoadedPlugin(
plugin,
aplugin.ExtensionTestPlugin2,
{"tree": True},
),
]
def test_classify_plugins():
report_plugin = _loaded(
plugin=_plugin(ep=_ep(name="R", group="flake8.report"))
)
tree_plugin = _loaded(parameters={"tree": True})
logical_line_plugin = _loaded(parameters={"logical_line": True})
physical_line_plugin = _loaded(parameters={"physical_line": True})
classified = finder._classify_plugins(
[report_plugin, tree_plugin, logical_line_plugin, physical_line_plugin]
)
assert classified == finder.Plugins(
checkers=finder.Checkers(
tree=[tree_plugin],
logical_line=[logical_line_plugin],
physical_line=[physical_line_plugin],
),
reporters={"R": report_plugin},
)
@pytest.mark.usefixtures("reset_sys")
def test_load_plugins():
plugin = _plugin(ep=_ep(value="aplugin:ExtensionTestPlugin2"))
ret = finder.load_plugins([plugin], ["tests/integration/subdir"])
import aplugin
assert ret == finder.Plugins(
checkers=finder.Checkers(
tree=[
finder.LoadedPlugin(
plugin,
aplugin.ExtensionTestPlugin2,
{"tree": True},
),
],
logical_line=[],
physical_line=[],
),
reporters={},
)

View file

@ -0,0 +1,74 @@
import argparse
import pytest
from flake8._compat import importlib_metadata
from flake8.formatting import default
from flake8.plugins import finder
from flake8.plugins import reporter
def _opts(**kwargs):
kwargs.setdefault("quiet", 0),
kwargs.setdefault("color", "never")
kwargs.setdefault("output_file", None)
return argparse.Namespace(**kwargs)
@pytest.fixture
def reporters():
def _plugin(name, cls):
return finder.LoadedPlugin(
finder.Plugin(
"flake8",
"123",
importlib_metadata.EntryPoint(
name, f"{cls.__module__}:{cls.__name__}", "flake8.report"
),
),
cls,
{"options": True},
)
return {
"default": _plugin("default", default.Default),
"pylint": _plugin("pylint", default.Pylint),
"quiet-filename": _plugin("quiet-filename", default.FilenameOnly),
"quiet-nothing": _plugin("quiet-nothing", default.Nothing),
}
def test_make_formatter_default(reporters):
ret = reporter.make(reporters, _opts(format="default"))
assert isinstance(ret, default.Default)
assert ret.error_format == default.Default.error_format
def test_make_formatter_quiet_filename(reporters):
ret = reporter.make(reporters, _opts(format="default", quiet=1))
assert isinstance(ret, default.FilenameOnly)
@pytest.mark.parametrize("quiet", (2, 3))
def test_make_formatter_very_quiet(reporters, quiet):
ret = reporter.make(reporters, _opts(format="default", quiet=quiet))
assert isinstance(ret, default.Nothing)
def test_make_formatter_custom(reporters):
ret = reporter.make(reporters, _opts(format="pylint"))
assert isinstance(ret, default.Pylint)
def test_make_formatter_format_string(reporters, caplog):
ret = reporter.make(reporters, _opts(format="hi %(code)s"))
assert isinstance(ret, default.Default)
assert ret.error_format == "hi %(code)s"
assert caplog.record_tuples == [
(
"flake8.plugins.reporter",
30,
"'hi %(code)s' is an unknown formatter. Falling back to default.",
)
]

View file

@ -1,7 +1,5 @@
"""Tests for the Application class."""
import argparse
import sys
from unittest import mock
import pytest
@ -44,62 +42,3 @@ def test_application_exit_code(
application.options = options(exit_zero=exit_zero)
assert application.exit_code() == value
def test_warns_on_unknown_formatter_plugin_name(application):
"""Verify we log a warning with an unfound plugin."""
default = mock.Mock()
execute = default.execute
application.formatting_plugins = {
"default": default,
}
with mock.patch.object(app.LOG, "warning") as warning:
assert execute is application.formatter_for("fake-plugin-name")
assert warning.called is True
assert warning.call_count == 1
def test_returns_specified_plugin(application):
"""Verify we get the plugin we want."""
desired = mock.Mock()
execute = desired.execute
application.formatting_plugins = {
"default": mock.Mock(),
"desired": desired,
}
with mock.patch.object(app.LOG, "warning") as warning:
assert execute is application.formatter_for("desired")
assert warning.called is False
def test_prelim_opts_args(application):
"""Verify we get sensible prelim opts and args."""
opts, args = application.parse_preliminary_options(
["--foo", "--verbose", "src", "setup.py", "--statistics", "--version"]
)
assert opts.verbose
assert args == ["--foo", "src", "setup.py", "--statistics", "--version"]
def test_prelim_opts_ignore_help(application):
"""Verify -h/--help is not handled."""
# GIVEN
# WHEN
_, args = application.parse_preliminary_options(["--help", "-h"])
# THEN
assert args == ["--help", "-h"]
def test_prelim_opts_handles_empty(application):
"""Verify empty argv lists are handled correctly."""
irrelevant_args = ["myexe", "/path/to/foo"]
with mock.patch.object(sys, "argv", irrelevant_args):
opts, args = application.parse_preliminary_options([])
assert args == []

View file

@ -7,6 +7,7 @@ import pytest
from flake8 import checker
from flake8.main.options import JobsArgument
from flake8.plugins import finder
def style_guide_mock():
@ -22,7 +23,7 @@ def style_guide_mock():
def _parallel_checker_manager():
"""Call Manager.run() and return the number of calls to `run_serial`."""
style_guide = style_guide_mock()
manager = checker.Manager(style_guide, [])
manager = checker.Manager(style_guide, finder.Checkers([], [], []))
# multiple checkers is needed for parallel mode
manager.checkers = [mock.Mock(), mock.Mock()]
return manager
@ -54,7 +55,7 @@ def test_oserrors_are_reraised(_):
def test_multiprocessing_is_disabled(_):
"""Verify not being able to import multiprocessing forces jobs to 0."""
style_guide = style_guide_mock()
manager = checker.Manager(style_guide, [])
manager = checker.Manager(style_guide, finder.Checkers([], [], []))
assert manager.jobs == 0
@ -68,7 +69,7 @@ def test_multiprocessing_cpu_count_not_implemented():
"cpu_count",
side_effect=NotImplementedError,
):
manager = checker.Manager(style_guide, [])
manager = checker.Manager(style_guide, finder.Checkers([], [], []))
assert manager.jobs == 0
@ -77,13 +78,7 @@ def test_make_checkers(_):
"""Verify that we create a list of FileChecker instances."""
style_guide = style_guide_mock()
style_guide.options.filenames = ["file1", "file2"]
checkplugins = mock.Mock()
checkplugins.to_dictionary.return_value = {
"ast_plugins": [],
"logical_line_plugins": [],
"physical_line_plugins": [],
}
manager = checker.Manager(style_guide, checkplugins)
manager = checker.Manager(style_guide, finder.Checkers([], [], []))
with mock.patch("flake8.utils.fnmatch", return_value=True):
with mock.patch("flake8.processor.FileProcessor"):

View file

@ -1,56 +1,47 @@
"""Tests for our debugging module."""
from unittest import mock
import pytest
from flake8._compat import importlib_metadata
from flake8.main import debug
from flake8.plugins import finder
@pytest.mark.parametrize(
("versions", "expected"),
(
([], []),
(
[("p1", "1"), ("p2", "2"), ("p1", "1")],
[
{"plugin": "p1", "version": "1"},
{"plugin": "p2", "version": "2"},
def test_debug_information():
def _plugin(pkg, version, ep_name):
return finder.LoadedPlugin(
finder.Plugin(
pkg,
version,
importlib_metadata.EntryPoint(
ep_name, "dne:dne", "flake8.extension"
),
),
None,
{},
)
plugins = finder.Plugins(
checkers=finder.Checkers(
tree=[
_plugin("pkg1", "1.2.3", "X1"),
_plugin("pkg1", "1.2.3", "X2"),
_plugin("pkg2", "4.5.6", "X3"),
],
logical_line=[],
physical_line=[],
),
),
)
def test_plugins_from(versions, expected):
"""Test that we format plugins appropriately."""
option_manager = mock.Mock(**{"manager.versions.return_value": versions})
assert expected == debug.plugins_from(option_manager)
reporters={},
)
@mock.patch("platform.python_implementation", return_value="CPython")
@mock.patch("platform.python_version", return_value="3.5.3")
@mock.patch("platform.system", return_value="Linux")
def test_information(system, pyversion, pyimpl):
"""Verify that we return all the information we care about."""
expected = {
"version": "3.1.0",
info = debug.information("9001", plugins)
assert info == {
"version": "9001",
"plugins": [
{"plugin": "mccabe", "version": "0.5.9"},
{"plugin": "pycodestyle", "version": "2.0.0"},
{"plugin": "pkg1", "version": "1.2.3"},
{"plugin": "pkg2", "version": "4.5.6"},
],
"platform": {
"python_implementation": "CPython",
"python_version": "3.5.3",
"system": "Linux",
"python_implementation": mock.ANY,
"python_version": mock.ANY,
"system": mock.ANY,
},
}
plugins = mock.Mock(
**{
"manager.versions.return_value": [
("pycodestyle", "2.0.0"),
("mccabe", "0.5.9"),
]
}
)
assert expected == debug.information("3.1.0", plugins)
pyimpl.assert_called_once_with()
pyversion.assert_called_once_with()
system.assert_called_once_with()

View file

@ -1,26 +1,33 @@
"""Unit tests for the FileChecker class."""
import argparse
from unittest import mock
import pytest
import flake8
from flake8 import checker
from flake8._compat import importlib_metadata
from flake8.plugins import finder
@mock.patch("flake8.checker.FileChecker._make_processor", return_value=None)
def test_repr(*args):
"""Verify we generate a correct repr."""
file_checker = checker.FileChecker(
"example.py",
checks={},
options=object(),
filename="example.py",
plugins=finder.Checkers([], [], []),
options=argparse.Namespace(),
)
assert repr(file_checker) == "FileChecker for example.py"
def test_nonexistent_file():
"""Verify that checking non-existent file results in an error."""
c = checker.FileChecker("foobar.py", checks={}, options=object())
c = checker.FileChecker(
filename="example.py",
plugins=finder.Checkers([], [], []),
options=argparse.Namespace(),
)
assert c.processor is None
assert not c.should_process
@ -31,17 +38,21 @@ def test_nonexistent_file():
def test_raises_exception_on_failed_plugin(tmp_path, default_options):
"""Checks that a failing plugin results in PluginExecutionFailed."""
foobar = tmp_path / "foobar.py"
foobar.write_text("I exist!") # Create temp file
plugin = {
"name": "failure",
"plugin_name": "failure", # Both are necessary
"parameters": dict(),
"plugin": mock.MagicMock(side_effect=ValueError),
}
"""Verify a failing plugin results in an plugin error"""
fname = tmp_path.joinpath("t.py")
fname.touch()
plugin = finder.LoadedPlugin(
finder.Plugin(
"plugin-name",
"1.2.3",
importlib_metadata.EntryPoint("X", "dne:dne", "flake8.extension"),
),
mock.Mock(side_effect=ValueError),
{},
)
fchecker = checker.FileChecker(
str(foobar), checks=[], options=default_options
filename=str(fname),
plugins=finder.Checkers([], [], []),
options=default_options,
)
with pytest.raises(flake8.exceptions.PluginExecutionFailed):
fchecker.run_check(plugin)

View file

@ -0,0 +1,17 @@
from flake8.main import options
def test_stage1_arg_parser():
stage1_parser = options.stage1_arg_parser()
opts, args = stage1_parser.parse_known_args(
["--foo", "--verbose", "src", "setup.py", "--statistics", "--version"]
)
assert opts.verbose
assert args == ["--foo", "src", "setup.py", "--statistics", "--version"]
def test_stage1_arg_parser_ignores_help():
stage1_parser = options.stage1_arg_parser()
_, args = stage1_parser.parse_known_args(["--help", "-h"])
assert args == ["--help", "-h"]

View file

@ -252,17 +252,6 @@ def test_optparse_normalize_help(optmanager, capsys):
assert "default: bar" in output
def test_optmanager_group(optmanager, capsys):
"""Test that group(...) causes options to be assigned to a group."""
with optmanager.group("groupname"):
optmanager.add_option("--foo")
with pytest.raises(SystemExit):
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert "\ngroupname:\n" in output
@pytest.mark.parametrize(
("s", "is_auto", "n_jobs"),
(

View file

@ -1,169 +0,0 @@
"""Tests for flake8.plugins.manager.Plugin."""
import argparse
from unittest import mock
import pytest
from flake8 import exceptions
from flake8.options import manager as options_manager
from flake8.plugins import manager
def test_load_plugin_fallsback_on_old_setuptools():
"""Verify we fallback gracefully to on old versions of setuptools."""
entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin()
entry_point.load.assert_called_once_with()
def test_load_plugin_is_idempotent():
"""Verify we use the preferred methods on new versions of setuptools."""
entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin()
plugin.load_plugin()
plugin.load_plugin()
entry_point.load.assert_called_once_with()
def test_load_plugin_catches_and_reraises_exceptions():
"""Verify we raise our own FailedToLoadPlugin."""
entry_point = mock.Mock(spec=["load"])
entry_point.load.side_effect = ValueError("Test failure")
plugin = manager.Plugin("T000", entry_point)
with pytest.raises(exceptions.FailedToLoadPlugin):
plugin.load_plugin()
def test_load_noncallable_plugin():
"""Verify that we do not load a non-callable plugin."""
entry_point = mock.Mock(spec=["load"])
entry_point.load.return_value = mock.NonCallableMock()
plugin = manager.Plugin("T000", entry_point)
with pytest.raises(exceptions.FailedToLoadPlugin):
plugin.load_plugin()
entry_point.load.assert_called_once_with()
def test_plugin_property_loads_plugin_on_first_use():
"""Verify that we load our plugin when we first try to use it."""
entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin("T000", entry_point)
assert plugin.plugin is not None
entry_point.load.assert_called_once_with()
def test_execute_calls_plugin_with_passed_arguments():
"""Verify that we pass arguments directly to the plugin."""
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock()
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
plugin.execute("arg1", "arg2", kwarg1="value1", kwarg2="value2")
plugin_obj.assert_called_once_with(
"arg1", "arg2", kwarg1="value1", kwarg2="value2"
)
# Extra assertions
assert entry_point.load.called is False
def test_version_proxies_to_the_plugin():
"""Verify that we pass arguments directly to the plugin."""
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(spec_set=["version"])
plugin_obj.version = "a.b.c"
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
assert plugin.version == "a.b.c"
def test_register_options():
"""Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(
spec_set=["name", "version", "add_options", "parse_options"]
)
option_manager = mock.MagicMock(spec=options_manager.OptionManager)
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
# Call the method we're testing.
plugin.register_options(option_manager)
# Assert that we call add_options
plugin_obj.add_options.assert_called_once_with(option_manager)
def test_register_options_checks_plugin_for_method():
"""Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(spec_set=["name", "version", "parse_options"])
option_manager = mock.Mock(spec=["register_plugin"])
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
# Call the method we're testing.
plugin.register_options(option_manager)
# Assert that we register the plugin
assert option_manager.register_plugin.called is False
def test_provide_options():
"""Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(
spec_set=["name", "version", "add_options", "parse_options"]
)
option_values = argparse.Namespace(enable_extensions=[])
option_manager = mock.Mock()
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
# Call the method we're testing.
plugin.provide_options(option_manager, option_values, None)
# Assert that we call add_options
plugin_obj.parse_options.assert_called_once_with(
option_manager, option_values, None
)
@pytest.mark.parametrize(
"ignore_list, code, expected_list",
[
(["E", "W", "F", "C9"], "W", ["E", "F", "C9"]),
(["E", "W", "F"], "C9", ["E", "W", "F"]),
],
)
def test_enable(ignore_list, code, expected_list):
"""Verify that enabling a plugin removes it from the ignore list."""
options = mock.Mock(ignore=ignore_list)
optmanager = mock.Mock()
plugin = manager.Plugin(code, mock.Mock())
plugin.enable(optmanager, options)
assert options.ignore == expected_list
def test_enable_without_providing_parsed_options():
"""Verify that enabling a plugin removes it from the ignore list."""
optmanager = mock.Mock()
plugin = manager.Plugin("U4", mock.Mock())
plugin.enable(optmanager)
optmanager.remove_from_default_ignore.assert_called_once_with(["U4"])

View file

@ -1,57 +0,0 @@
"""Tests for flake8.plugins.manager.PluginManager."""
from unittest import mock
from flake8._compat import importlib_metadata
from flake8.plugins import manager
@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")
entry_points_mck.assert_called_once_with()
@mock.patch.object(importlib_metadata, "entry_points")
def test_calls_entrypoints_creates_plugins_automaticaly(entry_points_mck):
"""Verify that we create Plugins on instantiation."""
entry_points_mck.return_value = {
"testing.entrypoints": [
importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint("T200", "", "testing.entrypoints"),
],
}
plugin_mgr = manager.PluginManager(namespace="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.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_points_mck.return_value = {
"testing.entrypoints": [
importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint("T200", "", "testing.entrypoints"),
],
}
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.object(importlib_metadata, "entry_points")
def test_local_plugins(entry_points_mck):
"""Verify PluginManager can load given local plugins."""
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.value == "path.to:Plugin"

View file

@ -1,177 +0,0 @@
"""Tests for flake8.plugins.manager.PluginTypeManager."""
from unittest import mock
import pytest
from flake8 import exceptions
from flake8.plugins import manager
TEST_NAMESPACE = "testing.plugin-type-manager"
def create_plugin_mock(raise_exception=False):
"""Create an auto-spec'd mock of a flake8 Plugin."""
plugin = mock.create_autospec(manager.Plugin, instance=True)
if raise_exception:
plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin(
plugin_name="T101",
exception=ValueError("Test failure"),
)
return plugin
def create_mapping_manager_mock(plugins):
"""Create a mock for the PluginManager."""
# Have a function that will actually call the method underneath
def fake_map(func):
for plugin in plugins.values():
yield func(plugin)
# Mock out the PluginManager instance
manager_mock = mock.Mock(spec=["map"])
# Replace the map method
manager_mock.map = fake_map
# Store the plugins
manager_mock.plugins = plugins
return manager_mock
class FakeTestType(manager.PluginTypeManager):
"""Fake PluginTypeManager."""
namespace = TEST_NAMESPACE
@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
def test_instantiates_a_manager(PluginManager): # noqa: N803
"""Verify we create a PluginManager on instantiation."""
FakeTestType()
PluginManager.assert_called_once_with(TEST_NAMESPACE, local_plugins=None)
@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
def test_proxies_names_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the names attribute."""
PluginManager.return_value = mock.Mock(names=["T100", "T200", "T300"])
type_mgr = FakeTestType()
assert type_mgr.names == ["T100", "T200", "T300"]
@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
def test_proxies_plugins_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the plugins attribute."""
PluginManager.return_value = mock.Mock(plugins=["T100", "T200", "T300"])
type_mgr = FakeTestType()
assert type_mgr.plugins == ["T100", "T200", "T300"]
def test_generate_call_function():
"""Verify the function we generate."""
optmanager = object()
plugin = mock.Mock(method_name=lambda x: x)
func = manager.PluginTypeManager._generate_call_function(
"method_name",
optmanager,
)
assert callable(func)
assert func(plugin) is optmanager
@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
def test_load_plugins(PluginManager): # noqa: N803
"""Verify load plugins loads *every* plugin."""
# Create a bunch of fake plugins
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value.plugins = plugins
type_mgr = FakeTestType()
# Load the plugins (do what we're actually testing)
type_mgr.load_plugins()
# Assert that our closure does what we think it does
for plugin in plugins.values():
plugin.load_plugin.assert_called_once_with()
assert type_mgr.plugins_loaded is True
@mock.patch("flake8.plugins.manager.PluginManager")
def test_load_plugins_fails(PluginManager): # noqa: N803
"""Verify load plugins bubbles up exceptions."""
plugins_list = [create_plugin_mock(i == 1) for i in range(8)]
plugins = {"T10%i" % i: plugin for i, plugin in enumerate(plugins_list)}
# Return our PluginManager mock
PluginManager.return_value.plugins = plugins
type_mgr = FakeTestType()
with pytest.raises(exceptions.FailedToLoadPlugin):
type_mgr.load_plugins()
# Assert we didn't finish loading plugins
assert type_mgr.plugins_loaded is False
# Assert the first two plugins had their load_plugin method called
plugins_list[0].load_plugin.assert_called_once_with()
plugins_list[1].load_plugin.assert_called_once_with()
# Assert the rest of the plugins were not loaded
for plugin in plugins_list[2:]:
assert plugin.load_plugin.called is False
@mock.patch("flake8.plugins.manager.PluginManager")
def test_register_options(PluginManager): # noqa: N803
"""Test that we map over every plugin to register options."""
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object()
type_mgr = FakeTestType()
type_mgr.register_options(optmanager)
for plugin in plugins.values():
plugin.register_options.assert_called_with(optmanager)
@mock.patch("flake8.plugins.manager.PluginManager")
def test_provide_options(PluginManager): # noqa: N803
"""Test that we map over every plugin to provide parsed options."""
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object()
options = object()
type_mgr = FakeTestType()
type_mgr.provide_options(optmanager, options, [])
for plugin in plugins.values():
plugin.provide_options.assert_called_with(optmanager, options, [])
@mock.patch("flake8.plugins.manager.PluginManager", autospec=True)
def test_proxy_contains_to_managers_plugins_dict(PluginManager): # noqa: N803
"""Verify that we proxy __contains__ to the manager's dictionary."""
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value.plugins = plugins
type_mgr = FakeTestType()
for i in range(8):
key = "T10%i" % i
assert key in type_mgr
@mock.patch("flake8.plugins.manager.PluginManager")
def test_proxies_getitem_to_managers_plugins_dict(PluginManager): # noqa: N803
"""Verify that we can use the PluginTypeManager like a dictionary."""
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value.plugins = plugins
type_mgr = FakeTestType()
for i in range(8):
key = "T10%i" % i
assert type_mgr[key] is plugins[key]

View file

@ -9,7 +9,6 @@ import pytest
from flake8 import exceptions
from flake8 import utils
from flake8.plugins import manager as plugin_manager
RELATIVE_PATHS = ["flake8", "pep8", "pyflakes", "mccabe"]
@ -181,34 +180,6 @@ def test_fnmatch(filename, patterns, expected):
assert utils.fnmatch(filename, patterns) is expected
def test_parameters_for_class_plugin():
"""Verify that we can retrieve the parameters for a class plugin."""
class FakeCheck:
def __init__(self, tree):
raise NotImplementedError
plugin = plugin_manager.Plugin("plugin-name", object())
plugin._plugin = FakeCheck
assert utils.parameters_for(plugin) == {"tree": True}
def test_parameters_for_function_plugin():
"""Verify that we retrieve the parameters for a function plugin."""
def fake_plugin(physical_line, self, tree, optional=None):
raise NotImplementedError
plugin = plugin_manager.Plugin("plugin-name", object())
plugin._plugin = fake_plugin
assert utils.parameters_for(plugin) == {
"physical_line": True,
"self": True,
"tree": True,
"optional": False,
}
def read_diff_file(filename):
"""Read the diff file in its entirety."""
with open(filename) as fd: