mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-06 13:06:53 +00:00
rework plugin loading
This commit is contained in:
parent
38c5eceda9
commit
50d69150c1
36 changed files with 1277 additions and 1505 deletions
22
tests/fixtures/config_files/README.rst
vendored
22
tests/fixtures/config_files/README.rst
vendored
|
|
@ -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.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[flake8:local-plugins]
|
||||
extension =
|
||||
XE = aplugin:ExtensionTestPlugin2
|
||||
paths =
|
||||
../../integration/subdir/
|
||||
5
tests/fixtures/config_files/local-plugin.ini
vendored
5
tests/fixtures/config_files/local-plugin.ini
vendored
|
|
@ -1,5 +0,0 @@
|
|||
[flake8:local-plugins]
|
||||
extension =
|
||||
XE = tests.integration.test_plugins:ExtensionTestPlugin
|
||||
report =
|
||||
XR = tests.integration.test_plugins:ReportTestPlugin
|
||||
|
|
@ -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."""
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
0
tests/unit/plugins/__init__.py
Normal file
0
tests/unit/plugins/__init__.py
Normal file
610
tests/unit/plugins/finder_test.py
Normal file
610
tests/unit/plugins/finder_test.py
Normal 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={},
|
||||
)
|
||||
74
tests/unit/plugins/reporter_test.py
Normal file
74
tests/unit/plugins/reporter_test.py
Normal 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.",
|
||||
)
|
||||
]
|
||||
|
|
@ -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 == []
|
||||
|
|
|
|||
|
|
@ -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"):
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
17
tests/unit/test_main_options.py
Normal file
17
tests/unit/test_main_options.py
Normal 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"]
|
||||
|
|
@ -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"),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -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"])
|
||||
|
|
@ -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"
|
||||
|
|
@ -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]
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue