extend black formatting to tests as well

This commit is contained in:
Anthony Sottile 2021-04-18 09:17:48 -07:00
parent a7174759e9
commit af1668bf04
45 changed files with 1644 additions and 1307 deletions

View file

@ -1,14 +1,12 @@
exclude: ^tests/fixtures/example-code/
exclude: ^tests/fixtures/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
hooks:
- id: check-yaml
- id: debug-statements
exclude: ^tests/fixtures/example-code/invalid-syntax.py$
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: ^tests/fixtures/diffs/
- repo: https://github.com/asottile/reorder_python_imports
rev: v2.4.0
hooks:
@ -18,8 +16,7 @@ repos:
rev: 20.8b1
hooks:
- id: black
args: [--line-length=78]
files: ^src/
args: [--line-length=79]
- repo: https://github.com/asottile/pyupgrade
rev: v2.12.0
hooks:
@ -29,4 +26,4 @@ repos:
rev: v0.812
hooks:
- id: mypy
exclude: ^(docs/|example-plugin/|tests/fixtures)
exclude: ^(docs/|example-plugin/)

View file

@ -21,40 +21,40 @@ import sys
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
needs_sphinx = '1.3'
needs_sphinx = "1.3"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.extlinks',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'sphinx-prompt',
"sphinx.ext.autodoc",
"sphinx.ext.doctest",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinx.ext.todo",
"sphinx.ext.coverage",
"sphinx.ext.viewcode",
"sphinx-prompt",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = 'flake8'
copyright = '2016, Ian Stapleton Cordasco'
author = 'Ian Stapleton Cordasco'
project = "flake8"
copyright = "2016, Ian Stapleton Cordasco"
author = "Ian Stapleton Cordasco"
import flake8
@ -104,7 +104,7 @@ exclude_patterns = []
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@ -120,7 +120,7 @@ todo_include_todos = True
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'sphinx_rtd_theme'
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -212,20 +212,17 @@ html_theme = 'sphinx_rtd_theme'
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'flake8doc'
htmlhelp_basename = "flake8doc"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
@ -234,8 +231,13 @@ latex_elements = {
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'flake8.tex', 'flake8 Documentation',
'Ian Stapleton Cordasco', 'manual'),
(
master_doc,
"flake8.tex",
"flake8 Documentation",
"Ian Stapleton Cordasco",
"manual",
),
]
# The name of an image file (relative to this directory) to place at the top of
@ -264,8 +266,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('manpage', 'flake8', 'Flake8 Command Line Documentation',
[author], 1)
("manpage", "flake8", "Flake8 Command Line Documentation", [author], 1)
]
# If true, show URL addresses after external links.
@ -278,9 +279,15 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Flake8', 'Flake8 Documentation', 'Tarek Ziade',
'Flake8', 'Code checking using pycodestyle, pyflakes and mccabe',
'Miscellaneous'),
(
"index",
"Flake8",
"Flake8 Documentation",
"Tarek Ziade",
"Flake8",
"Code checking using pycodestyle, pyflakes and mccabe",
"Miscellaneous",
),
]
# Documents to append as an appendix to all manuals.
@ -297,7 +304,7 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)}
intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)}
extlinks = {
"issue": ("https://github.com/pycqa/flake8/issues/%s", "#"),

View file

@ -1,29 +1,29 @@
import setuptools
setuptools.setup(
name='flake8-example-plugin',
license='MIT',
version='1.0.0',
description='Example plugin to Flake8',
author='Ian Cordasco',
author_email='graffatcolmingov@gmail.com',
url='https://github.com/pycqa/flake8',
package_dir={'': 'src/'},
packages=['flake8_example_plugin'],
name="flake8-example-plugin",
license="MIT",
version="1.0.0",
description="Example plugin to Flake8",
author="Ian Cordasco",
author_email="graffatcolmingov@gmail.com",
url="https://github.com/pycqa/flake8",
package_dir={"": "src/"},
packages=["flake8_example_plugin"],
entry_points={
'flake8.extension': [
'X1 = flake8_example_plugin:ExampleOne',
'X2 = flake8_example_plugin:ExampleTwo',
"flake8.extension": [
"X1 = flake8_example_plugin:ExampleOne",
"X2 = flake8_example_plugin:ExampleTwo",
],
},
classifiers=[
'Framework :: Flake8',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Software Development :: Quality Assurance',
"Framework :: Flake8",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
],
)

View file

@ -3,6 +3,6 @@ from .off_by_default import ExampleTwo
from .on_by_default import ExampleOne
__all__ = (
'ExampleOne',
'ExampleTwo',
"ExampleOne",
"ExampleTwo",
)

View file

@ -3,8 +3,9 @@
class ExampleTwo:
"""Second Example Plugin."""
name = 'off-by-default-example-plugin'
version = '1.0.0'
name = "off-by-default-example-plugin"
version = "1.0.0"
off_by_default = True
@ -13,5 +14,9 @@ class ExampleTwo:
def run(self):
"""Do nothing."""
yield (1, 0, 'X200 The off-by-default plugin was enabled',
'OffByDefaultPlugin')
yield (
1,
0,
"X200 The off-by-default plugin was enabled",
"OffByDefaultPlugin",
)

View file

@ -3,8 +3,9 @@
class ExampleOne:
"""First Example Plugin."""
name = 'on-by-default-example-plugin'
version = '1.0.0'
name = "on-by-default-example-plugin"
version = "1.0.0"
def __init__(self, tree):
self.tree = tree

View file

@ -4,6 +4,6 @@ import sys
import setuptools
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
setuptools.setup()

View file

@ -17,9 +17,7 @@ LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler())
__version__ = "3.9.1"
__version_info__ = tuple(
int(i) for i in __version__.split(".") if i.isdigit()
)
__version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit())
# There is nothing lower than logging.DEBUG (10) in the logging library,

View file

@ -241,9 +241,7 @@ class Manager:
"""
results_reported = results_found = 0
for checker in self._all_checkers:
results = sorted(
checker.results, key=lambda tup: (tup[1], tup[2])
)
results = sorted(checker.results, key=lambda tup: (tup[1], tup[2]))
filename = checker.display_name
with self.style_guide.processing_file(filename):
results_reported += self._handle_results(filename, results)

View file

@ -39,9 +39,7 @@ class InvalidSyntax(Flake8Exception):
def __init__(self, exception: Exception) -> None:
"""Initialize our InvalidSyntax exception."""
self.original_exception = exception
self.error_message = (
f"{type(exception).__name__}: {exception.args[0]}"
)
self.error_message = f"{type(exception).__name__}: {exception.args[0]}"
self.error_code = "E902"
self.line_number = 1
self.column_number = 0

View file

@ -369,6 +369,4 @@ def get_local_plugins(config_finder):
return local_plugins
LocalPlugins = collections.namedtuple(
"LocalPlugins", "extension report paths"
)
LocalPlugins = collections.namedtuple("LocalPlugins", "extension report paths")

View file

@ -472,8 +472,7 @@ class Checkers(PluginTypeManager):
plugin.to_dictionary() for plugin in self.logical_line_plugins
],
"physical_line_plugins": [
plugin.to_dictionary()
for plugin in self.physical_line_plugins
plugin.to_dictionary() for plugin in self.physical_line_plugins
],
}

View file

@ -289,9 +289,7 @@ class FileProcessor:
except (tokenize.TokenError, SyntaxError) as exc:
raise exceptions.InvalidSyntax(exception=exc)
def _noqa_line_range(
self, min_line: int, max_line: int
) -> Dict[int, str]:
def _noqa_line_range(self, min_line: int, max_line: int) -> Dict[int, str]:
line_range = range(min_line, max_line + 1)
joined = "".join(self.lines[min_line - 1 : max_line])
return dict.fromkeys(line_range, joined)

View file

@ -368,9 +368,7 @@ class StyleGuideManager:
:rtype:
:class:`~flake8.style_guide.StyleGuide`
"""
per_file = utils.parse_files_to_codes_mapping(
options.per_file_ignores
)
per_file = utils.parse_files_to_codes_mapping(options.per_file_ignores)
for filename, violations in per_file:
yield self.default_style_guide.copy(
filename=filename, extend_ignore_with=violations
@ -579,11 +577,7 @@ class StyleGuide:
)
is_not_inline_ignored = error.is_inline_ignored(disable_noqa) is False
is_included_in_diff = error.is_in(self._parsed_diff)
if (
error_is_selected
and is_not_inline_ignored
and is_included_in_diff
):
if error_is_selected and is_not_inline_ignored and is_included_in_diff:
self.formatter.handle(error)
self.stats.record(error)
return 1

View file

@ -271,13 +271,10 @@ def parse_unified_diff(diff: Optional[str] = None) -> Dict[str, Set[int]]:
# comparing.
if hunk_match:
(row, number_of_rows) = [
1 if not group else int(group)
for group in hunk_match.groups()
1 if not group else int(group) for group in hunk_match.groups()
]
assert current_path is not None
parsed_paths[current_path].update(
range(row, row + number_of_rows)
)
parsed_paths[current_path].update(range(row, row + number_of_rows))
# We have now parsed our diff into a dictionary that looks like:
# {'file.py': set(range(10, 16), range(18, 20)), ...}

View file

@ -3,4 +3,4 @@ import sys
import flake8
flake8.configure_logging(2, 'test-logs-%s.%s.log' % sys.version_info[0:2])
flake8.configure_logging(2, "test-logs-%s.%s.log" % sys.version_info[0:2])

View file

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

View file

@ -9,7 +9,7 @@ from flake8.options import aggregator
from flake8.options import config
from flake8.options import manager
CLI_SPECIFIED_CONFIG = 'tests/fixtures/config_files/cli-specified.ini'
CLI_SPECIFIED_CONFIG = "tests/fixtures/config_files/cli-specified.ini"
@pytest.fixture
@ -18,8 +18,8 @@ def optmanager():
prelim_parser = argparse.ArgumentParser(add_help=False)
options.register_preliminary_options(prelim_parser)
option_manager = manager.OptionManager(
prog='flake8',
version='3.0.0',
prog="flake8",
version="3.0.0",
parents=[prelim_parser],
)
options.register_default_options(option_manager)
@ -28,31 +28,50 @@ def optmanager():
def test_aggregate_options_with_config(optmanager):
"""Verify we aggregate options and config values appropriately."""
arguments = ['flake8', '--select',
'E11,E34,E402,W,F', '--exclude', 'tests/*']
arguments = [
"flake8",
"--select",
"E11,E34,E402,W,F",
"--exclude",
"tests/*",
]
config_finder = config.ConfigFileFinder(
'flake8',
config_file=CLI_SPECIFIED_CONFIG)
"flake8", config_file=CLI_SPECIFIED_CONFIG
)
options, args = aggregator.aggregate_options(
optmanager, config_finder, arguments)
optmanager, config_finder, arguments
)
assert options.select == ['E11', 'E34', 'E402', 'W', 'F']
assert options.ignore == ['E123', 'W234', 'E111']
assert options.exclude == [os.path.abspath('tests/*')]
assert options.select == ["E11", "E34", "E402", "W", "F"]
assert options.ignore == ["E123", "W234", "E111"]
assert options.exclude == [os.path.abspath("tests/*")]
def test_aggregate_options_when_isolated(optmanager):
"""Verify we aggregate options and config values appropriately."""
arguments = ['flake8', '--select', 'E11,E34,E402,W,F',
'--exclude', 'tests/*']
config_finder = config.ConfigFileFinder(
'flake8', ignore_config_files=True)
optmanager.extend_default_ignore(['E8'])
options, args = aggregator.aggregate_options(
optmanager, config_finder, arguments)
assert options.select == ['E11', 'E34', 'E402', 'W', 'F']
assert sorted(options.ignore) == [
'E121', 'E123', 'E126', 'E226', 'E24', 'E704', 'E8', 'W503', 'W504',
arguments = [
"flake8",
"--select",
"E11,E34,E402,W,F",
"--exclude",
"tests/*",
]
assert options.exclude == [os.path.abspath('tests/*')]
config_finder = config.ConfigFileFinder("flake8", ignore_config_files=True)
optmanager.extend_default_ignore(["E8"])
options, args = aggregator.aggregate_options(
optmanager, config_finder, arguments
)
assert options.select == ["E11", "E34", "E402", "W", "F"]
assert sorted(options.ignore) == [
"E121",
"E123",
"E126",
"E226",
"E24",
"E704",
"E8",
"W503",
"W504",
]
assert options.exclude == [os.path.abspath("tests/*")]

View file

@ -5,8 +5,8 @@ from flake8.api import legacy
def test_legacy_api(tmpdir):
"""A basic end-to-end test for the legacy api reporting errors."""
with tmpdir.as_cwd():
t_py = tmpdir.join('t.py')
t_py.write('import os # unused import\n')
t_py = tmpdir.join("t.py")
t_py.write("import os # unused import\n")
style_guide = legacy.get_style_guide()
report = style_guide.check_files([t_py.strpath])

View file

@ -10,13 +10,13 @@ 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_REPORT = (1, 1, "T000 Expected Message")
EXPECTED_REPORT_PHYSICAL_LINE = (1, "T000 Expected Message")
EXPECTED_RESULT_PHYSICAL_LINE = (
'T000',
"T000",
0,
1,
'Expected Message',
"Expected Message",
None,
)
@ -24,8 +24,8 @@ EXPECTED_RESULT_PHYSICAL_LINE = (
class PluginClass:
"""Simple file plugin class yielding the expected report."""
name = 'test'
version = '1.0.0'
name = "test"
version = "1.0.0"
def __init__(self, tree):
"""Construct a dummy object to provide mandatory parameter."""
@ -38,8 +38,8 @@ class PluginClass:
def plugin_func(func):
"""Decorate file plugins which are implemented as functions."""
func.name = 'test'
func.version = '1.0.0'
func.name = "test"
func.version = "1.0.0"
return func
@ -98,35 +98,37 @@ def mock_file_checker_with_plugin(plugin_target):
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 = mock.Mock(spec=["load"])
entry_point.name = plugin_target.name
entry_point.load.return_value = plugin_target
entry_point.value = 'mocked:value'
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]},
"entry_points",
return_value={"flake8.extension": [entry_point]},
):
checks = manager.Checkers()
# Prevent it from reading lines from stdin or somewhere else
with mock.patch('flake8.processor.FileProcessor.read_lines',
return_value=['Line 1']):
with mock.patch(
"flake8.processor.FileProcessor.read_lines", return_value=["Line 1"]
):
file_checker = checker.FileChecker(
'-',
checks.to_dictionary(),
mock.MagicMock()
"-", checks.to_dictionary(), mock.MagicMock()
)
return file_checker
@pytest.mark.parametrize('plugin_target', [
@pytest.mark.parametrize(
"plugin_target",
[
PluginClass,
plugin_func_gen,
plugin_func_list,
])
],
)
def test_handle_file_plugins(plugin_target):
"""Test the FileChecker class handling different file plugin types."""
file_checker = mock_file_checker_with_plugin(plugin_target)
@ -138,20 +140,25 @@ def test_handle_file_plugins(plugin_target):
report = mock.Mock()
file_checker.report = report
file_checker.run_ast_checks()
report.assert_called_once_with(error_code=None,
report.assert_called_once_with(
error_code=None,
line_number=EXPECTED_REPORT[0],
column=EXPECTED_REPORT[1],
text=EXPECTED_REPORT[2])
text=EXPECTED_REPORT[2],
)
@pytest.mark.parametrize('plugin_target,len_results', [
@pytest.mark.parametrize(
"plugin_target,len_results",
[
(plugin_func_physical_ret, 1),
(plugin_func_physical_none, 0),
(plugin_func_physical_list_single, 1),
(plugin_func_physical_list_multiple, 2),
(plugin_func_physical_gen_single, 1),
(plugin_func_physical_gen_multiple, 3),
])
],
)
def test_line_check_results(plugin_target, len_results):
"""Test the FileChecker class handling results from line checks."""
file_checker = mock_file_checker_with_plugin(plugin_target)
@ -167,54 +174,100 @@ def test_logical_line_offset_out_of_bounds():
@plugin_func
def _logical_line_out_of_bounds(logical_line):
yield 10000, 'L100 test'
yield 10000, "L100 test"
file_checker = mock_file_checker_with_plugin(_logical_line_out_of_bounds)
logical_ret = (
'',
"",
'print("xxxxxxxxxxx")',
[(0, (1, 0)), (5, (1, 5)), (6, (1, 6)), (19, (1, 19)), (20, (1, 20))],
)
with mock.patch.object(
FileProcessor, 'build_logical_line', return_value=logical_ret,
FileProcessor,
"build_logical_line",
return_value=logical_ret,
):
file_checker.run_logical_checks()
assert file_checker.results == [('L100', 0, 0, 'test', None)]
assert file_checker.results == [("L100", 0, 0, "test", None)]
PLACEHOLDER_CODE = 'some_line = "of" * code'
@pytest.mark.parametrize('results, expected_order', [
@pytest.mark.parametrize(
"results, expected_order",
[
# No entries should be added
([], []),
# Results are correctly ordered
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1]),
(
[
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
],
[0, 1],
),
# Reversed order of lines
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0]),
# Columns are not ordered correctly (when reports are ordered correctly)
([('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0, 2]),
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE)], [1, 2, 0]),
([('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 2, 1]),
([('A101', 1, 3, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE),
('A101', 3, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1, 2]),
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 1, 3, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE)], [0, 1, 2]),
(
[
("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
],
[1, 0],
),
# Columns are not ordered correctly
# (when reports are ordered correctly)
(
[
("A101", 1, 2, "placeholder error", PLACEHOLDER_CODE),
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
],
[1, 0, 2],
),
(
[
("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 1, 2, "placeholder error", PLACEHOLDER_CODE),
],
[1, 2, 0],
),
(
[
("A101", 1, 2, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 2, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
],
[0, 2, 1],
),
(
[
("A101", 1, 3, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 2, "placeholder error", PLACEHOLDER_CODE),
("A101", 3, 1, "placeholder error", PLACEHOLDER_CODE),
],
[0, 1, 2],
),
(
[
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 1, 3, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 2, "placeholder error", PLACEHOLDER_CODE),
],
[0, 1, 2],
),
# Previously sort column and message (so reversed) (see bug 196)
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE),
('A101', 2, 1, 'charlie error', PLACEHOLDER_CODE)], [0, 1]),
])
(
[
("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
("A101", 2, 1, "charlie error", PLACEHOLDER_CODE),
],
[0, 1],
),
],
)
def test_report_order(results, expected_order):
"""
Test in which order the results will be reported.
@ -222,6 +275,7 @@ def test_report_order(results, expected_order):
It gets a list of reports from the file checkers and verifies that the
result will be ordered independent from the original report.
"""
def count_side_effect(name, sorted_results):
"""Side effect for the result handler to tell all are reported."""
return len(sorted_results)
@ -230,11 +284,11 @@ def test_report_order(results, expected_order):
# tuples to create the expected result lists from the indexes
expected_results = [results[index] for index in expected_order]
file_checker = mock.Mock(spec=['results', 'display_name'])
file_checker = mock.Mock(spec=["results", "display_name"])
file_checker.results = results
file_checker.display_name = 'placeholder'
file_checker.display_name = "placeholder"
style_guide = mock.MagicMock(spec=['options', 'processing_file'])
style_guide = mock.MagicMock(spec=["options", "processing_file"])
# Create a placeholder manager without arguments or plugins
# Just add one custom file checker which just provides the results
@ -244,9 +298,9 @@ def test_report_order(results, expected_order):
# _handle_results is the first place which gets the sorted result
# Should something non-private be mocked instead?
handler = mock.Mock(side_effect=count_side_effect)
with mock.patch.object(manager, '_handle_results', handler):
with mock.patch.object(manager, "_handle_results", handler):
assert manager.report() == (len(results), len(results))
handler.assert_called_once_with('placeholder', expected_results)
handler.assert_called_once_with("placeholder", expected_results)
def test_acquire_when_multiprocessing_pool_can_initialize():

View file

@ -17,7 +17,7 @@ def _call_main(argv, retv=0):
def test_diff_option(tmpdir, capsys):
"""Ensure that `flake8 --diff` works."""
t_py_contents = '''\
t_py_contents = """\
import os
import sys # unused but not part of diff
@ -26,9 +26,9 @@ print('(to avoid trailing whitespace in test)')
print(os.path.join('foo', 'bar'))
y # part of the diff and an error
'''
"""
diff = '''\
diff = """\
diff --git a/t.py b/t.py
index d64ac39..7d943de 100644
--- a/t.py
@ -39,39 +39,39 @@ index d64ac39..7d943de 100644
print(os.path.join('foo', 'bar'))
+
+y # part of the diff and an error
'''
"""
with mock.patch.object(utils, 'stdin_get_value', return_value=diff):
with mock.patch.object(utils, "stdin_get_value", return_value=diff):
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_contents)
_call_main(['--diff'], retv=1)
tmpdir.join("t.py").write(t_py_contents)
_call_main(["--diff"], retv=1)
out, err = capsys.readouterr()
assert out == "t.py:8:1: F821 undefined name 'y'\n"
assert err == ''
assert err == ""
def test_form_feed_line_split(tmpdir, capsys):
"""Test that form feed is treated the same for stdin."""
src = 'x=1\n\f\ny=1\n'
expected_out = '''\
src = "x=1\n\f\ny=1\n"
expected_out = """\
t.py:1:2: E225 missing whitespace around operator
t.py:3:2: E225 missing whitespace around operator
'''
"""
with tmpdir.as_cwd():
tmpdir.join('t.py').write(src)
tmpdir.join("t.py").write(src)
with mock.patch.object(utils, 'stdin_get_value', return_value=src):
_call_main(['-', '--stdin-display-name=t.py'], retv=1)
with mock.patch.object(utils, "stdin_get_value", return_value=src):
_call_main(["-", "--stdin-display-name=t.py"], retv=1)
out, err = capsys.readouterr()
assert out == expected_out
assert err == ''
assert err == ""
_call_main(['t.py'], retv=1)
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == expected_out
assert err == ''
assert err == ""
def test_e101_indent_char_does_not_reset(tmpdir, capsys):
@ -89,82 +89,79 @@ if True:
"""
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_contents)
_call_main(['t.py'])
tmpdir.join("t.py").write(t_py_contents)
_call_main(["t.py"])
def test_statistics_option(tmpdir, capsys):
"""Ensure that `flake8 --statistics` works."""
with tmpdir.as_cwd():
tmpdir.join('t.py').write('import os\nimport sys\n')
_call_main(['--statistics', 't.py'], retv=1)
tmpdir.join("t.py").write("import os\nimport sys\n")
_call_main(["--statistics", "t.py"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:1:1: F401 'os' imported but unused
t.py:2:1: F401 'sys' imported but unused
2 F401 'os' imported but unused
'''
assert err == ''
"""
out, err = capsys.readouterr()
assert out == expected
assert err == ""
def test_show_source_option(tmpdir, capsys):
"""Ensure that --show-source and --no-show-source work."""
with tmpdir.as_cwd():
tmpdir.join('tox.ini').write('[flake8]\nshow_source = true\n')
tmpdir.join('t.py').write('import os\n')
_call_main(['t.py'], retv=1)
tmpdir.join("tox.ini").write("[flake8]\nshow_source = true\n")
tmpdir.join("t.py").write("import os\n")
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:1:1: F401 'os' imported but unused
import os
^
'''
assert err == ''
"""
out, err = capsys.readouterr()
assert out == expected
assert err == ""
with tmpdir.as_cwd():
_call_main(['t.py', '--no-show-source'], retv=1)
_call_main(["t.py", "--no-show-source"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:1:1: F401 'os' imported but unused
'''
assert err == ''
"""
out, err = capsys.readouterr()
assert out == expected
assert err == ""
def test_extend_exclude(tmpdir, capsys):
"""Ensure that `flake8 --extend-exclude` works."""
for d in ['project', 'vendor', 'legacy', '.git', '.tox', '.hg']:
tmpdir.mkdir(d).join('t.py').write('import os\nimport sys\n')
for d in ["project", "vendor", "legacy", ".git", ".tox", ".hg"]:
tmpdir.mkdir(d).join("t.py").write("import os\nimport sys\n")
with tmpdir.as_cwd():
_call_main(['--extend-exclude=vendor,legacy/'], retv=1)
_call_main(["--extend-exclude=vendor,legacy/"], retv=1)
out, err = capsys.readouterr()
expected_out = '''\
expected_out = """\
./project/t.py:1:1: F401 'os' imported but unused
./project/t.py:2:1: F401 'sys' imported but unused
'''
assert out == expected_out.replace('/', os.sep)
assert err == ''
"""
assert out == expected_out.replace("/", os.sep)
assert err == ""
def test_malformed_per_file_ignores_error(tmpdir, capsys):
"""Test the error message for malformed `per-file-ignores`."""
setup_cfg = '''\
setup_cfg = """\
[flake8]
per-file-ignores =
incorrect/*
values/*
'''
with tmpdir.as_cwd():
tmpdir.join('setup.cfg').write(setup_cfg)
_call_main(['.'], retv=1)
out, err = capsys.readouterr()
assert out == '''\
"""
expected = """\
There was a critical error during execution of Flake8:
Expected `per-file-ignores` to be a mapping from file exclude patterns to ignore codes.
@ -172,50 +169,59 @@ Configured `per-file-ignores` setting:
incorrect/*
values/*
''' # noqa: E501
""" # noqa: E501
with tmpdir.as_cwd():
tmpdir.join("setup.cfg").write(setup_cfg)
_call_main(["."], retv=1)
out, err = capsys.readouterr()
assert out == expected
def test_tokenization_error_but_not_syntax_error(tmpdir, capsys):
"""Test that flake8 does not crash on tokenization errors."""
with tmpdir.as_cwd():
# this is a crash in the tokenizer, but not in the ast
tmpdir.join('t.py').write("b'foo' \\\n")
_call_main(['t.py'], retv=1)
tmpdir.join("t.py").write("b'foo' \\\n")
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == 't.py:1:1: E902 TokenError: EOF in multi-line statement\n'
assert err == ''
assert out == "t.py:1:1: E902 TokenError: EOF in multi-line statement\n"
assert err == ""
def test_tokenization_error_is_a_syntax_error(tmpdir, capsys):
"""Test when tokenize raises a SyntaxError."""
with tmpdir.as_cwd():
tmpdir.join('t.py').write('if True:\n pass\n pass\n')
_call_main(['t.py'], retv=1)
tmpdir.join("t.py").write("if True:\n pass\n pass\n")
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == 't.py:1:1: E902 IndentationError: unindent does not match any outer indentation level\n' # noqa: E501
assert err == ''
expected = "t.py:1:1: E902 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
assert out == expected
assert err == ""
def test_bug_report_successful(capsys):
"""Test that --bug-report does not crash."""
_call_main(['--bug-report'])
_call_main(["--bug-report"])
out, err = capsys.readouterr()
assert json.loads(out)
assert err == ''
assert err == ""
def test_specific_noqa_does_not_clobber_pycodestyle_noqa(tmpdir, capsys):
"""See https://github.com/pycqa/flake8/issues/1104."""
with tmpdir.as_cwd():
tmpdir.join('t.py').write("test = ('ABC' == None) # noqa: E501\n")
_call_main(['t.py'], retv=1)
tmpdir.join("t.py").write("test = ('ABC' == None) # noqa: E501\n")
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:1:15: E711 comparison to None should be 'if cond is None:'
'''
"""
out, err = capsys.readouterr()
assert out == expected
def test_specific_noqa_on_line_with_continuation(tmpdir, capsys):
@ -230,60 +236,64 @@ x = """
'''
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src)
_call_main(['t.py'], retv=0)
tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=0)
out, err = capsys.readouterr()
assert out == err == ''
assert out == err == ""
def test_physical_line_file_not_ending_in_newline(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960."""
t_py_src = 'def f():\n\tpass'
t_py_src = "def f():\n\tpass"
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src)
_call_main(['t.py'], retv=1)
tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:2:1: W191 indentation contains tabs
t.py:2:6: W292 no newline at end of file
'''
"""
out, err = capsys.readouterr()
assert out == expected
def test_physical_line_file_not_ending_in_newline_trailing_ws(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960."""
t_py_src = 'x = 1 '
t_py_src = "x = 1 "
with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src)
_call_main(['t.py'], retv=1)
tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=1)
out, err = capsys.readouterr()
assert out == '''\
expected = """\
t.py:1:6: W291 trailing whitespace
t.py:1:9: W292 no newline at end of file
'''
"""
out, err = capsys.readouterr()
assert out == expected
def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys):
"""Test that arguments are obtained from 'sys.argv'."""
with mock.patch('sys.argv', ['flake8', '--help']):
with mock.patch("sys.argv", ["flake8", "--help"]):
_call_main(None)
out, err = capsys.readouterr()
assert out.startswith('usage: flake8 [options] file file ...\n')
assert err == ''
assert out.startswith("usage: flake8 [options] file file ...\n")
assert err == ""
def test_cli_config_option_respected(tmp_path):
"""Test --config is used."""
config = tmp_path / "flake8.ini"
config.write_text("""\
config.write_text(
"""\
[flake8]
ignore = F401
""")
"""
)
py_file = tmp_path / "t.py"
py_file.write_text("import os\n")
@ -294,10 +304,12 @@ ignore = F401
def test_cli_isolated_overrides_config_option(tmp_path):
"""Test --isolated overrides --config."""
config = tmp_path / "flake8.ini"
config.write_text("""\
config.write_text(
"""\
[flake8]
ignore = F401
""")
"""
)
py_file = tmp_path / "t.py"
py_file.write_text("import os\n")
@ -316,13 +328,13 @@ def test_file_not_found(tmpdir, capsys):
def test_output_file(tmpdir, capsys):
"""Ensure that --output-file is honored."""
tmpdir.join('t.py').write('import os\n')
tmpdir.join("t.py").write("import os\n")
with tmpdir.as_cwd():
_call_main(['t.py', '--output-file=f'], retv=1)
_call_main(["t.py", "--output-file=f"], retv=1)
out, err = capsys.readouterr()
assert out == err == ""
expected = "t.py:1:1: F401 'os' imported but unused\n"
assert tmpdir.join('f').read() == expected
assert tmpdir.join("f").read() == expected

View file

@ -1,15 +1,15 @@
"""Integration tests for plugin loading."""
from flake8.main import application
LOCAL_PLUGIN_CONFIG = 'tests/fixtures/config_files/local-plugin.ini'
LOCAL_PLUGIN_PATH_CONFIG = 'tests/fixtures/config_files/local-plugin-path.ini'
LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.ini"
LOCAL_PLUGIN_PATH_CONFIG = "tests/fixtures/config_files/local-plugin-path.ini"
class ExtensionTestPlugin:
"""Extension test plugin."""
name = 'ExtensionTestPlugin'
version = '1.0.0'
name = "ExtensionTestPlugin"
version = "1.0.0"
def __init__(self, tree):
"""Construct an instance of test plugin."""
@ -20,14 +20,14 @@ class ExtensionTestPlugin:
@classmethod
def add_options(cls, parser):
"""Register options."""
parser.add_option('--anopt')
parser.add_option("--anopt")
class ReportTestPlugin:
"""Report test plugin."""
name = 'ReportTestPlugin'
version = '1.0.0'
name = "ReportTestPlugin"
version = "1.0.0"
def __init__(self, tree):
"""Construct an instance of test plugin."""
@ -39,28 +39,29 @@ class ReportTestPlugin:
def test_enable_local_plugin_from_config():
"""App can load a local plugin from config file."""
app = application.Application()
app.initialize(['flake8', '--config', LOCAL_PLUGIN_CONFIG])
app.initialize(["flake8", "--config", LOCAL_PLUGIN_CONFIG])
assert app.check_plugins is not None
assert app.check_plugins['XE'].plugin is ExtensionTestPlugin
assert app.check_plugins["XE"].plugin is ExtensionTestPlugin
assert app.formatting_plugins is not None
assert app.formatting_plugins['XR'].plugin is ReportTestPlugin
assert app.formatting_plugins["XR"].plugin is ReportTestPlugin
def test_local_plugin_can_add_option():
"""A local plugin can add a CLI option."""
app = application.Application()
app.initialize(
['flake8', '--config', LOCAL_PLUGIN_CONFIG, '--anopt', 'foo'])
["flake8", "--config", LOCAL_PLUGIN_CONFIG, "--anopt", "foo"]
)
assert app.options is not None
assert app.options.anopt == 'foo'
assert app.options.anopt == "foo"
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])
app.initialize(["flake8", "--config", LOCAL_PLUGIN_PATH_CONFIG])
assert app.check_plugins is not None
assert app.check_plugins['XE'].plugin.name == 'ExtensionTestPlugin2'
assert app.check_plugins["XE"].plugin.name == "ExtensionTestPlugin2"

View file

@ -6,13 +6,13 @@ import pytest
def options_from(**kwargs):
"""Generate a Values instances with our kwargs."""
kwargs.setdefault('hang_closing', True)
kwargs.setdefault('max_line_length', 79)
kwargs.setdefault('max_doc_length', None)
kwargs.setdefault('indent_size', 4)
kwargs.setdefault('verbose', False)
kwargs.setdefault('stdin_display_name', 'stdin')
kwargs.setdefault('disable_noqa', False)
kwargs.setdefault("hang_closing", True)
kwargs.setdefault("max_line_length", 79)
kwargs.setdefault("max_doc_length", None)
kwargs.setdefault("indent_size", 4)
kwargs.setdefault("verbose", False)
kwargs.setdefault("stdin_display_name", "stdin")
kwargs.setdefault("disable_noqa", False)
return argparse.Namespace(**kwargs)

View file

@ -10,10 +10,10 @@ from flake8.main import application as app
def options(**kwargs):
"""Generate argparse.Namespace for our Application."""
kwargs.setdefault('verbose', 0)
kwargs.setdefault('output_file', None)
kwargs.setdefault('count', False)
kwargs.setdefault('exit_zero', False)
kwargs.setdefault("verbose", 0)
kwargs.setdefault("output_file", None)
kwargs.setdefault("count", False)
kwargs.setdefault("exit_zero", False)
return argparse.Namespace(**kwargs)
@ -24,19 +24,20 @@ def application():
@pytest.mark.parametrize(
'result_count, catastrophic, exit_zero, value', [
"result_count, catastrophic, exit_zero, value",
[
(0, False, False, False),
(0, True, False, True),
(2, False, False, True),
(2, True, False, True),
(0, True, True, True),
(2, False, True, False),
(2, True, True, True),
]
],
)
def test_exit_does_raise(result_count, catastrophic, exit_zero, value,
application):
def test_exit_does_raise(
result_count, catastrophic, exit_zero, value, application
):
"""Verify Application.exit doesn't raise SystemExit."""
application.result_count = result_count
application.catastrophic_failure = catastrophic
@ -53,10 +54,10 @@ def test_warns_on_unknown_formatter_plugin_name(application):
default = mock.Mock()
execute = default.execute
application.formatting_plugins = {
'default': default,
"default": default,
}
with mock.patch.object(app.LOG, 'warning') as warning:
assert execute is application.formatter_for('fake-plugin-name')
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
@ -67,12 +68,12 @@ def test_returns_specified_plugin(application):
desired = mock.Mock()
execute = desired.execute
application.formatting_plugins = {
'default': mock.Mock(),
'desired': desired,
"default": mock.Mock(),
"desired": desired,
}
with mock.patch.object(app.LOG, 'warning') as warning:
assert execute is application.formatter_for('desired')
with mock.patch.object(app.LOG, "warning") as warning:
assert execute is application.formatter_for("desired")
assert warning.called is False
@ -80,10 +81,11 @@ def test_returns_specified_plugin(application):
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'])
["--foo", "--verbose", "src", "setup.py", "--statistics", "--version"]
)
assert opts.verbose
assert args == ['--foo', 'src', 'setup.py', '--statistics', '--version']
assert args == ["--foo", "src", "setup.py", "--statistics", "--version"]
def test_prelim_opts_ignore_help(application):
@ -91,16 +93,16 @@ def test_prelim_opts_ignore_help(application):
# GIVEN
# WHEN
_, args = application.parse_preliminary_options(['--help', '-h'])
_, args = application.parse_preliminary_options(["--help", "-h"])
# THEN
assert args == ['--help', '-h']
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):
irrelevant_args = ["myexe", "/path/to/foo"]
with mock.patch.object(sys, "argv", irrelevant_args):
opts, args = application.parse_preliminary_options([])
assert args == []

View file

@ -10,23 +10,23 @@ from flake8.formatting import base
def options(**kwargs):
"""Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None)
kwargs.setdefault('tee', False)
kwargs.setdefault("output_file", None)
kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs)
@pytest.mark.parametrize('filename', [None, 'out.txt'])
@pytest.mark.parametrize("filename", [None, "out.txt"])
def test_start(filename):
"""Verify we open a new file in the start method."""
mock_open = mock.mock_open()
formatter = base.BaseFormatter(options(output_file=filename))
with mock.patch('flake8.formatting.base.open', mock_open):
with mock.patch("flake8.formatting.base.open", mock_open):
formatter.start()
if filename is None:
assert mock_open.called is False
else:
mock_open.assert_called_once_with(filename, 'a')
mock_open.assert_called_once_with(filename, "a")
def test_stop():
@ -45,68 +45,79 @@ def test_format_needs_to_be_implemented():
formatter = base.BaseFormatter(options())
with pytest.raises(NotImplementedError):
formatter.format(
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', None)
style_guide.Violation("A000", "file.py", 1, 1, "error text", None)
)
def test_show_source_returns_nothing_when_not_showing_source():
"""Ensure we return nothing when users want nothing."""
formatter = base.BaseFormatter(options(show_source=False))
assert formatter.show_source(
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', 'line')
) == ''
assert (
formatter.show_source(
style_guide.Violation(
"A000", "file.py", 1, 1, "error text", "line"
)
)
== ""
)
def test_show_source_returns_nothing_when_there_is_source():
"""Ensure we return nothing when there is no line."""
formatter = base.BaseFormatter(options(show_source=True))
assert formatter.show_source(
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', None)
) == ''
assert (
formatter.show_source(
style_guide.Violation("A000", "file.py", 1, 1, "error text", None)
)
== ""
)
@pytest.mark.parametrize(('line1', 'line2', 'column'), [
@pytest.mark.parametrize(
("line1", "line2", "column"),
[
(
'x=1\n',
' ^',
"x=1\n",
" ^",
2,
),
(
' x=(1\n +2)\n',
' ^',
" x=(1\n +2)\n",
" ^",
5,
),
(
'\tx\t=\ty\n',
'\t \t \t^',
"\tx\t=\ty\n",
"\t \t \t^",
6,
),
])
],
)
def test_show_source_updates_physical_line_appropriately(line1, line2, column):
"""Ensure the error column is appropriately indicated."""
formatter = base.BaseFormatter(options(show_source=True))
error = style_guide.Violation('A000', 'file.py', 1, column, 'error', line1)
error = style_guide.Violation("A000", "file.py", 1, column, "error", line1)
output = formatter.show_source(error)
assert output == line1 + line2
@pytest.mark.parametrize('tee', [False, True])
@pytest.mark.parametrize("tee", [False, True])
def test_write_uses_an_output_file(tee):
"""Verify that we use the output file when it's present."""
line = 'Something to write'
source = 'source'
line = "Something to write"
source = "source"
filemock = mock.Mock()
formatter = base.BaseFormatter(options(tee=tee))
formatter.output_fd = filemock
with mock.patch('flake8.formatting.base.print') as print_func:
with mock.patch("flake8.formatting.base.print") as print_func:
formatter.write(line, source)
if tee:
assert print_func.called
assert print_func.mock_calls == [
mock.call(line, end='\n'),
mock.call(source, end='\n'),
mock.call(line, end="\n"),
mock.call(source, end="\n"),
]
else:
assert not print_func.called
@ -119,11 +130,11 @@ def test_write_uses_an_output_file(tee):
]
@mock.patch('flake8.formatting.base.print')
@mock.patch("flake8.formatting.base.print")
def test_write_uses_print(print_function):
"""Verify that we use the print function without an output file."""
line = 'Something to write'
source = 'source'
line = "Something to write"
source = "source"
formatter = base.BaseFormatter(options())
formatter.write(line, source)
@ -131,8 +142,8 @@ def test_write_uses_print(print_function):
assert print_function.called is True
assert print_function.call_count == 2
assert print_function.mock_calls == [
mock.call(line, end='\n'),
mock.call(source, end='\n'),
mock.call(line, end="\n"),
mock.call(source, end="\n"),
]
@ -163,14 +174,14 @@ def test_handle_formats_the_error():
formatter = FormatFormatter(options(show_source=False))
filemock = formatter.output_fd = mock.Mock()
error = style_guide.Violation(
code='A001',
filename='example.py',
code="A001",
filename="example.py",
line_number=1,
column_number=1,
text='Fake error',
physical_line='a = 1',
text="Fake error",
physical_line="a = 1",
)
formatter.handle(error)
filemock.write.assert_called_once_with(repr(error) + '\n')
filemock.write.assert_called_once_with(repr(error) + "\n")

View file

@ -10,10 +10,12 @@ from flake8.main.options import JobsArgument
def style_guide_mock():
"""Create a mock StyleGuide object."""
return mock.MagicMock(**{
'options.diff': False,
'options.jobs': JobsArgument("4"),
})
return mock.MagicMock(
**{
"options.diff": False,
"options.jobs": JobsArgument("4"),
}
)
def _parallel_checker_manager():
@ -27,21 +29,21 @@ def _parallel_checker_manager():
def test_oserrors_cause_serial_fall_back():
"""Verify that OSErrors will cause the Manager to fallback to serial."""
err = OSError(errno.ENOSPC, 'Ominous message about spaceeeeee')
with mock.patch('_multiprocessing.SemLock', side_effect=err):
err = OSError(errno.ENOSPC, "Ominous message about spaceeeeee")
with mock.patch("_multiprocessing.SemLock", side_effect=err):
manager = _parallel_checker_manager()
with mock.patch.object(manager, 'run_serial') as serial:
with mock.patch.object(manager, "run_serial") as serial:
manager.run()
assert serial.call_count == 1
@mock.patch('flake8.checker._multiprocessing_is_fork', return_value=True)
@mock.patch("flake8.checker._multiprocessing_is_fork", return_value=True)
def test_oserrors_are_reraised(is_windows):
"""Verify that unexpected OSErrors will cause the Manager to reraise."""
err = OSError(errno.EAGAIN, 'Ominous message')
with mock.patch('_multiprocessing.SemLock', side_effect=err):
err = OSError(errno.EAGAIN, "Ominous message")
with mock.patch("_multiprocessing.SemLock", side_effect=err):
manager = _parallel_checker_manager()
with mock.patch.object(manager, 'run_serial') as serial:
with mock.patch.object(manager, "run_serial") as serial:
with pytest.raises(OSError):
manager.run()
assert serial.call_count == 0
@ -50,7 +52,7 @@ def test_oserrors_are_reraised(is_windows):
def test_multiprocessing_is_disabled():
"""Verify not being able to import multiprocessing forces jobs to 0."""
style_guide = style_guide_mock()
with mock.patch('flake8.checker.multiprocessing', None):
with mock.patch("flake8.checker.multiprocessing", None):
manager = checker.Manager(style_guide, [], [])
assert manager.jobs == 0
@ -58,20 +60,20 @@ def test_multiprocessing_is_disabled():
def test_make_checkers():
"""Verify that we create a list of FileChecker instances."""
style_guide = style_guide_mock()
files = ['file1', 'file2']
files = ["file1", "file2"]
checkplugins = mock.Mock()
checkplugins.to_dictionary.return_value = {
'ast_plugins': [],
'logical_line_plugins': [],
'physical_line_plugins': [],
"ast_plugins": [],
"logical_line_plugins": [],
"physical_line_plugins": [],
}
with mock.patch('flake8.checker.multiprocessing', None):
with mock.patch("flake8.checker.multiprocessing", None):
manager = checker.Manager(style_guide, files, checkplugins)
with mock.patch('flake8.utils.filenames_from') as filenames_from:
filenames_from.side_effect = [['file1'], ['file2']]
with mock.patch('flake8.utils.fnmatch', return_value=True):
with mock.patch('flake8.processor.FileProcessor'):
with mock.patch("flake8.utils.filenames_from") as filenames_from:
filenames_from.side_effect = [["file1"], ["file2"]]
with mock.patch("flake8.utils.fnmatch", return_value=True):
with mock.patch("flake8.processor.FileProcessor"):
manager.make_checkers()
assert manager._all_checkers

View file

@ -7,73 +7,93 @@ import pytest
from flake8.options import config
CLI_SPECIFIED_FILEPATH = 'tests/fixtures/config_files/cli-specified.ini'
BROKEN_CONFIG_PATH = 'tests/fixtures/config_files/broken.ini'
CLI_SPECIFIED_FILEPATH = "tests/fixtures/config_files/cli-specified.ini"
BROKEN_CONFIG_PATH = "tests/fixtures/config_files/broken.ini"
def test_cli_config():
"""Verify opening and reading the file specified via the cli."""
cli_filepath = CLI_SPECIFIED_FILEPATH
finder = config.ConfigFileFinder('flake8')
finder = config.ConfigFileFinder("flake8")
parsed_config = finder.cli_config(cli_filepath)
assert parsed_config.has_section('flake8')
assert parsed_config.has_section("flake8")
@pytest.mark.parametrize('cwd,expected', [
@pytest.mark.parametrize(
"cwd,expected",
[
# Root directory of project
(os.path.abspath('.'),
[os.path.abspath('setup.cfg'),
os.path.abspath('tox.ini')]),
(
os.path.abspath("."),
[os.path.abspath("setup.cfg"), os.path.abspath("tox.ini")],
),
# Subdirectory of project directory
(os.path.abspath('src'),
[os.path.abspath('setup.cfg'),
os.path.abspath('tox.ini')]),
(
os.path.abspath("src"),
[os.path.abspath("setup.cfg"), os.path.abspath("tox.ini")],
),
# Outside of project directory
(os.path.abspath('/'),
[]),
])
(os.path.abspath("/"), []),
],
)
def test_generate_possible_local_files(cwd, expected):
"""Verify generation of all possible config paths."""
finder = config.ConfigFileFinder('flake8')
finder = config.ConfigFileFinder("flake8")
with mock.patch.object(os, 'getcwd', return_value=cwd):
with mock.patch.object(os, "getcwd", return_value=cwd):
config_files = list(finder.generate_possible_local_files())
assert config_files == expected
@pytest.mark.parametrize('extra_config_files,expected', [
@pytest.mark.parametrize(
"extra_config_files,expected",
[
# Extra config files specified
([CLI_SPECIFIED_FILEPATH],
[os.path.abspath('setup.cfg'),
os.path.abspath('tox.ini'),
os.path.abspath(CLI_SPECIFIED_FILEPATH)]),
(
[CLI_SPECIFIED_FILEPATH],
[
os.path.abspath("setup.cfg"),
os.path.abspath("tox.ini"),
os.path.abspath(CLI_SPECIFIED_FILEPATH),
],
),
# Missing extra config files specified
([CLI_SPECIFIED_FILEPATH,
'tests/fixtures/config_files/missing.ini'],
[os.path.abspath('setup.cfg'),
os.path.abspath('tox.ini'),
os.path.abspath(CLI_SPECIFIED_FILEPATH)]),
])
(
[
CLI_SPECIFIED_FILEPATH,
"tests/fixtures/config_files/missing.ini",
],
[
os.path.abspath("setup.cfg"),
os.path.abspath("tox.ini"),
os.path.abspath(CLI_SPECIFIED_FILEPATH),
],
),
],
)
def test_local_config_files(extra_config_files, expected):
"""Verify discovery of local config files."""
finder = config.ConfigFileFinder('flake8', extra_config_files)
finder = config.ConfigFileFinder("flake8", extra_config_files)
assert list(finder.local_config_files()) == expected
def test_local_configs():
"""Verify we return a ConfigParser."""
finder = config.ConfigFileFinder('flake8')
finder = config.ConfigFileFinder("flake8")
assert isinstance(finder.local_configs(), configparser.RawConfigParser)
@pytest.mark.parametrize('files', [
@pytest.mark.parametrize(
"files",
[
[BROKEN_CONFIG_PATH],
[CLI_SPECIFIED_FILEPATH, BROKEN_CONFIG_PATH],
])
],
)
def test_read_config_catches_broken_config_files(files):
"""Verify that we do not allow the exception to bubble up."""
_, parsed = config.ConfigFileFinder._read_config(*files)
@ -82,40 +102,42 @@ def test_read_config_catches_broken_config_files(files):
def test_read_config_catches_decoding_errors(tmpdir):
"""Verify that we do not allow the exception to bubble up."""
setup_cfg = tmpdir.join('setup.cfg')
setup_cfg = tmpdir.join("setup.cfg")
# pick bytes that are unlikely to decode
setup_cfg.write_binary(b'[x]\ny = \x81\x8d\x90\x9d')
setup_cfg.write_binary(b"[x]\ny = \x81\x8d\x90\x9d")
_, parsed = config.ConfigFileFinder._read_config(setup_cfg.strpath)
assert parsed == []
def test_config_file_default_value():
"""Verify the default 'config_file' attribute value."""
finder = config.ConfigFileFinder('flake8')
finder = config.ConfigFileFinder("flake8")
assert finder.config_file is None
def test_setting_config_file_value():
"""Verify the 'config_file' attribute matches constructed value."""
config_file_value = 'flake8.ini'
finder = config.ConfigFileFinder('flake8', config_file=config_file_value)
config_file_value = "flake8.ini"
finder = config.ConfigFileFinder("flake8", config_file=config_file_value)
assert finder.config_file == config_file_value
def test_ignore_config_files_default_value():
"""Verify the default 'ignore_config_files' attribute value."""
finder = config.ConfigFileFinder('flake8')
finder = config.ConfigFileFinder("flake8")
assert finder.ignore_config_files is False
@pytest.mark.parametrize('ignore_config_files_arg', [
@pytest.mark.parametrize(
"ignore_config_files_arg",
[
False,
True,
])
],
)
def test_setting_ignore_config_files_value(ignore_config_files_arg):
"""Verify the 'ignore_config_files' attribute matches constructed value."""
finder = config.ConfigFileFinder(
'flake8',
ignore_config_files=ignore_config_files_arg
"flake8", ignore_config_files=ignore_config_files_arg
)
assert finder.ignore_config_files is ignore_config_files_arg

View file

@ -12,51 +12,82 @@ def test_dependencies():
assert [] == debug.dependencies()
@pytest.mark.parametrize('plugins, expected', [
@pytest.mark.parametrize(
"plugins, expected",
[
([], []),
([manager.PluginVersion('pycodestyle', '2.0.0', False)],
[{'plugin': 'pycodestyle', 'version': '2.0.0', 'is_local': False}]),
([manager.PluginVersion('pycodestyle', '2.0.0', False),
manager.PluginVersion('mccabe', '0.5.9', False)],
[{'plugin': 'mccabe', 'version': '0.5.9', 'is_local': False},
{'plugin': 'pycodestyle', 'version': '2.0.0', 'is_local': False}]),
([manager.PluginVersion('pycodestyle', '2.0.0', False),
manager.PluginVersion('my-local', '0.0.1', True),
manager.PluginVersion('mccabe', '0.5.9', False)],
[{'plugin': 'mccabe', 'version': '0.5.9', 'is_local': False},
{'plugin': 'my-local', 'version': '0.0.1', 'is_local': True},
{'plugin': 'pycodestyle', 'version': '2.0.0', 'is_local': False}]),
])
(
[manager.PluginVersion("pycodestyle", "2.0.0", False)],
[
{
"plugin": "pycodestyle",
"version": "2.0.0",
"is_local": False,
}
],
),
(
[
manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion("mccabe", "0.5.9", False),
],
[
{"plugin": "mccabe", "version": "0.5.9", "is_local": False},
{
"plugin": "pycodestyle",
"version": "2.0.0",
"is_local": False,
},
],
),
(
[
manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion("my-local", "0.0.1", True),
manager.PluginVersion("mccabe", "0.5.9", False),
],
[
{"plugin": "mccabe", "version": "0.5.9", "is_local": False},
{"plugin": "my-local", "version": "0.0.1", "is_local": True},
{
"plugin": "pycodestyle",
"version": "2.0.0",
"is_local": False,
},
],
),
],
)
def test_plugins_from(plugins, expected):
"""Test that we format plugins appropriately."""
option_manager = mock.Mock(registered_plugins=set(plugins))
assert expected == debug.plugins_from(option_manager)
@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')
@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',
'plugins': [{'plugin': 'mccabe', 'version': '0.5.9',
'is_local': False},
{'plugin': 'pycodestyle', 'version': '2.0.0',
'is_local': False}],
'dependencies': [],
'platform': {
'python_implementation': 'CPython',
'python_version': '3.5.3',
'system': 'Linux',
"version": "3.1.0",
"plugins": [
{"plugin": "mccabe", "version": "0.5.9", "is_local": False},
{"plugin": "pycodestyle", "version": "2.0.0", "is_local": False},
],
"dependencies": [],
"platform": {
"python_implementation": "CPython",
"python_version": "3.5.3",
"system": "Linux",
},
}
option_manager = mock.Mock(
registered_plugins={
manager.PluginVersion('pycodestyle', '2.0.0', False),
manager.PluginVersion('mccabe', '0.5.9', False),
manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion("mccabe", "0.5.9", False),
},
version='3.1.0',
version="3.1.0",
)
assert expected == debug.information(option_manager)
pyimpl.assert_called_once_with()
@ -64,14 +95,16 @@ def test_information(system, pyversion, pyimpl):
system.assert_called_once_with()
@mock.patch('flake8.main.debug.print')
@mock.patch('flake8.main.debug.information', return_value={})
@mock.patch('json.dumps', return_value='{}')
@mock.patch("flake8.main.debug.print")
@mock.patch("flake8.main.debug.information", return_value={})
@mock.patch("json.dumps", return_value="{}")
def test_print_information_no_plugins(dumps, information, print_mock):
"""Verify we print and exit only when we have plugins."""
option_manager = mock.Mock(registered_plugins=set())
action = debug.DebugAction(
"--bug-report", dest="bug_report", option_manager=option_manager,
"--bug-report",
dest="bug_report",
option_manager=option_manager,
)
assert action(None, None, None, None) is None
assert dumps.called is False
@ -79,21 +112,23 @@ def test_print_information_no_plugins(dumps, information, print_mock):
assert print_mock.called is False
@mock.patch('flake8.main.debug.print')
@mock.patch('flake8.main.debug.information', return_value={})
@mock.patch('json.dumps', return_value='{}')
@mock.patch("flake8.main.debug.print")
@mock.patch("flake8.main.debug.information", return_value={})
@mock.patch("json.dumps", return_value="{}")
def test_print_information(dumps, information, print_mock):
"""Verify we print and exit only when we have plugins."""
plugins = [
manager.PluginVersion('pycodestyle', '2.0.0', False),
manager.PluginVersion('mccabe', '0.5.9', False),
manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion("mccabe", "0.5.9", False),
]
option_manager = mock.Mock(registered_plugins=set(plugins))
action = debug.DebugAction(
"--bug-report", dest="bug_report", option_manager=option_manager,
"--bug-report",
dest="bug_report",
option_manager=option_manager,
)
with pytest.raises(SystemExit):
action(None, None, None, None)
print_mock.assert_called_once_with('{}')
print_mock.assert_called_once_with("{}")
dumps.assert_called_once_with({}, indent=2, sort_keys=True)
information.assert_called_once_with(option_manager)

View file

@ -7,21 +7,21 @@ from flake8 import exceptions
@pytest.mark.parametrize(
'err',
"err",
(
exceptions.FailedToLoadPlugin(
plugin_name='plugin_name',
exception=ValueError('boom!'),
plugin_name="plugin_name",
exception=ValueError("boom!"),
),
exceptions.InvalidSyntax(exception=ValueError('Unexpected token: $')),
exceptions.InvalidSyntax(exception=ValueError("Unexpected token: $")),
exceptions.PluginRequestedUnknownParameters(
plugin={'plugin_name': 'plugin_name'},
exception=ValueError('boom!'),
plugin={"plugin_name": "plugin_name"},
exception=ValueError("boom!"),
),
exceptions.PluginExecutionFailed(
plugin={'plugin_name': 'plugin_name'},
exception=ValueError('boom!'),
)
plugin={"plugin_name": "plugin_name"},
exception=ValueError("boom!"),
),
),
)
def test_pickleable(err):

View file

@ -7,7 +7,7 @@ import flake8
from flake8 import checker
@mock.patch('flake8.processor.FileProcessor')
@mock.patch("flake8.processor.FileProcessor")
def test_run_ast_checks_handles_SyntaxErrors(FileProcessor): # noqa: N802,N803
"""Stress our SyntaxError handling.
@ -15,26 +15,31 @@ def test_run_ast_checks_handles_SyntaxErrors(FileProcessor): # noqa: N802,N803
"""
processor = mock.Mock(lines=[])
FileProcessor.return_value = processor
processor.build_ast.side_effect = SyntaxError('Failed to build ast',
('', 1, 5, 'foo(\n'))
processor.build_ast.side_effect = SyntaxError(
"Failed to build ast", ("", 1, 5, "foo(\n")
)
file_checker = checker.FileChecker(__file__, checks={}, options=object())
with mock.patch.object(file_checker, 'report') as report:
with mock.patch.object(file_checker, "report") as report:
file_checker.run_ast_checks()
report.assert_called_once_with(
'E999', 1, 3,
'SyntaxError: Failed to build ast',
"E999",
1,
3,
"SyntaxError: Failed to build ast",
)
@mock.patch('flake8.checker.FileChecker._make_processor', return_value=None)
@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(),
"example.py",
checks={},
options=object(),
)
assert repr(file_checker) == 'FileChecker for example.py'
assert repr(file_checker) == "FileChecker for example.py"
def test_nonexistent_file():
@ -50,7 +55,7 @@ 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 = tmp_path / "foobar.py"
foobar.write_text("I exist!") # Create temp file
plugin = {
"name": "failure",
@ -60,6 +65,7 @@ def test_raises_exception_on_failed_plugin(tmp_path, default_options):
}
"""Verify a failing plugin results in an plugin error"""
fchecker = checker.FileChecker(
str(foobar), checks=[], options=default_options)
str(foobar), checks=[], options=default_options
)
with pytest.raises(flake8.exceptions.PluginExecutionFailed):
fchecker.run_check(plugin)

View file

@ -17,7 +17,7 @@ def test_read_lines_splits_lines(default_options):
def _lines_from_file(tmpdir, contents, options):
f = tmpdir.join('f.py')
f = tmpdir.join("f.py")
# be careful to write the bytes exactly to avoid newline munging
f.write_binary(contents)
return processor.FileProcessor(f.strpath, options).lines
@ -26,111 +26,125 @@ def _lines_from_file(tmpdir, contents, options):
def test_read_lines_universal_newlines(tmpdir, default_options):
r"""Verify that line endings are translated to \n."""
lines = _lines_from_file(
tmpdir, b'# coding: utf-8\r\nx = 1\r\n', default_options)
assert lines == ['# coding: utf-8\n', 'x = 1\n']
tmpdir, b"# coding: utf-8\r\nx = 1\r\n", default_options
)
assert lines == ["# coding: utf-8\n", "x = 1\n"]
def test_read_lines_incorrect_utf_16(tmpdir, default_options):
"""Verify that an incorrectly encoded file is read as latin-1."""
lines = _lines_from_file(
tmpdir, b'# coding: utf16\nx = 1\n', default_options)
assert lines == ['# coding: utf16\n', 'x = 1\n']
tmpdir, b"# coding: utf16\nx = 1\n", default_options
)
assert lines == ["# coding: utf16\n", "x = 1\n"]
def test_read_lines_unknown_encoding(tmpdir, default_options):
"""Verify that an unknown encoding is still read as latin-1."""
lines = _lines_from_file(
tmpdir, b'# coding: fake-encoding\nx = 1\n', default_options)
assert lines == ['# coding: fake-encoding\n', 'x = 1\n']
tmpdir, b"# coding: fake-encoding\nx = 1\n", default_options
)
assert lines == ["# coding: fake-encoding\n", "x = 1\n"]
@pytest.mark.parametrize('first_line', [
@pytest.mark.parametrize(
"first_line",
[
'\xEF\xBB\xBF"""Module docstring."""\n',
'\uFEFF"""Module docstring."""\n',
])
],
)
def test_strip_utf_bom(first_line, default_options):
r"""Verify that we strip '\xEF\xBB\xBF' from the first line."""
lines = [first_line]
file_processor = processor.FileProcessor('-', default_options, lines[:])
file_processor = processor.FileProcessor("-", default_options, lines[:])
assert file_processor.lines != lines
assert file_processor.lines[0] == '"""Module docstring."""\n'
@pytest.mark.parametrize('lines, expected', [
@pytest.mark.parametrize(
"lines, expected",
[
(['\xEF\xBB\xBF"""Module docstring."""\n'], False),
(['\uFEFF"""Module docstring."""\n'], False),
(['#!/usr/bin/python', '# flake8 is great', 'a = 1'], False),
(['#!/usr/bin/python', '# flake8: noqa', 'a = 1'], True),
(['#!/usr/bin/python', '# flake8:noqa', 'a = 1'], True),
(['# flake8: noqa', '#!/usr/bin/python', 'a = 1'], True),
(['# flake8:noqa', '#!/usr/bin/python', 'a = 1'], True),
(['#!/usr/bin/python', 'a = 1', '# flake8: noqa'], True),
(['#!/usr/bin/python', 'a = 1', '# flake8:noqa'], True),
(['#!/usr/bin/python', 'a = 1 # flake8: noqa'], False),
(['#!/usr/bin/python', 'a = 1 # flake8:noqa'], False),
])
(["#!/usr/bin/python", "# flake8 is great", "a = 1"], False),
(["#!/usr/bin/python", "# flake8: noqa", "a = 1"], True),
(["#!/usr/bin/python", "# flake8:noqa", "a = 1"], True),
(["# flake8: noqa", "#!/usr/bin/python", "a = 1"], True),
(["# flake8:noqa", "#!/usr/bin/python", "a = 1"], True),
(["#!/usr/bin/python", "a = 1", "# flake8: noqa"], True),
(["#!/usr/bin/python", "a = 1", "# flake8:noqa"], True),
(["#!/usr/bin/python", "a = 1 # flake8: noqa"], False),
(["#!/usr/bin/python", "a = 1 # flake8:noqa"], False),
],
)
def test_should_ignore_file(lines, expected, default_options):
"""Verify that we ignore a file if told to."""
file_processor = processor.FileProcessor('-', default_options, lines)
file_processor = processor.FileProcessor("-", default_options, lines)
assert file_processor.should_ignore_file() is expected
def test_should_ignore_file_to_handle_disable_noqa(default_options):
"""Verify that we ignore a file if told to."""
lines = ['# flake8: noqa']
file_processor = processor.FileProcessor('-', default_options, lines)
lines = ["# flake8: noqa"]
file_processor = processor.FileProcessor("-", default_options, lines)
assert file_processor.should_ignore_file() is True
default_options.disable_noqa = True
file_processor = processor.FileProcessor('-', default_options, lines)
file_processor = processor.FileProcessor("-", default_options, lines)
assert file_processor.should_ignore_file() is False
@mock.patch('flake8.utils.stdin_get_value')
@mock.patch("flake8.utils.stdin_get_value")
def test_read_lines_from_stdin(stdin_get_value, default_options):
"""Verify that we use our own utility function to retrieve stdin."""
stdin_get_value.return_value = ''
processor.FileProcessor('-', default_options)
stdin_get_value.return_value = ""
processor.FileProcessor("-", default_options)
stdin_get_value.assert_called_once_with()
@mock.patch('flake8.utils.stdin_get_value')
@mock.patch("flake8.utils.stdin_get_value")
def test_stdin_filename_attribute(stdin_get_value, default_options):
"""Verify that we update the filename attribute."""
stdin_get_value.return_value = ''
file_processor = processor.FileProcessor('-', default_options)
assert file_processor.filename == 'stdin'
stdin_get_value.return_value = ""
file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == "stdin"
@mock.patch('flake8.utils.stdin_get_value')
@mock.patch("flake8.utils.stdin_get_value")
def test_read_lines_uses_display_name(stdin_get_value, default_options):
"""Verify that when processing stdin we use a display name if present."""
default_options.stdin_display_name = 'display_name.py'
stdin_get_value.return_value = ''
file_processor = processor.FileProcessor('-', default_options)
assert file_processor.filename == 'display_name.py'
default_options.stdin_display_name = "display_name.py"
stdin_get_value.return_value = ""
file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == "display_name.py"
@mock.patch('flake8.utils.stdin_get_value')
@mock.patch("flake8.utils.stdin_get_value")
def test_read_lines_ignores_empty_display_name(
stdin_get_value, default_options,
stdin_get_value,
default_options,
):
"""Verify that when processing stdin we use a display name if present."""
stdin_get_value.return_value = ''
default_options.stdin_display_name = ''
file_processor = processor.FileProcessor('-', default_options)
assert file_processor.filename == 'stdin'
stdin_get_value.return_value = ""
default_options.stdin_display_name = ""
file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == "stdin"
def test_noqa_line_for(default_options):
"""Verify we grab the correct line from the cached lines."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'Line 1\n',
'Line 2\n',
'Line 3\n',
])
file_processor = processor.FileProcessor(
"-",
default_options,
lines=[
"Line 1\n",
"Line 2\n",
"Line 3\n",
],
)
for i in range(1, 4):
assert file_processor.noqa_line_for(i) == f'Line {i}\n'
assert file_processor.noqa_line_for(i) == f"Line {i}\n"
def test_noqa_line_for_continuation(default_options):
@ -145,15 +159,15 @@ world
""" # 7
'''
lines = src.splitlines(True)
file_processor = processor.FileProcessor('-', default_options, lines=lines)
file_processor = processor.FileProcessor("-", default_options, lines=lines)
assert file_processor.noqa_line_for(0) is None
l_1_2 = 'from foo \\\n import bar # 2\n'
l_1_2 = "from foo \\\n import bar # 2\n"
assert file_processor.noqa_line_for(1) == l_1_2
assert file_processor.noqa_line_for(2) == l_1_2
assert file_processor.noqa_line_for(3) == '\n'
assert file_processor.noqa_line_for(3) == "\n"
l_4_7 = 'x = """\nhello\nworld\n""" # 7\n'
for i in (4, 5, 6, 7):
@ -164,46 +178,63 @@ world
def test_noqa_line_for_no_eol_at_end_of_file(default_options):
"""Verify that we properly handle noqa line at the end of the file."""
src = 'from foo \\\nimport bar' # no end of file newline
src = "from foo \\\nimport bar" # no end of file newline
lines = src.splitlines(True)
file_processor = processor.FileProcessor('-', default_options, lines=lines)
file_processor = processor.FileProcessor("-", default_options, lines=lines)
l_1_2 = 'from foo \\\nimport bar'
l_1_2 = "from foo \\\nimport bar"
assert file_processor.noqa_line_for(1) == l_1_2
assert file_processor.noqa_line_for(2) == l_1_2
def test_next_line(default_options):
"""Verify we update the file_processor state for each new line."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'Line 1',
'Line 2',
'Line 3',
])
file_processor = processor.FileProcessor(
"-",
default_options,
lines=[
"Line 1",
"Line 2",
"Line 3",
],
)
for i in range(1, 4):
assert file_processor.next_line() == f'Line {i}'
assert file_processor.next_line() == f"Line {i}"
assert file_processor.line_number == i
@pytest.mark.parametrize('params, args, expected_kwargs', [
({'blank_before': True, 'blank_lines': True},
@pytest.mark.parametrize(
"params, args, expected_kwargs",
[
(
{"blank_before": True, "blank_lines": True},
None,
{'blank_before': 0, 'blank_lines': 0}),
({'noqa': True, 'fake': True},
{'fake': 'foo'},
{'noqa': False, 'fake': 'foo'}),
({'blank_before': True, 'blank_lines': True, 'noqa': True},
{'blank_before': 10, 'blank_lines': 5, 'noqa': True},
{'blank_before': 10, 'blank_lines': 5, 'noqa': True}),
({}, {'fake': 'foo'}, {'fake': 'foo'}),
({'non-existent': False}, {'fake': 'foo'}, {'fake': 'foo'}),
])
{"blank_before": 0, "blank_lines": 0},
),
(
{"noqa": True, "fake": True},
{"fake": "foo"},
{"noqa": False, "fake": "foo"},
),
(
{"blank_before": True, "blank_lines": True, "noqa": True},
{"blank_before": 10, "blank_lines": 5, "noqa": True},
{"blank_before": 10, "blank_lines": 5, "noqa": True},
),
({}, {"fake": "foo"}, {"fake": "foo"}),
({"non-existent": False}, {"fake": "foo"}, {"fake": "foo"}),
],
)
def test_keyword_arguments_for(params, args, expected_kwargs, default_options):
"""Verify the keyword args are generated properly."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'Line 1',
])
file_processor = processor.FileProcessor(
"-",
default_options,
lines=[
"Line 1",
],
)
kwargs_for = file_processor.keyword_arguments_for
assert kwargs_for(params, args) == expected_kwargs
@ -213,27 +244,38 @@ def test_keyword_arguments_for_does_not_handle_attribute_errors(
default_options,
):
"""Verify we re-raise AttributeErrors."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'Line 1',
])
file_processor = processor.FileProcessor(
"-",
default_options,
lines=[
"Line 1",
],
)
with pytest.raises(AttributeError):
file_processor.keyword_arguments_for({'fake': True})
file_processor.keyword_arguments_for({"fake": True})
@pytest.mark.parametrize('unsplit_line, expected_lines', [
('line', []),
('line 1\n', ['line 1']),
('line 1\nline 2\n', ['line 1', 'line 2']),
('line 1\n\nline 2\n', ['line 1', '', 'line 2']),
])
@pytest.mark.parametrize(
"unsplit_line, expected_lines",
[
("line", []),
("line 1\n", ["line 1"]),
("line 1\nline 2\n", ["line 1", "line 2"]),
("line 1\n\nline 2\n", ["line 1", "", "line 2"]),
],
)
def test_split_line(unsplit_line, expected_lines, default_options):
"""Verify the token line splitting."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'Line 1',
])
file_processor = processor.FileProcessor(
"-",
default_options,
lines=[
"Line 1",
],
)
token = (1, unsplit_line, (0, 0), (0, 0), '')
token = (1, unsplit_line, (0, 0), (0, 0), "")
actual_lines = list(file_processor.split_line(token))
assert expected_lines == actual_lines
@ -242,9 +284,9 @@ def test_split_line(unsplit_line, expected_lines, default_options):
def test_build_ast(default_options):
"""Verify the logic for how we build an AST for plugins."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'a = 1\n'
])
file_processor = processor.FileProcessor(
"-", default_options, lines=["a = 1\n"]
)
module = file_processor.build_ast()
assert isinstance(module, ast.Module)
@ -252,25 +294,25 @@ def test_build_ast(default_options):
def test_next_logical_line_updates_the_previous_logical_line(default_options):
"""Verify that we update our tracking of the previous logical line."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'a = 1\n'
])
file_processor = processor.FileProcessor(
"-", default_options, lines=["a = 1\n"]
)
file_processor.indent_level = 1
file_processor.logical_line = 'a = 1'
assert file_processor.previous_logical == ''
file_processor.logical_line = "a = 1"
assert file_processor.previous_logical == ""
assert file_processor.previous_indent_level == 0
file_processor.next_logical_line()
assert file_processor.previous_logical == 'a = 1'
assert file_processor.previous_logical == "a = 1"
assert file_processor.previous_indent_level == 1
def test_visited_new_blank_line(default_options):
"""Verify we update the number of blank lines seen."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'a = 1\n'
])
file_processor = processor.FileProcessor(
"-", default_options, lines=["a = 1\n"]
)
assert file_processor.blank_lines == 0
file_processor.visited_new_blank_line()
@ -279,9 +321,9 @@ def test_visited_new_blank_line(default_options):
def test_inside_multiline(default_options):
"""Verify we update the line number and reset multiline."""
file_processor = processor.FileProcessor('-', default_options, lines=[
'a = 1\n'
])
file_processor = processor.FileProcessor(
"-", default_options, lines=["a = 1\n"]
)
assert file_processor.multiline is False
assert file_processor.line_number == 0
@ -292,7 +334,9 @@ def test_inside_multiline(default_options):
assert file_processor.multiline is False
@pytest.mark.parametrize('string, expected', [
@pytest.mark.parametrize(
"string, expected",
[
('""', '""'),
("''", "''"),
('"a"', '"x"'),
@ -311,44 +355,66 @@ def test_inside_multiline(default_options):
("'''abcdef'''", "'''xxxxxx'''"),
('"""xxxxxx"""', '"""xxxxxx"""'),
("'''xxxxxx'''", "'''xxxxxx'''"),
])
],
)
def test_mutate_string(string, expected, default_options):
"""Verify we appropriately mutate the string to sanitize it."""
actual = processor.mutate_string(string)
assert expected == actual
@pytest.mark.parametrize('string, expected', [
(' ', 4),
(' ', 6),
('\t', 8),
('\t\t', 16),
(' \t', 8),
(' \t', 16),
])
@pytest.mark.parametrize(
"string, expected",
[
(" ", 4),
(" ", 6),
("\t", 8),
("\t\t", 16),
(" \t", 8),
(" \t", 16),
],
)
def test_expand_indent(string, expected):
"""Verify we correctly measure the amount of indentation."""
actual = processor.expand_indent(string)
assert expected == actual
@pytest.mark.parametrize('token, log_string', [
[(tokenize.COMMENT, '# this is a comment',
@pytest.mark.parametrize(
"token, log_string",
[
[
(
tokenize.COMMENT,
"# this is a comment",
(1, 0), # (start_row, start_column)
(1, 19), # (end_ro, end_column)
'# this is a comment',),
"l.1\t[:19]\tCOMMENT\t'# this is a comment'"],
[(tokenize.COMMENT, '# this is a comment',
"# this is a comment",
),
"l.1\t[:19]\tCOMMENT\t'# this is a comment'",
],
[
(
tokenize.COMMENT,
"# this is a comment",
(1, 5), # (start_row, start_column)
(1, 19), # (end_ro, end_column)
'# this is a comment',),
"l.1\t[5:19]\tCOMMENT\t'# this is a comment'"],
[(tokenize.COMMENT, '# this is a comment',
"# this is a comment",
),
"l.1\t[5:19]\tCOMMENT\t'# this is a comment'",
],
[
(
tokenize.COMMENT,
"# this is a comment",
(1, 0), # (start_row, start_column)
(2, 19), # (end_ro, end_column)
'# this is a comment',),
"l.1\tl.2\tCOMMENT\t'# this is a comment'"],
])
"# this is a comment",
),
"l.1\tl.2\tCOMMENT\t'# this is a comment'",
],
],
)
def test_log_token(token, log_string):
"""Verify we use the log object passed in."""
log = mock.Mock()
@ -359,15 +425,18 @@ def test_log_token(token, log_string):
)
@pytest.mark.parametrize('current_count, token_text, expected', [
(0, '(', 1),
(0, '[', 1),
(0, '{', 1),
(1, ')', 0),
(1, ']', 0),
(1, '}', 0),
(10, '+', 10),
])
@pytest.mark.parametrize(
"current_count, token_text, expected",
[
(0, "(", 1),
(0, "[", 1),
(0, "{", 1),
(1, ")", 0),
(1, "]", 0),
(1, "}", 0),
(10, "+", 10),
],
)
def test_count_parentheses(current_count, token_text, expected):
"""Verify our arithmetic is correct."""
assert processor.count_parentheses(current_count, token_text) == expected

View file

@ -7,8 +7,8 @@ from flake8.formatting import default
def options(**kwargs):
"""Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None)
kwargs.setdefault('tee', False)
kwargs.setdefault("output_file", None)
kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs)
@ -18,22 +18,23 @@ def test_caches_filenames_already_printed():
assert formatter.filenames_already_printed == set()
formatter.format(
style_guide.Violation('code', 'file.py', 1, 1, 'text', 'l'))
assert formatter.filenames_already_printed == {'file.py'}
style_guide.Violation("code", "file.py", 1, 1, "text", "l")
)
assert formatter.filenames_already_printed == {"file.py"}
def test_only_returns_a_string_once_from_format():
"""Verify format ignores the second error with the same filename."""
formatter = default.FilenameOnly(options())
error = style_guide.Violation('code', 'file.py', 1, 1, 'text', '1')
error = style_guide.Violation("code", "file.py", 1, 1, "text", "1")
assert formatter.format(error) == 'file.py'
assert formatter.format(error) == "file.py"
assert formatter.format(error) is None
def test_show_source_returns_nothing():
"""Verify show_source returns nothing."""
formatter = default.FilenameOnly(options())
error = style_guide.Violation('code', 'file.py', 1, 1, 'text', '1')
error = style_guide.Violation("code", "file.py", 1, 1, "text", "1")
assert formatter.show_source(error) is None

View file

@ -23,8 +23,8 @@ def test_get_local_plugins_uses_cli_config():
config_finder = mock.MagicMock()
config_finder.cli_config.return_value = config_obj
config_finder.ignore_config_files = False
config_obj.get.return_value = ''
config_file_value = 'foo.ini'
config_obj.get.return_value = ""
config_file_value = "foo.ini"
config_finder.config_file = config_file_value
config.get_local_plugins(config_finder)
@ -34,12 +34,12 @@ def test_get_local_plugins_uses_cli_config():
def test_get_local_plugins():
"""Verify get_local_plugins returns expected plugins."""
config_fixture_path = 'tests/fixtures/config_files/local-plugin.ini'
config_finder = config.ConfigFileFinder('flake8')
config_fixture_path = "tests/fixtures/config_files/local-plugin.ini"
config_finder = config.ConfigFileFinder("flake8")
with mock.patch.object(config_finder, 'local_config_files') as localcfs:
with mock.patch.object(config_finder, "local_config_files") as localcfs:
localcfs.return_value = [config_fixture_path]
local_plugins = config.get_local_plugins(config_finder)
assert local_plugins.extension == ['XE = test_plugins:ExtensionTestPlugin']
assert local_plugins.report == ['XR = test_plugins:ReportTestPlugin']
assert local_plugins.extension == ["XE = test_plugins:ExtensionTestPlugin"]
assert local_plugins.report == ["XR = test_plugins:ReportTestPlugin"]

View file

@ -21,12 +21,14 @@ def test_get_style_guide():
)
mockedapp = mock.Mock()
mockedapp.parse_preliminary_options.return_value = (prelim_opts, [])
mockedapp.program = 'flake8'
with mock.patch('flake8.api.legacy.config.ConfigFileFinder') as mock_config_finder: # noqa: E501
mockedapp.program = "flake8"
with mock.patch(
"flake8.api.legacy.config.ConfigFileFinder"
) as mock_config_finder: # noqa: E501
config_finder = ConfigFileFinder(mockedapp.program)
mock_config_finder.return_value = config_finder
with mock.patch('flake8.main.application.Application') as application:
with mock.patch("flake8.main.application.Application") as application:
application.return_value = mockedapp
style_guide = api.get_style_guide()
@ -35,7 +37,8 @@ def test_get_style_guide():
mockedapp.find_plugins.assert_called_once_with(config_finder)
mockedapp.register_plugin_options.assert_called_once_with()
mockedapp.parse_configuration_and_cli.assert_called_once_with(
config_finder, [])
config_finder, []
)
mockedapp.make_formatter.assert_called_once_with()
mockedapp.make_guide.assert_called_once_with()
mockedapp.make_file_checker_manager.assert_called_once_with()
@ -45,22 +48,22 @@ def test_get_style_guide():
def test_styleguide_options():
"""Show that we proxy the StyleGuide.options attribute."""
app = mock.Mock()
app.options = 'options'
app.options = "options"
style_guide = api.StyleGuide(app)
assert style_guide.options == 'options'
assert style_guide.options == "options"
def test_styleguide_paths():
"""Show that we proxy the StyleGuide.paths attribute."""
app = mock.Mock()
app.paths = 'paths'
app.paths = "paths"
style_guide = api.StyleGuide(app)
assert style_guide.paths == 'paths'
assert style_guide.paths == "paths"
def test_styleguide_check_files():
"""Verify we call the right application methods."""
paths = ['foo', 'bar']
paths = ["foo", "bar"]
app = mock.Mock()
style_guide = api.StyleGuide(app)
report = style_guide.check_files(paths)
@ -80,8 +83,8 @@ def test_styleguide_excluded():
file_checker_manager = app.file_checker_manager = mock.Mock()
style_guide = api.StyleGuide(app)
style_guide.excluded('file.py')
file_checker_manager.is_path_excluded.assert_called_once_with('file.py')
style_guide.excluded("file.py")
file_checker_manager.is_path_excluded.assert_called_once_with("file.py")
def test_styleguide_excluded_with_parent():
@ -95,10 +98,10 @@ def test_styleguide_excluded_with_parent():
file_checker_manager.is_path_excluded.return_value = False
style_guide = api.StyleGuide(app)
style_guide.excluded('file.py', 'parent')
style_guide.excluded("file.py", "parent")
assert file_checker_manager.is_path_excluded.call_args_list == [
mock.call('file.py'),
mock.call(os.path.join('parent', 'file.py')),
mock.call("file.py"),
mock.call(os.path.join("parent", "file.py")),
]
@ -123,7 +126,7 @@ def test_styleguide_init_report_with_non_subclass():
def test_styleguide_init_report():
"""Verify we do the right incantation for the Application."""
app = mock.Mock(guide='fake')
app = mock.Mock(guide="fake")
style_guide = api.StyleGuide(app)
class FakeFormatter(formatter.BaseFormatter):
@ -140,16 +143,16 @@ def test_styleguide_input_file():
"""Verify we call StyleGuide.check_files with the filename."""
app = mock.Mock()
style_guide = api.StyleGuide(app)
with mock.patch.object(style_guide, 'check_files') as check_files:
style_guide.input_file('file.py')
check_files.assert_called_once_with(['file.py'])
with mock.patch.object(style_guide, "check_files") as check_files:
style_guide.input_file("file.py")
check_files.assert_called_once_with(["file.py"])
def test_report_total_errors():
"""Verify total errors is just a proxy attribute."""
app = mock.Mock(result_count='Fake count')
app = mock.Mock(result_count="Fake count")
report = api.Report(app)
assert report.total_errors == 'Fake count'
assert report.total_errors == "Fake count"
def test_report_get_statistics():
@ -160,5 +163,5 @@ def test_report_get_statistics():
app = mock.Mock(guide=style_guide)
report = api.Report(app)
assert report.get_statistics('E') == []
stats.statistics_for.assert_called_once_with('E')
assert report.get_statistics("E") == []
stats.statistics_for.assert_called_once_with("E")

View file

@ -11,47 +11,54 @@ from flake8.options import manager
@pytest.fixture
def optmanager():
"""Generate an OptionManager with simple values."""
return manager.OptionManager(prog='flake8', version='3.0.0a1')
return manager.OptionManager(prog="flake8", version="3.0.0a1")
@pytest.fixture
def config_finder():
"""Generate a simple ConfigFileFinder."""
return config.ConfigFileFinder('flake8')
return config.ConfigFileFinder("flake8")
def test_parse_cli_config(optmanager, config_finder):
"""Parse the specified config file as a cli config file."""
optmanager.add_option('--exclude', parse_from_config=True,
optmanager.add_option(
"--exclude",
parse_from_config=True,
comma_separated_list=True,
normalize_paths=True)
optmanager.add_option('--ignore', parse_from_config=True,
comma_separated_list=True)
optmanager.add_option('--quiet', parse_from_config=True,
action='count')
normalize_paths=True,
)
optmanager.add_option(
"--ignore", parse_from_config=True, comma_separated_list=True
)
optmanager.add_option("--quiet", parse_from_config=True, action="count")
parser = config.MergedConfigParser(optmanager, config_finder)
config_file = 'tests/fixtures/config_files/cli-specified.ini'
config_file = "tests/fixtures/config_files/cli-specified.ini"
parsed_config = parser.parse_cli_config(config_file)
config_dir = os.path.dirname(config_file)
assert parsed_config == {
'ignore': ['E123', 'W234', 'E111'],
'exclude': [
os.path.abspath(os.path.join(config_dir, 'foo/')),
os.path.abspath(os.path.join(config_dir, 'bar/')),
os.path.abspath(os.path.join(config_dir, 'bogus/')),
"ignore": ["E123", "W234", "E111"],
"exclude": [
os.path.abspath(os.path.join(config_dir, "foo/")),
os.path.abspath(os.path.join(config_dir, "bar/")),
os.path.abspath(os.path.join(config_dir, "bogus/")),
],
'quiet': 1,
"quiet": 1,
}
@pytest.mark.parametrize('filename,is_configured_by', [
('tests/fixtures/config_files/cli-specified.ini', True),
('tests/fixtures/config_files/no-flake8-section.ini', False),
])
@pytest.mark.parametrize(
"filename,is_configured_by",
[
("tests/fixtures/config_files/cli-specified.ini", True),
("tests/fixtures/config_files/no-flake8-section.ini", False),
],
)
def test_is_configured_by(
filename, is_configured_by, optmanager, config_finder):
filename, is_configured_by, optmanager, config_finder
):
"""Verify the behaviour of the is_configured_by method."""
parsed_config, _ = config.ConfigFileFinder._read_config(filename)
parser = config.MergedConfigParser(optmanager, config_finder)
@ -61,83 +68,94 @@ def test_is_configured_by(
def test_parse_user_config(optmanager, config_finder):
"""Verify parsing of user config files."""
optmanager.add_option('--exclude', parse_from_config=True,
optmanager.add_option(
"--exclude",
parse_from_config=True,
comma_separated_list=True,
normalize_paths=True)
optmanager.add_option('--ignore', parse_from_config=True,
comma_separated_list=True)
optmanager.add_option('--quiet', parse_from_config=True,
action='count')
normalize_paths=True,
)
optmanager.add_option(
"--ignore", parse_from_config=True, comma_separated_list=True
)
optmanager.add_option("--quiet", parse_from_config=True, action="count")
parser = config.MergedConfigParser(optmanager, config_finder)
config_finder.user_config_file = ('tests/fixtures/config_files/'
'cli-specified.ini')
config_finder.user_config_file = (
"tests/fixtures/config_files/" "cli-specified.ini"
)
parsed_config = parser.parse_user_config()
assert parsed_config == {
'ignore': ['E123', 'W234', 'E111'],
'exclude': [
os.path.abspath('foo/'),
os.path.abspath('bar/'),
os.path.abspath('bogus/'),
"ignore": ["E123", "W234", "E111"],
"exclude": [
os.path.abspath("foo/"),
os.path.abspath("bar/"),
os.path.abspath("bogus/"),
],
'quiet': 1,
"quiet": 1,
}
def test_parse_local_config(optmanager, config_finder):
"""Verify parsing of local config files."""
optmanager.add_option('--exclude', parse_from_config=True,
optmanager.add_option(
"--exclude",
parse_from_config=True,
comma_separated_list=True,
normalize_paths=True)
optmanager.add_option('--ignore', parse_from_config=True,
comma_separated_list=True)
optmanager.add_option('--quiet', parse_from_config=True,
action='count')
normalize_paths=True,
)
optmanager.add_option(
"--ignore", parse_from_config=True, comma_separated_list=True
)
optmanager.add_option("--quiet", parse_from_config=True, action="count")
parser = config.MergedConfigParser(optmanager, config_finder)
with mock.patch.object(config_finder, 'local_config_files') as localcfs:
with mock.patch.object(config_finder, "local_config_files") as localcfs:
localcfs.return_value = [
'tests/fixtures/config_files/cli-specified.ini'
"tests/fixtures/config_files/cli-specified.ini"
]
parsed_config = parser.parse_local_config()
assert parsed_config == {
'ignore': ['E123', 'W234', 'E111'],
'exclude': [
os.path.abspath('foo/'),
os.path.abspath('bar/'),
os.path.abspath('bogus/'),
"ignore": ["E123", "W234", "E111"],
"exclude": [
os.path.abspath("foo/"),
os.path.abspath("bar/"),
os.path.abspath("bogus/"),
],
'quiet': 1,
"quiet": 1,
}
def test_merge_user_and_local_config(optmanager, config_finder):
"""Verify merging of parsed user and local config files."""
optmanager.add_option('--exclude', parse_from_config=True,
optmanager.add_option(
"--exclude",
parse_from_config=True,
comma_separated_list=True,
normalize_paths=True)
optmanager.add_option('--ignore', parse_from_config=True,
comma_separated_list=True)
optmanager.add_option('--select', parse_from_config=True,
comma_separated_list=True)
normalize_paths=True,
)
optmanager.add_option(
"--ignore", parse_from_config=True, comma_separated_list=True
)
optmanager.add_option(
"--select", parse_from_config=True, comma_separated_list=True
)
parser = config.MergedConfigParser(optmanager, config_finder)
with mock.patch.object(config_finder, 'local_config_files') as localcfs:
with mock.patch.object(config_finder, "local_config_files") as localcfs:
localcfs.return_value = [
'tests/fixtures/config_files/local-config.ini'
"tests/fixtures/config_files/local-config.ini"
]
config_finder.user_config_file = ('tests/fixtures/config_files/'
'user-config.ini')
config_finder.user_config_file = (
"tests/fixtures/config_files/" "user-config.ini"
)
parsed_config = parser.merge_user_and_local_config()
assert parsed_config == {
'exclude': [
os.path.abspath('docs/')
],
'ignore': ['D203'],
'select': ['E', 'W', 'F'],
"exclude": [os.path.abspath("docs/")],
"ignore": ["D203"],
"select": ["E", "W", "F"],
}
@ -154,7 +172,7 @@ def test_parse_isolates_config(optmanager):
def test_parse_uses_cli_config(optmanager):
"""Verify behaviour of the parse method with a specified config."""
config_file_value = 'foo.ini'
config_file_value = "foo.ini"
config_finder = mock.MagicMock()
config_finder.config_file = config_file_value
config_finder.ignore_config_files = False
@ -164,62 +182,74 @@ def test_parse_uses_cli_config(optmanager):
config_finder.cli_config.assert_called_once_with(config_file_value)
@pytest.mark.parametrize('config_fixture_path', [
'tests/fixtures/config_files/cli-specified.ini',
'tests/fixtures/config_files/cli-specified-with-inline-comments.ini',
'tests/fixtures/config_files/cli-specified-without-inline-comments.ini',
])
@pytest.mark.parametrize(
"config_fixture_path",
[
"tests/fixtures/config_files/cli-specified.ini",
"tests/fixtures/config_files/cli-specified-with-inline-comments.ini",
"tests/fixtures/config_files/cli-specified-without-inline-comments.ini", # noqa: E501
],
)
def test_parsed_configs_are_equivalent(
optmanager, config_finder, config_fixture_path):
optmanager, config_finder, config_fixture_path
):
"""Verify the each file matches the expected parsed output.
This is used to ensure our documented behaviour does not regress.
"""
optmanager.add_option('--exclude', parse_from_config=True,
optmanager.add_option(
"--exclude",
parse_from_config=True,
comma_separated_list=True,
normalize_paths=True)
optmanager.add_option('--ignore', parse_from_config=True,
comma_separated_list=True)
normalize_paths=True,
)
optmanager.add_option(
"--ignore", parse_from_config=True, comma_separated_list=True
)
parser = config.MergedConfigParser(optmanager, config_finder)
with mock.patch.object(config_finder, 'local_config_files') as localcfs:
with mock.patch.object(config_finder, "local_config_files") as localcfs:
localcfs.return_value = [config_fixture_path]
with mock.patch.object(config_finder,
'user_config_file') as usercf:
usercf.return_value = ''
with mock.patch.object(config_finder, "user_config_file") as usercf:
usercf.return_value = ""
parsed_config = parser.merge_user_and_local_config()
assert parsed_config['ignore'] == ['E123', 'W234', 'E111']
assert parsed_config['exclude'] == [
os.path.abspath('foo/'),
os.path.abspath('bar/'),
os.path.abspath('bogus/'),
assert parsed_config["ignore"] == ["E123", "W234", "E111"]
assert parsed_config["exclude"] == [
os.path.abspath("foo/"),
os.path.abspath("bar/"),
os.path.abspath("bogus/"),
]
@pytest.mark.parametrize('config_file', [
'tests/fixtures/config_files/config-with-hyphenated-options.ini'
])
@pytest.mark.parametrize(
"config_file",
["tests/fixtures/config_files/config-with-hyphenated-options.ini"],
)
def test_parsed_hyphenated_and_underscored_names(
optmanager, config_finder, config_file):
optmanager, config_finder, config_file
):
"""Verify we find hyphenated option names as well as underscored.
This tests for options like --max-line-length and --enable-extensions
which are able to be specified either as max-line-length or
max_line_length in our config files.
"""
optmanager.add_option('--max-line-length', parse_from_config=True,
type=int)
optmanager.add_option('--enable-extensions', parse_from_config=True,
comma_separated_list=True)
optmanager.add_option(
"--max-line-length", parse_from_config=True, type=int
)
optmanager.add_option(
"--enable-extensions",
parse_from_config=True,
comma_separated_list=True,
)
parser = config.MergedConfigParser(optmanager, config_finder)
with mock.patch.object(config_finder, 'local_config_files') as localcfs:
with mock.patch.object(config_finder, "local_config_files") as localcfs:
localcfs.return_value = [config_file]
with mock.patch.object(config_finder,
'user_config_file') as usercf:
usercf.return_value = ''
with mock.patch.object(config_finder, "user_config_file") as usercf:
usercf.return_value = ""
parsed_config = parser.merge_user_and_local_config()
assert parsed_config['max_line_length'] == 110
assert parsed_config['enable_extensions'] == ['H101', 'H235']
assert parsed_config["max_line_length"] == 110
assert parsed_config["enable_extensions"] == ["H101", "H235"]

View file

@ -7,15 +7,15 @@ from flake8.formatting import default
def options(**kwargs):
"""Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None)
kwargs.setdefault('tee', False)
kwargs.setdefault("output_file", None)
kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs)
def test_format_returns_nothing():
"""Verify Nothing.format returns None."""
formatter = default.Nothing(options())
error = style_guide.Violation('code', 'file.py', 1, 1, 'text', '1')
error = style_guide.Violation("code", "file.py", 1, 1, "text", "1")
assert formatter.format(error) is None
@ -23,6 +23,6 @@ def test_format_returns_nothing():
def test_show_source_returns_nothing():
"""Verify Nothing.show_source returns None."""
formatter = default.Nothing(options())
error = style_guide.Violation('code', 'file.py', 1, 1, 'text', '1')
error = style_guide.Violation("code", "file.py", 1, 1, "text", "1")
assert formatter.show_source(error) is None

View file

@ -10,9 +10,9 @@ from flake8.options import manager
def test_to_argparse():
"""Test conversion to an argparse arguments."""
opt = manager.Option(
short_option_name='-t',
long_option_name='--test',
action='count',
short_option_name="-t",
long_option_name="--test",
action="count",
parse_from_config=True,
normalize_paths=True,
)
@ -20,42 +20,44 @@ def test_to_argparse():
assert opt.parse_from_config is True
args, kwargs = opt.to_argparse()
assert args == ['-t', '--test']
assert kwargs == {'action': 'count', 'type': mock.ANY}
assert isinstance(kwargs['type'], functools.partial)
assert args == ["-t", "--test"]
assert kwargs == {"action": "count", "type": mock.ANY}
assert isinstance(kwargs["type"], functools.partial)
def test_to_optparse():
"""Test that .to_optparse() produces a useful error message."""
with pytest.raises(AttributeError) as excinfo:
manager.Option('--foo').to_optparse
msg, = excinfo.value.args
assert msg == 'to_optparse: flake8 now uses argparse'
manager.Option("--foo").to_optparse
(msg,) = excinfo.value.args
assert msg == "to_optparse: flake8 now uses argparse"
def test_to_argparse_creates_an_option_as_we_expect():
"""Show that we pass all keyword args to argparse."""
opt = manager.Option('-t', '--test', action='count')
opt = manager.Option("-t", "--test", action="count")
args, kwargs = opt.to_argparse()
assert args == ['-t', '--test']
assert kwargs == {'action': 'count'}
assert args == ["-t", "--test"]
assert kwargs == {"action": "count"}
def test_config_name_generation():
"""Show that we generate the config name deterministically."""
opt = manager.Option(long_option_name='--some-very-long-option-name',
parse_from_config=True)
opt = manager.Option(
long_option_name="--some-very-long-option-name",
parse_from_config=True,
)
assert opt.config_name == 'some_very_long_option_name'
assert opt.config_name == "some_very_long_option_name"
def test_config_name_needs_long_option_name():
"""Show that we error out if the Option should be parsed from config."""
with pytest.raises(ValueError):
manager.Option('-s', parse_from_config=True)
manager.Option("-s", parse_from_config=True)
def test_dest_is_not_overridden():
"""Show that we do not override custom destinations."""
opt = manager.Option('-s', '--short', dest='something_not_short')
assert opt.dest == 'something_not_short'
opt = manager.Option("-s", "--short", dest="something_not_short")
assert opt.dest == "something_not_short"

View file

@ -9,13 +9,13 @@ from flake8 import utils
from flake8.main.options import JobsArgument
from flake8.options import manager
TEST_VERSION = '3.0.0b1'
TEST_VERSION = "3.0.0b1"
@pytest.fixture
def optmanager():
"""Generate a simple OptionManager with default test arguments."""
return manager.OptionManager(prog='flake8', version=TEST_VERSION)
return manager.OptionManager(prog="flake8", version=TEST_VERSION)
def test_option_manager_creates_option_parser(optmanager):
@ -27,30 +27,29 @@ def test_option_manager_including_parent_options():
"""Verify parent options are included in the parsed options."""
# GIVEN
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('--parent')
parent_parser.add_argument("--parent")
# WHEN
optmanager = manager.OptionManager(
prog='flake8',
version=TEST_VERSION,
parents=[parent_parser])
option, _ = optmanager.parse_args(['--parent', 'foo'])
prog="flake8", version=TEST_VERSION, parents=[parent_parser]
)
option, _ = optmanager.parse_args(["--parent", "foo"])
# THEN
assert option.parent == 'foo'
assert option.parent == "foo"
def test_parse_args_forwarding_default_values(optmanager):
"""Verify default provided values are present in the final result."""
namespace = argparse.Namespace(foo='bar')
namespace = argparse.Namespace(foo="bar")
options, args = optmanager.parse_args([], namespace)
assert options.foo == 'bar'
assert options.foo == "bar"
def test_parse_args_forwarding_type_coercion(optmanager):
"""Verify default provided values are type converted from add_option."""
optmanager.add_option('--foo', type=int)
namespace = argparse.Namespace(foo='5')
optmanager.add_option("--foo", type=int)
namespace = argparse.Namespace(foo="5")
options, args = optmanager.parse_args([], namespace)
assert options.foo == 5
@ -60,8 +59,8 @@ def test_add_option_short_option_only(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('-s', help='Test short opt')
assert optmanager.options[0].short_option_name == '-s'
optmanager.add_option("-s", help="Test short opt")
assert optmanager.options[0].short_option_name == "-s"
def test_add_option_long_option_only(optmanager):
@ -69,9 +68,9 @@ def test_add_option_long_option_only(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--long', help='Test long opt')
optmanager.add_option("--long", help="Test long opt")
assert optmanager.options[0].short_option_name is manager._ARG.NO
assert optmanager.options[0].long_option_name == '--long'
assert optmanager.options[0].long_option_name == "--long"
def test_add_short_and_long_option_names(optmanager):
@ -79,9 +78,9 @@ def test_add_short_and_long_option_names(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('-b', '--both', help='Test both opts')
assert optmanager.options[0].short_option_name == '-b'
assert optmanager.options[0].long_option_name == '--both'
optmanager.add_option("-b", "--both", help="Test both opts")
assert optmanager.options[0].short_option_name == "-b"
assert optmanager.options[0].long_option_name == "--both"
def test_add_option_with_custom_args(optmanager):
@ -89,11 +88,11 @@ def test_add_option_with_custom_args(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--parse', parse_from_config=True)
optmanager.add_option('--commas', comma_separated_list=True)
optmanager.add_option('--files', normalize_paths=True)
optmanager.add_option("--parse", parse_from_config=True)
optmanager.add_option("--commas", comma_separated_list=True)
optmanager.add_option("--files", normalize_paths=True)
attrs = ['parse_from_config', 'comma_separated_list', 'normalize_paths']
attrs = ["parse_from_config", "comma_separated_list", "normalize_paths"]
for option, attr in zip(optmanager.options, attrs):
assert getattr(option, attr) is True
@ -103,10 +102,10 @@ def test_parse_args_normalize_path(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--config', normalize_paths=True)
optmanager.add_option("--config", normalize_paths=True)
options, args = optmanager.parse_args(['--config', '../config.ini'])
assert options.config == os.path.abspath('../config.ini')
options, args = optmanager.parse_args(["--config", "../config.ini"])
assert options.config == os.path.abspath("../config.ini")
def test_parse_args_handles_comma_separated_defaults(optmanager):
@ -114,11 +113,12 @@ def test_parse_args_handles_comma_separated_defaults(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--exclude', default='E123,W234',
comma_separated_list=True)
optmanager.add_option(
"--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args([])
assert options.exclude == ['E123', 'W234']
assert options.exclude == ["E123", "W234"]
def test_parse_args_handles_comma_separated_lists(optmanager):
@ -126,11 +126,12 @@ def test_parse_args_handles_comma_separated_lists(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--exclude', default='E123,W234',
comma_separated_list=True)
optmanager.add_option(
"--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args(['--exclude', 'E201,W111,F280'])
assert options.exclude == ['E201', 'W111', 'F280']
options, args = optmanager.parse_args(["--exclude", "E201,W111,F280"])
assert options.exclude == ["E201", "W111", "F280"]
def test_parse_args_normalize_paths(optmanager):
@ -138,57 +139,61 @@ def test_parse_args_normalize_paths(optmanager):
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option('--extra-config', normalize_paths=True,
comma_separated_list=True)
optmanager.add_option(
"--extra-config", normalize_paths=True, comma_separated_list=True
)
options, args = optmanager.parse_args([
'--extra-config', '../config.ini,tox.ini,flake8/some-other.cfg'
])
options, args = optmanager.parse_args(
["--extra-config", "../config.ini,tox.ini,flake8/some-other.cfg"]
)
assert options.extra_config == [
os.path.abspath('../config.ini'),
'tox.ini',
os.path.abspath('flake8/some-other.cfg'),
os.path.abspath("../config.ini"),
"tox.ini",
os.path.abspath("flake8/some-other.cfg"),
]
def test_generate_versions(optmanager):
"""Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False),
manager.PluginVersion('Testing 101', '0.0.0', False),
manager.PluginVersion('Testing 300', '0.0.0', True),
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", True),
]
assert (optmanager.generate_versions()
== 'Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0')
assert (
optmanager.generate_versions()
== "Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0"
)
def test_plugins_are_sorted_in_generate_versions(optmanager):
"""Verify we sort before joining strings in generate_versions."""
optmanager.registered_plugins = [
manager.PluginVersion('pyflakes', '1.5.0', False),
manager.PluginVersion('mccabe', '0.7.0', False),
manager.PluginVersion('pycodestyle', '2.2.0', False),
manager.PluginVersion('flake8-docstrings', '0.6.1', False),
manager.PluginVersion('flake8-bugbear', '2016.12.1', False),
manager.PluginVersion("pyflakes", "1.5.0", False),
manager.PluginVersion("mccabe", "0.7.0", False),
manager.PluginVersion("pycodestyle", "2.2.0", False),
manager.PluginVersion("flake8-docstrings", "0.6.1", False),
manager.PluginVersion("flake8-bugbear", "2016.12.1", False),
]
assert (optmanager.generate_versions()
== 'flake8-bugbear: 2016.12.1, '
'flake8-docstrings: 0.6.1, '
'mccabe: 0.7.0, '
'pycodestyle: 2.2.0, '
'pyflakes: 1.5.0')
assert (
optmanager.generate_versions() == "flake8-bugbear: 2016.12.1, "
"flake8-docstrings: 0.6.1, "
"mccabe: 0.7.0, "
"pycodestyle: 2.2.0, "
"pyflakes: 1.5.0"
)
def test_generate_versions_with_format_string(optmanager):
"""Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins.update([
manager.PluginVersion('Testing', '0.0.0', False),
manager.PluginVersion('Testing', '0.0.0', False),
manager.PluginVersion('Testing', '0.0.0', False),
])
assert (
optmanager.generate_versions() == 'Testing: 0.0.0'
optmanager.registered_plugins.update(
[
manager.PluginVersion("Testing", "0.0.0", False),
manager.PluginVersion("Testing", "0.0.0", False),
manager.PluginVersion("Testing", "0.0.0", False),
]
)
assert optmanager.generate_versions() == "Testing: 0.0.0"
def test_update_version_string(optmanager):
@ -197,17 +202,20 @@ def test_update_version_string(optmanager):
assert optmanager.version_action.version == TEST_VERSION
optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False),
manager.PluginVersion('Testing 101', '0.0.0', False),
manager.PluginVersion('Testing 300', '0.0.0', False),
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", False),
]
optmanager.update_version_string()
assert optmanager.version == TEST_VERSION
assert (optmanager.version_action.version == TEST_VERSION
+ ' (Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0) '
+ utils.get_python_version())
assert (
optmanager.version_action.version
== TEST_VERSION
+ " (Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0) "
+ utils.get_python_version()
)
def test_generate_epilog(optmanager):
@ -215,14 +223,14 @@ def test_generate_epilog(optmanager):
assert optmanager.parser.epilog is None
optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False),
manager.PluginVersion('Testing 101', '0.0.0', False),
manager.PluginVersion('Testing 300', '0.0.0', False),
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", False),
]
expected_value = (
'Installed plugins: Testing 100: 0.0.0, Testing 101: 0.0.0, Testing'
' 300: 0.0.0'
"Installed plugins: Testing 100: 0.0.0, Testing 101: 0.0.0, Testing"
" 300: 0.0.0"
)
optmanager.generate_epilog()
@ -233,14 +241,14 @@ def test_extend_default_ignore(optmanager):
"""Verify that we update the extended default ignore list."""
assert optmanager.extended_default_ignore == set()
optmanager.extend_default_ignore(['T100', 'T101', 'T102'])
assert optmanager.extended_default_ignore == {'T100', 'T101', 'T102'}
optmanager.extend_default_ignore(["T100", "T101", "T102"])
assert optmanager.extended_default_ignore == {"T100", "T101", "T102"}
def test_parse_known_args(optmanager):
"""Verify we ignore unknown options."""
with mock.patch('sys.exit') as sysexit:
optmanager.parse_known_args(['--max-complexity', '5'])
with mock.patch("sys.exit") as sysexit:
optmanager.parse_known_args(["--max-complexity", "5"])
assert sysexit.called is False
@ -249,101 +257,101 @@ def test_optparse_normalize_callback_option_legacy(optmanager):
"""Test the optparse shim for `callback=`."""
callback_foo = mock.Mock()
optmanager.add_option(
'--foo',
action='callback',
"--foo",
action="callback",
callback=callback_foo,
callback_args=(1, 2),
callback_kwargs={'a': 'b'},
callback_kwargs={"a": "b"},
)
callback_bar = mock.Mock()
optmanager.add_option(
'--bar',
action='callback',
type='string',
"--bar",
action="callback",
type="string",
callback=callback_bar,
)
callback_baz = mock.Mock()
optmanager.add_option(
'--baz',
action='callback',
type='string',
"--baz",
action="callback",
type="string",
nargs=2,
callback=callback_baz,
)
optmanager.parse_args(['--foo', '--bar', 'bararg', '--baz', '1', '2'])
optmanager.parse_args(["--foo", "--bar", "bararg", "--baz", "1", "2"])
callback_foo.assert_called_once_with(
mock.ANY, # the option / action instance
'--foo',
"--foo",
None,
mock.ANY, # the OptionParser / ArgumentParser
1,
2,
a='b',
a="b",
)
callback_bar.assert_called_once_with(
mock.ANY, # the option / action instance
'--bar',
'bararg',
"--bar",
"bararg",
mock.ANY, # the OptionParser / ArgumentParser
)
callback_baz.assert_called_once_with(
mock.ANY, # the option / action instance
'--baz',
('1', '2'),
"--baz",
("1", "2"),
mock.ANY, # the OptionParser / ArgumentParser
)
@pytest.mark.parametrize(
('type_s', 'input_val', 'expected'),
("type_s", "input_val", "expected"),
(
('int', '5', 5),
('long', '6', 6),
('string', 'foo', 'foo'),
('float', '1.5', 1.5),
('complex', '1+5j', 1 + 5j),
("int", "5", 5),
("long", "6", 6),
("string", "foo", "foo"),
("float", "1.5", 1.5),
("complex", "1+5j", 1 + 5j),
# optparse allows this but does not document it
('str', 'foo', 'foo'),
("str", "foo", "foo"),
),
)
def test_optparse_normalize_types(optmanager, type_s, input_val, expected):
"""Test the optparse shim for type="typename"."""
optmanager.add_option('--foo', type=type_s)
opts, args = optmanager.parse_args(['--foo', input_val])
optmanager.add_option("--foo", type=type_s)
opts, args = optmanager.parse_args(["--foo", input_val])
assert opts.foo == expected
def test_optparse_normalize_choice_type(optmanager):
"""Test the optparse shim for type="choice"."""
optmanager.add_option('--foo', type='choice', choices=('1', '2', '3'))
opts, args = optmanager.parse_args(['--foo', '1'])
assert opts.foo == '1'
optmanager.add_option("--foo", type="choice", choices=("1", "2", "3"))
opts, args = optmanager.parse_args(["--foo", "1"])
assert opts.foo == "1"
# fails to parse
with pytest.raises(SystemExit):
optmanager.parse_args(['--foo', '4'])
optmanager.parse_args(["--foo", "4"])
def test_optparse_normalize_help(optmanager, capsys):
"""Test the optparse shim for %default in help text."""
optmanager.add_option('--foo', default='bar', help='default: %default')
optmanager.add_option("--foo", default="bar", help="default: %default")
with pytest.raises(SystemExit):
optmanager.parse_args(['--help'])
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert 'default: bar' in output
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 optmanager.group("groupname"):
optmanager.add_option("--foo")
with pytest.raises(SystemExit):
optmanager.parse_args(['--help'])
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert '\ngroupname:\n' in output
assert "\ngroupname:\n" in output
@pytest.mark.parametrize(

View file

@ -11,8 +11,8 @@ 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)
entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin()
entry_point.load.assert_called_once_with()
@ -20,8 +20,8 @@ def test_load_plugin_fallsback_on_old_setuptools():
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)
entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin()
plugin.load_plugin()
@ -31,9 +31,9 @@ def test_load_plugin_is_idempotent():
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)
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()
@ -41,9 +41,9 @@ def test_load_plugin_catches_and_reraises_exceptions():
def test_load_noncallable_plugin():
"""Verify that we do not load a non-callable plugin."""
entry_point = mock.Mock(spec=['load'])
entry_point = mock.Mock(spec=["load"])
entry_point.load.return_value = mock.NonCallableMock()
plugin = manager.Plugin('T000', entry_point)
plugin = manager.Plugin("T000", entry_point)
with pytest.raises(exceptions.FailedToLoadPlugin):
plugin.load_plugin()
@ -52,8 +52,8 @@ def test_load_noncallable_plugin():
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)
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()
@ -61,14 +61,14 @@ def test_plugin_property_loads_plugin_on_first_use():
def test_execute_calls_plugin_with_passed_arguments():
"""Verify that we pass arguments directly to the plugin."""
entry_point = mock.Mock(spec=['load'])
entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock()
plugin = manager.Plugin('T000', entry_point)
plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
plugin.execute('arg1', 'arg2', kwarg1='value1', kwarg2='value2')
plugin.execute("arg1", "arg2", kwarg1="value1", kwarg2="value2")
plugin_obj.assert_called_once_with(
'arg1', 'arg2', kwarg1='value1', kwarg2='value2'
"arg1", "arg2", kwarg1="value1", kwarg2="value2"
)
# Extra assertions
@ -77,23 +77,24 @@ def test_execute_calls_plugin_with_passed_arguments():
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)
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'
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'])
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 = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
# Call the method we're testing.
@ -106,10 +107,10 @@ def test_register_options():
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)
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.
@ -122,12 +123,13 @@ def test_register_options_checks_plugin_for_method():
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'])
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 = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj
# Call the method we're testing.
@ -139,10 +141,13 @@ def test_provide_options():
)
@pytest.mark.parametrize('ignore_list, code, expected_list', [
(['E', 'W', 'F', 'C9'], 'W', ['E', 'F', 'C9']),
(['E', 'W', 'F'], 'C9', ['E', 'W', 'F']),
])
@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)
@ -157,8 +162,8 @@ def test_enable(ignore_list, code, 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 = manager.Plugin("U4", mock.Mock())
plugin.enable(optmanager)
optmanager.remove_from_default_ignore.assert_called_once_with(['U4'])
optmanager.remove_from_default_ignore.assert_called_once_with(["U4"])

View file

@ -5,54 +5,53 @@ from flake8._compat import importlib_metadata
from flake8.plugins import manager
@mock.patch.object(importlib_metadata, 'entry_points')
@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')
manager.PluginManager(namespace="testing.entrypoints")
entry_points_mck.assert_called_once_with()
@mock.patch.object(importlib_metadata, 'entry_points')
@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'),
"testing.entrypoints": [
importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint("T200", "", "testing.entrypoints"),
],
}
plugin_mgr = manager.PluginManager(namespace='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)
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')
@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'),
"testing.entrypoints": [
importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint("T200", "", "testing.entrypoints"),
],
}
plugin_mgr = manager.PluginManager(namespace='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')
@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']
namespace="testing.entrypoints", local_plugins=["X = path.to:Plugin"]
)
assert plugin_mgr.plugins['X'].entry_point.value == 'path.to:Plugin'
assert plugin_mgr.plugins["X"].entry_point.value == "path.to:Plugin"

View file

@ -14,8 +14,8 @@ def create_plugin_mock(raise_exception=False):
plugin = mock.create_autospec(manager.Plugin, instance=True)
if raise_exception:
plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin(
plugin_name='T101',
exception=ValueError('Test failure'),
plugin_name="T101",
exception=ValueError("Test failure"),
)
return plugin
@ -28,7 +28,7 @@ def create_mapping_manager_mock(plugins):
yield func(plugin)
# Mock out the PluginManager instance
manager_mock = mock.Mock(spec=['map'])
manager_mock = mock.Mock(spec=["map"])
# Replace the map method
manager_mock.map = fake_map
return manager_mock
@ -47,7 +47,7 @@ class FakeTestType(manager.PluginTypeManager):
namespace = TEST_NAMESPACE
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_instantiates_a_manager(PluginManager): # noqa: N803
"""Verify we create a PluginManager on instantiation."""
FakeTestType()
@ -55,26 +55,22 @@ def test_instantiates_a_manager(PluginManager): # noqa: N803
PluginManager.assert_called_once_with(TEST_NAMESPACE, local_plugins=None)
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_proxies_names_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the names attribute."""
PluginManager.return_value = mock.Mock(names=[
'T100', 'T200', 'T300'
])
PluginManager.return_value = mock.Mock(names=["T100", "T200", "T300"])
type_mgr = FakeTestType()
assert type_mgr.names == ['T100', 'T200', 'T300']
assert type_mgr.names == ["T100", "T200", "T300"]
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_proxies_plugins_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the plugins attribute."""
PluginManager.return_value = mock.Mock(plugins=[
'T100', 'T200', 'T300'
])
PluginManager.return_value = mock.Mock(plugins=["T100", "T200", "T300"])
type_mgr = FakeTestType()
assert type_mgr.plugins == ['T100', 'T200', 'T300']
assert type_mgr.plugins == ["T100", "T200", "T300"]
def test_generate_call_function():
@ -82,21 +78,28 @@ def test_generate_call_function():
optmanager = object()
plugin = mock.Mock(method_name=lambda x: x)
func = manager.PluginTypeManager._generate_call_function(
'method_name', optmanager,
"method_name",
optmanager,
)
assert callable(func)
assert func(plugin) is optmanager
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_load_plugins(PluginManager): # noqa: N803
"""Verify load plugins loads *every* plugin."""
# Create a bunch of fake plugins
plugins = [create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock()]
plugins = [
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
@ -109,13 +112,19 @@ def test_load_plugins(PluginManager): # noqa: N803
assert type_mgr.plugins_loaded is True
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_load_plugins_fails(PluginManager): # noqa: N803
"""Verify load plugins bubbles up exceptions."""
plugins = [create_plugin_mock(), create_plugin_mock(True),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock()]
plugins = [
create_plugin_mock(),
create_plugin_mock(True),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
@ -133,13 +142,19 @@ def test_load_plugins_fails(PluginManager): # noqa: N803
assert plugin.load_plugin.called is False
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
def test_register_options(PluginManager): # noqa: N803
"""Test that we map over every plugin to register options."""
plugins = [create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock()]
plugins = [
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object()
@ -151,13 +166,19 @@ def test_register_options(PluginManager): # noqa: N803
plugin.register_options.assert_called_with(optmanager)
@mock.patch('flake8.plugins.manager.PluginManager')
@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 = [create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), create_plugin_mock()]
plugins = [
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object()
@ -167,32 +188,30 @@ def test_provide_options(PluginManager): # noqa: N803
type_mgr.provide_options(optmanager, options, [])
for plugin in plugins:
plugin.provide_options.assert_called_with(optmanager,
options,
[])
plugin.provide_options.assert_called_with(optmanager, options, [])
@mock.patch('flake8.plugins.manager.PluginManager')
@mock.patch("flake8.plugins.manager.PluginManager")
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)}
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value = create_manager_with_plugins(plugins)
type_mgr = FakeTestType()
for i in range(8):
key = 'T10%i' % i
key = "T10%i" % i
assert key in type_mgr
@mock.patch('flake8.plugins.manager.PluginManager')
@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)}
plugins = {"T10%i" % i: create_plugin_mock() for i in range(8)}
# Return our PluginManager mock
PluginManager.return_value = create_manager_with_plugins(plugins)
type_mgr = FakeTestType()
for i in range(8):
key = 'T10%i' % i
key = "T10%i" % i
assert type_mgr[key] is plugins[key]

View file

@ -18,14 +18,14 @@ def test_all_pyflakes_messages_have_flake8_codes_assigned():
def test_undefined_local_code():
"""In pyflakes 2.1.0 this code's string formatting was changed."""
src = '''\
src = """\
import sys
def f():
sys = sys
'''
"""
tree = ast.parse(src)
checker = pyflakes_shim.FlakesChecker(tree, (), 't.py')
checker = pyflakes_shim.FlakesChecker(tree, (), "t.py")
message_texts = [s for _, _, s, _ in checker.run()]
assert message_texts == [
"F823 local variable 'sys' defined in enclosing scope on line 1 referenced before assignment", # noqa: E501

View file

@ -4,19 +4,19 @@ import pytest
from flake8 import statistics as stats
from flake8 import style_guide
DEFAULT_ERROR_CODE = 'E100'
DEFAULT_FILENAME = 'file.py'
DEFAULT_TEXT = 'Default text'
DEFAULT_ERROR_CODE = "E100"
DEFAULT_FILENAME = "file.py"
DEFAULT_TEXT = "Default text"
def make_error(**kwargs):
"""Create errors with a bunch of default values."""
return style_guide.Violation(
code=kwargs.pop('code', DEFAULT_ERROR_CODE),
filename=kwargs.pop('filename', DEFAULT_FILENAME),
line_number=kwargs.pop('line_number', 1),
column_number=kwargs.pop('column_number', 1),
text=kwargs.pop('text', DEFAULT_TEXT),
code=kwargs.pop("code", DEFAULT_ERROR_CODE),
filename=kwargs.pop("filename", DEFAULT_FILENAME),
line_number=kwargs.pop("line_number", 1),
column_number=kwargs.pop("column_number", 1),
text=kwargs.pop("text", DEFAULT_TEXT),
physical_line=None,
)
@ -29,26 +29,29 @@ def test_key_creation():
assert key.code == DEFAULT_ERROR_CODE
@pytest.mark.parametrize('code, filename, args, expected_result', [
@pytest.mark.parametrize(
"code, filename, args, expected_result",
[
# Error prefix matches
('E123', 'file000.py', ('E', None), True),
('E123', 'file000.py', ('E1', None), True),
('E123', 'file000.py', ('E12', None), True),
('E123', 'file000.py', ('E123', None), True),
("E123", "file000.py", ("E", None), True),
("E123", "file000.py", ("E1", None), True),
("E123", "file000.py", ("E12", None), True),
("E123", "file000.py", ("E123", None), True),
# Error prefix and filename match
('E123', 'file000.py', ('E', 'file000.py'), True),
('E123', 'file000.py', ('E1', 'file000.py'), True),
('E123', 'file000.py', ('E12', 'file000.py'), True),
('E123', 'file000.py', ('E123', 'file000.py'), True),
("E123", "file000.py", ("E", "file000.py"), True),
("E123", "file000.py", ("E1", "file000.py"), True),
("E123", "file000.py", ("E12", "file000.py"), True),
("E123", "file000.py", ("E123", "file000.py"), True),
# Error prefix does not match
('E123', 'file000.py', ('W', None), False),
("E123", "file000.py", ("W", None), False),
# Error prefix matches but filename does not
('E123', 'file000.py', ('E', 'file001.py'), False),
("E123", "file000.py", ("E", "file001.py"), False),
# Error prefix does not match but filename does
('E123', 'file000.py', ('W', 'file000.py'), False),
("E123", "file000.py", ("W", "file000.py"), False),
# Neither error prefix match nor filename
('E123', 'file000.py', ('W', 'file001.py'), False),
])
("E123", "file000.py", ("W", "file001.py"), False),
],
)
def test_key_matching(code, filename, args, expected_result):
"""Verify Key#matches behaves as we expect with fthe above input."""
key = stats.Key.create_from(make_error(code=code, filename=filename))
@ -75,7 +78,7 @@ def test_statistic_increment():
def test_recording_statistics():
"""Verify that we appropriately create a new Statistic and store it."""
aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == []
assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error())
storage = aggregator._store
for key, value in storage.items():
@ -88,9 +91,9 @@ def test_recording_statistics():
def test_statistics_for_single_record():
"""Show we can retrieve the only statistic recorded."""
aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == []
assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error())
statistics = list(aggregator.statistics_for('E'))
statistics = list(aggregator.statistics_for("E"))
assert len(statistics) == 1
assert isinstance(statistics[0], stats.Statistic)
@ -98,11 +101,11 @@ def test_statistics_for_single_record():
def test_statistics_for_filters_by_filename():
"""Show we can retrieve the only statistic recorded."""
aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == []
assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error())
aggregator.record(make_error(filename='example.py'))
aggregator.record(make_error(filename="example.py"))
statistics = list(aggregator.statistics_for('E', DEFAULT_FILENAME))
statistics = list(aggregator.statistics_for("E", DEFAULT_FILENAME))
assert len(statistics) == 1
assert isinstance(statistics[0], stats.Statistic)
@ -111,11 +114,11 @@ def test_statistic_for_retrieves_more_than_one_value():
"""Show this works for more than a couple statistic values."""
aggregator = stats.Statistics()
for i in range(50):
aggregator.record(make_error(code=f'E1{i:02d}'))
aggregator.record(make_error(code=f'W2{i:02d}'))
aggregator.record(make_error(code=f"E1{i:02d}"))
aggregator.record(make_error(code=f"W2{i:02d}"))
statistics = list(aggregator.statistics_for('E'))
statistics = list(aggregator.statistics_for("E"))
assert len(statistics) == 50
statistics = list(aggregator.statistics_for('W22'))
statistics = list(aggregator.statistics_for("W22"))
assert len(statistics) == 10

View file

@ -14,7 +14,9 @@ from flake8.plugins import manager as plugin_manager
RELATIVE_PATHS = ["flake8", "pep8", "pyflakes", "mccabe"]
@pytest.mark.parametrize("value,expected", [
@pytest.mark.parametrize(
"value,expected",
[
("E123,\n\tW234,\n E206", ["E123", "W234", "E206"]),
("E123,W234,E206", ["E123", "W234", "E206"]),
("E123 W234 E206", ["E123", "W234", "E206"]),
@ -26,74 +28,78 @@ RELATIVE_PATHS = ["flake8", "pep8", "pyflakes", "mccabe"]
("E123, W234,, E206,,", ["E123", "W234", "E206"]),
("E123,,W234,,E206,,", ["E123", "W234", "E206"]),
("", []),
])
],
)
def test_parse_comma_separated_list(value, expected):
"""Verify that similar inputs produce identical outputs."""
assert utils.parse_comma_separated_list(value) == expected
@pytest.mark.parametrize(
('value', 'expected'),
("value", "expected"),
(
# empty option configures nothing
('', []), (' ', []), ('\n\n\n', []),
("", []),
(" ", []),
("\n\n\n", []),
# basic case
(
'f.py:E123',
[('f.py', ['E123'])],
"f.py:E123",
[("f.py", ["E123"])],
),
# multiple filenames, multiple codes
(
'f.py,g.py:E,F',
[('f.py', ['E', 'F']), ('g.py', ['E', 'F'])],
"f.py,g.py:E,F",
[("f.py", ["E", "F"]), ("g.py", ["E", "F"])],
),
# demonstrate that whitespace is not important around tokens
(
' f.py , g.py : E , F ',
[('f.py', ['E', 'F']), ('g.py', ['E', 'F'])],
" f.py , g.py : E , F ",
[("f.py", ["E", "F"]), ("g.py", ["E", "F"])],
),
# whitespace can separate groups of configuration
(
'f.py:E g.py:F',
[('f.py', ['E']), ('g.py', ['F'])],
"f.py:E g.py:F",
[("f.py", ["E"]), ("g.py", ["F"])],
),
# newlines can separate groups of configuration
(
'f.py: E\ng.py: F\n',
[('f.py', ['E']), ('g.py', ['F'])],
"f.py: E\ng.py: F\n",
[("f.py", ["E"]), ("g.py", ["F"])],
),
# whitespace can be used in place of commas
(
'f.py g.py: E F',
[('f.py', ['E', 'F']), ('g.py', ['E', 'F'])],
"f.py g.py: E F",
[("f.py", ["E", "F"]), ("g.py", ["E", "F"])],
),
# go ahead, indent your codes
(
'f.py:\n E,F\ng.py:\n G,H',
[('f.py', ['E', 'F']), ('g.py', ['G', 'H'])],
"f.py:\n E,F\ng.py:\n G,H",
[("f.py", ["E", "F"]), ("g.py", ["G", "H"])],
),
# capitalized filenames are ok too
(
'F.py,G.py: F,G',
[('F.py', ['F', 'G']), ('G.py', ['F', 'G'])],
"F.py,G.py: F,G",
[("F.py", ["F", "G"]), ("G.py", ["F", "G"])],
),
# it's easier to allow zero filenames or zero codes than forbid it
(':E', []), ('f.py:', []),
(':E f.py:F', [('f.py', ['F'])]),
('f.py: g.py:F', [('g.py', ['F'])]),
('f.py:E:', []),
('f.py:E.py:', []),
('f.py:Eg.py:F', [('Eg.py', ['F'])]),
(":E", []),
("f.py:", []),
(":E f.py:F", [("f.py", ["F"])]),
("f.py: g.py:F", [("g.py", ["F"])]),
("f.py:E:", []),
("f.py:E.py:", []),
("f.py:Eg.py:F", [("Eg.py", ["F"])]),
# sequences are also valid (?)
(
['f.py:E,F', 'g.py:G,H'],
[('f.py', ['E', 'F']), ('g.py', ['G', 'H'])],
["f.py:E,F", "g.py:G,H"],
[("f.py", ["E", "F"]), ("g.py", ["G", "H"])],
),
# six-digits codes are allowed
(
'f.py: ABC123',
[('f.py', ['ABC123'])],
)
"f.py: ABC123",
[("f.py", ["ABC123"])],
),
),
)
def test_parse_files_to_codes_mapping(value, expected):
@ -102,16 +108,19 @@ def test_parse_files_to_codes_mapping(value, expected):
@pytest.mark.parametrize(
'value',
"value",
(
# code while looking for filenames
'E123', 'f.py,E123', 'f.py E123',
"E123",
"f.py,E123",
"f.py E123",
# eof while looking for filenames
'f.py', 'f.py:E,g.py'
"f.py",
"f.py:E,g.py"
# colon while looking for codes
'f.py::',
"f.py::",
# no separator between
'f.py:E1F1',
"f.py:E1F1",
),
)
def test_invalid_file_list(value):
@ -120,22 +129,32 @@ def test_invalid_file_list(value):
utils.parse_files_to_codes_mapping(value)
@pytest.mark.parametrize("value,expected", [
@pytest.mark.parametrize(
"value,expected",
[
("flake8", "flake8"),
("../flake8", os.path.abspath("../flake8")),
("flake8/", os.path.abspath("flake8")),
])
],
)
def test_normalize_path(value, expected):
"""Verify that we normalize paths provided to the tool."""
assert utils.normalize_path(value) == expected
@pytest.mark.parametrize("value,expected", [
(["flake8", "pep8", "pyflakes", "mccabe"],
["flake8", "pep8", "pyflakes", "mccabe"]),
(["../flake8", "../pep8", "../pyflakes", "../mccabe"],
[os.path.abspath(f"../{p}") for p in RELATIVE_PATHS]),
])
@pytest.mark.parametrize(
"value,expected",
[
(
["flake8", "pep8", "pyflakes", "mccabe"],
["flake8", "pep8", "pyflakes", "mccabe"],
),
(
["../flake8", "../pep8", "../pyflakes", "../mccabe"],
[os.path.abspath(f"../{p}") for p in RELATIVE_PATHS],
),
],
)
def test_normalize_paths(value, expected):
"""Verify we normalizes a sequence of paths provided to the tool."""
assert utils.normalize_paths(value) == expected
@ -143,19 +162,22 @@ def test_normalize_paths(value, expected):
def test_is_windows_checks_for_nt():
"""Verify that we correctly detect Windows."""
with mock.patch.object(os, 'name', 'nt'):
with mock.patch.object(os, "name", "nt"):
assert utils.is_windows() is True
with mock.patch.object(os, 'name', 'posix'):
with mock.patch.object(os, "name", "posix"):
assert utils.is_windows() is False
@pytest.mark.parametrize('filename,patterns,expected', [
('foo.py', [], True),
('foo.py', ['*.pyc'], False),
('foo.pyc', ['*.pyc'], True),
('foo.pyc', ['*.swp', '*.pyc', '*.py'], True),
])
@pytest.mark.parametrize(
"filename,patterns,expected",
[
("foo.py", [], True),
("foo.py", ["*.pyc"], False),
("foo.pyc", ["*.pyc"], True),
("foo.pyc", ["*.swp", "*.pyc", "*.py"], True),
],
)
def test_fnmatch(filename, patterns, expected):
"""Verify that our fnmatch wrapper works as expected."""
assert utils.fnmatch(filename, patterns) is expected
@ -165,104 +187,110 @@ def test_fnmatch(filename, patterns, expected):
def files_dir(tmpdir):
"""Create test dir for testing filenames_from."""
with tmpdir.as_cwd():
tmpdir.join('a/b/c.py').ensure()
tmpdir.join('a/b/d.py').ensure()
tmpdir.join('a/b/e/f.py').ensure()
tmpdir.join("a/b/c.py").ensure()
tmpdir.join("a/b/d.py").ensure()
tmpdir.join("a/b/e/f.py").ensure()
yield tmpdir
def _normpath(s):
return s.replace('/', os.sep)
return s.replace("/", os.sep)
def _normpaths(pths):
return {_normpath(pth) for pth in pths}
@pytest.mark.usefixtures('files_dir')
@pytest.mark.usefixtures("files_dir")
def test_filenames_from_a_directory():
"""Verify that filenames_from walks a directory."""
filenames = set(utils.filenames_from(_normpath('a/b/')))
filenames = set(utils.filenames_from(_normpath("a/b/")))
# should include all files
expected = _normpaths(('a/b/c.py', 'a/b/d.py', 'a/b/e/f.py'))
expected = _normpaths(("a/b/c.py", "a/b/d.py", "a/b/e/f.py"))
assert filenames == expected
@pytest.mark.usefixtures('files_dir')
@pytest.mark.usefixtures("files_dir")
def test_filenames_from_a_directory_with_a_predicate():
"""Verify that predicates filter filenames_from."""
filenames = set(utils.filenames_from(
arg=_normpath('a/b/'),
predicate=lambda path: path.endswith(_normpath('b/c.py')),
))
filenames = set(
utils.filenames_from(
arg=_normpath("a/b/"),
predicate=lambda path: path.endswith(_normpath("b/c.py")),
)
)
# should not include c.py
expected = _normpaths(('a/b/d.py', 'a/b/e/f.py'))
expected = _normpaths(("a/b/d.py", "a/b/e/f.py"))
assert filenames == expected
@pytest.mark.usefixtures('files_dir')
@pytest.mark.usefixtures("files_dir")
def test_filenames_from_a_directory_with_a_predicate_from_the_current_dir():
"""Verify that predicates filter filenames_from."""
filenames = set(utils.filenames_from(
arg=_normpath('./a/b'),
predicate=lambda path: path == 'c.py',
))
filenames = set(
utils.filenames_from(
arg=_normpath("./a/b"),
predicate=lambda path: path == "c.py",
)
)
# none should have matched the predicate so all returned
expected = _normpaths(('./a/b/c.py', './a/b/d.py', './a/b/e/f.py'))
expected = _normpaths(("./a/b/c.py", "./a/b/d.py", "./a/b/e/f.py"))
assert filenames == expected
@pytest.mark.usefixtures('files_dir')
@pytest.mark.usefixtures("files_dir")
def test_filenames_from_a_single_file():
"""Verify that we simply yield that filename."""
filenames = set(utils.filenames_from(_normpath('a/b/c.py')))
assert filenames == {_normpath('a/b/c.py')}
filenames = set(utils.filenames_from(_normpath("a/b/c.py")))
assert filenames == {_normpath("a/b/c.py")}
def test_filenames_from_a_single_file_does_not_exist():
"""Verify that a passed filename which does not exist is returned back."""
filenames = set(utils.filenames_from(_normpath('d/n/e.py')))
assert filenames == {_normpath('d/n/e.py')}
filenames = set(utils.filenames_from(_normpath("d/n/e.py")))
assert filenames == {_normpath("d/n/e.py")}
def test_filenames_from_exclude_doesnt_exclude_directory_names(tmpdir):
"""Verify that we don't greedily exclude subdirs."""
tmpdir.join('1').ensure_dir().join('dont_return_me.py').ensure()
tmpdir.join('2').join('1').ensure_dir().join('return_me.py').ensure()
exclude = [tmpdir.join('1').strpath]
tmpdir.join("1").ensure_dir().join("dont_return_me.py").ensure()
tmpdir.join("2").join("1").ensure_dir().join("return_me.py").ensure()
exclude = [tmpdir.join("1").strpath]
# This acts similar to src.flake8.checker.is_path_excluded
def predicate(pth):
return utils.fnmatch(os.path.abspath(pth), exclude)
with tmpdir.as_cwd():
filenames = list(utils.filenames_from('.', predicate))
assert filenames == [os.path.join('.', '2', '1', 'return_me.py')]
filenames = list(utils.filenames_from(".", predicate))
assert filenames == [os.path.join(".", "2", "1", "return_me.py")]
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_manager.Plugin("plugin-name", object())
plugin._plugin = FakeCheck
assert utils.parameters_for(plugin) == {'tree': True}
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_manager.Plugin("plugin-name", object())
plugin._plugin = fake_plugin
assert utils.parameters_for(plugin) == {
'physical_line': True,
'self': True,
'tree': True,
'optional': False,
"physical_line": True,
"self": True,
"tree": True,
"optional": False,
}
@ -273,29 +301,32 @@ def read_diff_file(filename):
return content
SINGLE_FILE_DIFF = read_diff_file('tests/fixtures/diffs/single_file_diff')
SINGLE_FILE_DIFF = read_diff_file("tests/fixtures/diffs/single_file_diff")
SINGLE_FILE_INFO = {
'flake8/utils.py': set(range(75, 83)).union(set(range(84, 94))),
"flake8/utils.py": set(range(75, 83)).union(set(range(84, 94))),
}
TWO_FILE_DIFF = read_diff_file('tests/fixtures/diffs/two_file_diff')
TWO_FILE_DIFF = read_diff_file("tests/fixtures/diffs/two_file_diff")
TWO_FILE_INFO = {
'flake8/utils.py': set(range(75, 83)).union(set(range(84, 94))),
'tests/unit/test_utils.py': set(range(115, 128)),
"flake8/utils.py": set(range(75, 83)).union(set(range(84, 94))),
"tests/unit/test_utils.py": set(range(115, 128)),
}
MULTI_FILE_DIFF = read_diff_file('tests/fixtures/diffs/multi_file_diff')
MULTI_FILE_DIFF = read_diff_file("tests/fixtures/diffs/multi_file_diff")
MULTI_FILE_INFO = {
'flake8/utils.py': set(range(75, 83)).union(set(range(84, 94))),
'tests/unit/test_utils.py': set(range(115, 129)),
'tests/fixtures/diffs/single_file_diff': set(range(1, 28)),
'tests/fixtures/diffs/two_file_diff': set(range(1, 46)),
"flake8/utils.py": set(range(75, 83)).union(set(range(84, 94))),
"tests/unit/test_utils.py": set(range(115, 129)),
"tests/fixtures/diffs/single_file_diff": set(range(1, 28)),
"tests/fixtures/diffs/two_file_diff": set(range(1, 46)),
}
@pytest.mark.parametrize("diff, parsed_diff", [
@pytest.mark.parametrize(
"diff, parsed_diff",
[
(SINGLE_FILE_DIFF, SINGLE_FILE_INFO),
(TWO_FILE_DIFF, TWO_FILE_INFO),
(MULTI_FILE_DIFF, MULTI_FILE_INFO),
])
],
)
def test_parse_unified_diff(diff, parsed_diff):
"""Verify that what we parse from a diff matches expectations."""
assert utils.parse_unified_diff(diff) == parsed_diff
@ -304,19 +335,19 @@ def test_parse_unified_diff(diff, parsed_diff):
def test_matches_filename_for_excluding_dotfiles():
"""Verify that `.` and `..` are not matched by `.*`."""
logger = logging.Logger(__name__)
assert not utils.matches_filename('.', ('.*',), '', logger)
assert not utils.matches_filename('..', ('.*',), '', logger)
assert not utils.matches_filename(".", (".*",), "", logger)
assert not utils.matches_filename("..", (".*",), "", logger)
def test_stdin_get_value_crlf():
"""Ensure that stdin is normalized from crlf to lf."""
stdin = io.TextIOWrapper(io.BytesIO(b'1\r\n2\r\n'), 'UTF-8')
with mock.patch.object(sys, 'stdin', stdin):
assert utils.stdin_get_value.__wrapped__() == '1\n2\n'
stdin = io.TextIOWrapper(io.BytesIO(b"1\r\n2\r\n"), "UTF-8")
with mock.patch.object(sys, "stdin", stdin):
assert utils.stdin_get_value.__wrapped__() == "1\n2\n"
def test_stdin_unknown_coding_token():
"""Ensure we produce source even for unknown encodings."""
stdin = io.TextIOWrapper(io.BytesIO(b'# coding: unknown\n'), 'UTF-8')
with mock.patch.object(sys, 'stdin', stdin):
assert utils.stdin_get_value.__wrapped__() == '# coding: unknown\n'
stdin = io.TextIOWrapper(io.BytesIO(b"# coding: unknown\n"), "UTF-8")
with mock.patch.object(sys, "stdin", stdin):
assert utils.stdin_get_value.__wrapped__() == "# coding: unknown\n"

View file

@ -6,61 +6,74 @@ import pytest
from flake8 import style_guide
@pytest.mark.parametrize('error_code,physical_line,expected_result', [
('E111', 'a = 1', False),
('E121', 'a = 1 # noqa: E111', False),
('E121', 'a = 1 # noqa: E111,W123,F821', False),
('E111', 'a = 1 # noqa: E111,W123,F821', True),
('W123', 'a = 1 # noqa: E111,W123,F821', True),
('W123', 'a = 1 # noqa: E111, W123,F821', True),
('E111', 'a = 1 # noqa: E11,W123,F821', True),
('E121', 'a = 1 # noqa:E111,W123,F821', False),
('E111', 'a = 1 # noqa:E111,W123,F821', True),
('W123', 'a = 1 # noqa:E111,W123,F821', True),
('W123', 'a = 1 # noqa:E111, W123,F821', True),
('E111', 'a = 1 # noqa:E11,W123,F821', True),
('E111', 'a = 1 # noqa, analysis:ignore', True),
('E111', 'a = 1 # noqa analysis:ignore', True),
('E111', 'a = 1 # noqa - We do not care', True),
('E111', 'a = 1 # noqa: We do not care', True),
('E111', 'a = 1 # noqa:We do not care', True),
('ABC123', 'a = 1 # noqa: ABC123', True),
('E111', 'a = 1 # noqa: ABC123', False),
('ABC123', 'a = 1 # noqa: ABC124', False),
])
@pytest.mark.parametrize(
"error_code,physical_line,expected_result",
[
("E111", "a = 1", False),
("E121", "a = 1 # noqa: E111", False),
("E121", "a = 1 # noqa: E111,W123,F821", False),
("E111", "a = 1 # noqa: E111,W123,F821", True),
("W123", "a = 1 # noqa: E111,W123,F821", True),
("W123", "a = 1 # noqa: E111, W123,F821", True),
("E111", "a = 1 # noqa: E11,W123,F821", True),
("E121", "a = 1 # noqa:E111,W123,F821", False),
("E111", "a = 1 # noqa:E111,W123,F821", True),
("W123", "a = 1 # noqa:E111,W123,F821", True),
("W123", "a = 1 # noqa:E111, W123,F821", True),
("E111", "a = 1 # noqa:E11,W123,F821", True),
("E111", "a = 1 # noqa, analysis:ignore", True),
("E111", "a = 1 # noqa analysis:ignore", True),
("E111", "a = 1 # noqa - We do not care", True),
("E111", "a = 1 # noqa: We do not care", True),
("E111", "a = 1 # noqa:We do not care", True),
("ABC123", "a = 1 # noqa: ABC123", True),
("E111", "a = 1 # noqa: ABC123", False),
("ABC123", "a = 1 # noqa: ABC124", False),
],
)
def test_is_inline_ignored(error_code, physical_line, expected_result):
"""Verify that we detect inline usage of ``# noqa``."""
error = style_guide.Violation(
error_code, 'filename.py', 1, 1, 'error text', None)
error_code, "filename.py", 1, 1, "error text", None
)
# We want `None` to be passed as the physical line so we actually use our
# monkey-patched linecache.getline value.
with mock.patch('linecache.getline', return_value=physical_line):
with mock.patch("linecache.getline", return_value=physical_line):
assert error.is_inline_ignored(False) is expected_result
def test_disable_is_inline_ignored():
"""Verify that is_inline_ignored exits immediately if disabling NoQA."""
error = style_guide.Violation(
'E121', 'filename.py', 1, 1, 'error text', 'line')
"E121", "filename.py", 1, 1, "error text", "line"
)
with mock.patch('linecache.getline') as getline:
with mock.patch("linecache.getline") as getline:
assert error.is_inline_ignored(True) is False
assert getline.called is False
@pytest.mark.parametrize('violation_file,violation_line,diff,expected', [
('file.py', 10, {}, True),
('file.py', 1, {'file.py': range(1, 2)}, True),
('file.py', 10, {'file.py': range(1, 2)}, False),
('file.py', 1, {'other.py': range(1, 2)}, False),
('file.py', 10, {'other.py': range(1, 2)}, False),
])
@pytest.mark.parametrize(
"violation_file,violation_line,diff,expected",
[
("file.py", 10, {}, True),
("file.py", 1, {"file.py": range(1, 2)}, True),
("file.py", 10, {"file.py": range(1, 2)}, False),
("file.py", 1, {"other.py": range(1, 2)}, False),
("file.py", 10, {"other.py": range(1, 2)}, False),
],
)
def test_violation_is_in_diff(violation_file, violation_line, diff, expected):
"""Verify that we find violations within a diff."""
violation = style_guide.Violation(
'E001', violation_file, violation_line, 1, 'warning', 'line',
"E001",
violation_file,
violation_line,
1,
"warning",
"line",
)
assert violation.is_in(diff) is expected