Merge pull request #1319 from PyCQA/format_tests

extend black formatting to tests as well
This commit is contained in:
Anthony Sottile 2021-04-18 09:27:41 -07:00 committed by GitHub
commit 645cd71f57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 1644 additions and 1307 deletions

View file

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

View file

@ -16,45 +16,45 @@ import sys
# If extensions (or modules to document with autodoc) are in another directory, # If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the # add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here. # documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.')) # sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------ # -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here. # 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 # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones. # ones.
extensions = [ extensions = [
'sphinx.ext.autodoc', "sphinx.ext.autodoc",
'sphinx.ext.doctest', "sphinx.ext.doctest",
'sphinx.ext.extlinks', "sphinx.ext.extlinks",
'sphinx.ext.intersphinx', "sphinx.ext.intersphinx",
'sphinx.ext.todo', "sphinx.ext.todo",
'sphinx.ext.coverage', "sphinx.ext.coverage",
'sphinx.ext.viewcode', "sphinx.ext.viewcode",
'sphinx-prompt', "sphinx-prompt",
] ]
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates'] templates_path = ["_templates"]
# The suffix(es) of source filenames. # The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string: # You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md'] # source_suffix = ['.rst', '.md']
source_suffix = '.rst' source_suffix = ".rst"
# The encoding of source files. # The encoding of source files.
#source_encoding = 'utf-8-sig' # source_encoding = 'utf-8-sig'
# The master toctree document. # The master toctree document.
master_doc = 'index' master_doc = "index"
# General information about the project. # General information about the project.
project = 'flake8' project = "flake8"
copyright = '2016, Ian Stapleton Cordasco' copyright = "2016, Ian Stapleton Cordasco"
author = 'Ian Stapleton Cordasco' author = "Ian Stapleton Cordasco"
import flake8 import flake8
@ -80,9 +80,9 @@ language = None
# There are two options for replacing |today|: either, you set today to some # There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used: # non-false value, then it is used:
#today = '' # today = ''
# Else, today_fmt is used as the format for a strftime call. # Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y' # today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
@ -90,27 +90,27 @@ exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for all # The reST default role (used for this markup: `text`) to use for all
# documents. # documents.
#default_role = None # default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text. # If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True # add_function_parentheses = True
# If true, the current module name will be prepended to all description # If true, the current module name will be prepended to all description
# unit titles (such as .. function::). # unit titles (such as .. function::).
#add_module_names = True # add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the # If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default. # output. They are ignored by default.
#show_authors = False # show_authors = False
# The name of the Pygments (syntax highlighting) style to use. # 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. # A list of ignored prefixes for module index sorting.
#modindex_common_prefix = [] # modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents. # If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False # keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing. # If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True todo_include_todos = True
@ -120,31 +120,31 @@ todo_include_todos = True
# The theme to use for HTML and HTML Help pages. See the documentation for # The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes. # 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 # 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 # further. For a list of options available for each theme, see the
# documentation. # documentation.
#html_theme_options = {} # html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory. # Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = [] # html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to # The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation". # "<project> v<release> documentation".
#html_title = None # html_title = None
# A shorter title for the navigation bar. Default is the same as html_title. # A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None # html_short_title = None
# The name of an image file (relative to this directory) to place at the top # The name of an image file (relative to this directory) to place at the top
# of the sidebar. # of the sidebar.
#html_logo = None # html_logo = None
# The name of an image file (within the static path) to use as favicon of the # The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large. # pixels large.
#html_favicon = None # html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here, # Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files, # relative to this directory. They are copied after the builtin static files,
@ -154,109 +154,111 @@ html_theme = 'sphinx_rtd_theme'
# Add any extra paths that contain custom files (such as robots.txt or # Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied # .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation. # directly to the root of the documentation.
#html_extra_path = [] # html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format. # using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y' # html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to # If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities. # typographically correct entities.
#html_use_smartypants = True # html_use_smartypants = True
# Custom sidebar templates, maps document names to template names. # Custom sidebar templates, maps document names to template names.
#html_sidebars = {} # html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to # Additional templates that should be rendered to pages, maps page names to
# template names. # template names.
#html_additional_pages = {} # html_additional_pages = {}
# If false, no module index is generated. # If false, no module index is generated.
#html_domain_indices = True # html_domain_indices = True
# If false, no index is generated. # If false, no index is generated.
#html_use_index = True # html_use_index = True
# If true, the index is split into individual pages for each letter. # If true, the index is split into individual pages for each letter.
#html_split_index = False # html_split_index = False
# If true, links to the reST sources are added to the pages. # If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True # html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True # html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True # html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will # If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the # contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served. # base URL from which the finished HTML is served.
#html_use_opensearch = '' # html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml"). # This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None # html_file_suffix = None
# Language to be used for generating the HTML full-text search index. # Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages: # Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en' # html_search_language = 'en'
# A dictionary with options for the search language support, empty by default. # A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value # Now only 'ja' uses this config value
#html_search_options = {'type': 'default'} # html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that # The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used. # implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js' # html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'flake8doc' htmlhelp_basename = "flake8doc"
# -- Options for LaTeX output --------------------------------------------- # -- Options for LaTeX output ---------------------------------------------
latex_elements = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper', #'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
# The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt',
#'pointsize': '10pt', # Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble. # Latex figure (float) alignment
#'preamble': '', #'figure_align': 'htbp',
# Latex figure (float) alignment
#'figure_align': 'htbp',
} }
# Grouping the document tree into LaTeX files. List of tuples # Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, # (source start file, target name, title,
# author, documentclass [howto, manual, or own class]). # author, documentclass [howto, manual, or own class]).
latex_documents = [ 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 # The name of an image file (relative to this directory) to place at the top of
# the title page. # the title page.
#latex_logo = None # latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts, # For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters. # not chapters.
#latex_use_parts = False # latex_use_parts = False
# If true, show page references after internal links. # If true, show page references after internal links.
#latex_show_pagerefs = False # latex_show_pagerefs = False
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
#latex_show_urls = False # latex_show_urls = False
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#latex_appendices = [] # latex_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#latex_domain_indices = True # latex_domain_indices = True
# -- Options for manual page output --------------------------------------- # -- Options for manual page output ---------------------------------------
@ -264,12 +266,11 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
('manpage', 'flake8', 'Flake8 Command Line Documentation', ("manpage", "flake8", "Flake8 Command Line Documentation", [author], 1)
[author], 1)
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
#man_show_urls = False # man_show_urls = False
# -- Options for Texinfo output ------------------------------------------- # -- Options for Texinfo output -------------------------------------------
@ -278,26 +279,32 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
('index', 'Flake8', 'Flake8 Documentation', 'Tarek Ziade', (
'Flake8', 'Code checking using pycodestyle, pyflakes and mccabe', "index",
'Miscellaneous'), "Flake8",
"Flake8 Documentation",
"Tarek Ziade",
"Flake8",
"Code checking using pycodestyle, pyflakes and mccabe",
"Miscellaneous",
),
] ]
# Documents to append as an appendix to all manuals. # Documents to append as an appendix to all manuals.
#texinfo_appendices = [] # texinfo_appendices = []
# If false, no module index is generated. # If false, no module index is generated.
#texinfo_domain_indices = True # texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'. # How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote' # texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu. # If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False # texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library. # 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 = { extlinks = {
"issue": ("https://github.com/pycqa/flake8/issues/%s", "#"), "issue": ("https://github.com/pycqa/flake8/issues/%s", "#"),

View file

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

View file

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

View file

@ -3,8 +3,9 @@
class ExampleTwo: class ExampleTwo:
"""Second Example Plugin.""" """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 off_by_default = True
@ -13,5 +14,9 @@ class ExampleTwo:
def run(self): def run(self):
"""Do nothing.""" """Do nothing."""
yield (1, 0, 'X200 The off-by-default plugin was enabled', yield (
'OffByDefaultPlugin') 1,
0,
"X200 The off-by-default plugin was enabled",
"OffByDefaultPlugin",
)

View file

@ -3,8 +3,9 @@
class ExampleOne: class ExampleOne:
"""First Example Plugin.""" """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): def __init__(self, tree):
self.tree = tree self.tree = tree

View file

@ -4,6 +4,6 @@ import sys
import setuptools 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() setuptools.setup()

View file

@ -17,9 +17,7 @@ LOG = logging.getLogger(__name__)
LOG.addHandler(logging.NullHandler()) LOG.addHandler(logging.NullHandler())
__version__ = "3.9.1" __version__ = "3.9.1"
__version_info__ = tuple( __version_info__ = tuple(int(i) for i in __version__.split(".") if i.isdigit())
int(i) for i in __version__.split(".") if i.isdigit()
)
# There is nothing lower than logging.DEBUG (10) in the logging library, # 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 results_reported = results_found = 0
for checker in self._all_checkers: for checker in self._all_checkers:
results = sorted( results = sorted(checker.results, key=lambda tup: (tup[1], tup[2]))
checker.results, key=lambda tup: (tup[1], tup[2])
)
filename = checker.display_name filename = checker.display_name
with self.style_guide.processing_file(filename): with self.style_guide.processing_file(filename):
results_reported += self._handle_results(filename, results) results_reported += self._handle_results(filename, results)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,4 +3,4 @@ import sys
import flake8 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: class ExtensionTestPlugin2:
"""Extension test plugin in its own directory.""" """Extension test plugin in its own directory."""
name = 'ExtensionTestPlugin2' name = "ExtensionTestPlugin2"
version = '1.0.0' version = "1.0.0"
def __init__(self, tree): def __init__(self, tree):
"""Construct an instance of test plugin.""" """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 config
from flake8.options import manager 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 @pytest.fixture
@ -18,8 +18,8 @@ def optmanager():
prelim_parser = argparse.ArgumentParser(add_help=False) prelim_parser = argparse.ArgumentParser(add_help=False)
options.register_preliminary_options(prelim_parser) options.register_preliminary_options(prelim_parser)
option_manager = manager.OptionManager( option_manager = manager.OptionManager(
prog='flake8', prog="flake8",
version='3.0.0', version="3.0.0",
parents=[prelim_parser], parents=[prelim_parser],
) )
options.register_default_options(option_manager) options.register_default_options(option_manager)
@ -28,31 +28,50 @@ def optmanager():
def test_aggregate_options_with_config(optmanager): def test_aggregate_options_with_config(optmanager):
"""Verify we aggregate options and config values appropriately.""" """Verify we aggregate options and config values appropriately."""
arguments = ['flake8', '--select', arguments = [
'E11,E34,E402,W,F', '--exclude', 'tests/*'] "flake8",
"--select",
"E11,E34,E402,W,F",
"--exclude",
"tests/*",
]
config_finder = config.ConfigFileFinder( config_finder = config.ConfigFileFinder(
'flake8', "flake8", config_file=CLI_SPECIFIED_CONFIG
config_file=CLI_SPECIFIED_CONFIG) )
options, args = aggregator.aggregate_options( options, args = aggregator.aggregate_options(
optmanager, config_finder, arguments) optmanager, config_finder, arguments
)
assert options.select == ['E11', 'E34', 'E402', 'W', 'F'] assert options.select == ["E11", "E34", "E402", "W", "F"]
assert options.ignore == ['E123', 'W234', 'E111'] assert options.ignore == ["E123", "W234", "E111"]
assert options.exclude == [os.path.abspath('tests/*')] assert options.exclude == [os.path.abspath("tests/*")]
def test_aggregate_options_when_isolated(optmanager): def test_aggregate_options_when_isolated(optmanager):
"""Verify we aggregate options and config values appropriately.""" """Verify we aggregate options and config values appropriately."""
arguments = ['flake8', '--select', 'E11,E34,E402,W,F', arguments = [
'--exclude', 'tests/*'] "flake8",
config_finder = config.ConfigFileFinder( "--select",
'flake8', ignore_config_files=True) "E11,E34,E402,W,F",
optmanager.extend_default_ignore(['E8']) "--exclude",
options, args = aggregator.aggregate_options( "tests/*",
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/*')] 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): def test_legacy_api(tmpdir):
"""A basic end-to-end test for the legacy api reporting errors.""" """A basic end-to-end test for the legacy api reporting errors."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
t_py = tmpdir.join('t.py') t_py = tmpdir.join("t.py")
t_py.write('import os # unused import\n') t_py.write("import os # unused import\n")
style_guide = legacy.get_style_guide() style_guide = legacy.get_style_guide()
report = style_guide.check_files([t_py.strpath]) report = style_guide.check_files([t_py.strpath])

View file

@ -10,13 +10,13 @@ from flake8.processor import FileProcessor
PHYSICAL_LINE = "# Physical line content" PHYSICAL_LINE = "# Physical line content"
EXPECTED_REPORT = (1, 1, 'T000 Expected Message') EXPECTED_REPORT = (1, 1, "T000 Expected Message")
EXPECTED_REPORT_PHYSICAL_LINE = (1, 'T000 Expected Message') EXPECTED_REPORT_PHYSICAL_LINE = (1, "T000 Expected Message")
EXPECTED_RESULT_PHYSICAL_LINE = ( EXPECTED_RESULT_PHYSICAL_LINE = (
'T000', "T000",
0, 0,
1, 1,
'Expected Message', "Expected Message",
None, None,
) )
@ -24,8 +24,8 @@ EXPECTED_RESULT_PHYSICAL_LINE = (
class PluginClass: class PluginClass:
"""Simple file plugin class yielding the expected report.""" """Simple file plugin class yielding the expected report."""
name = 'test' name = "test"
version = '1.0.0' version = "1.0.0"
def __init__(self, tree): def __init__(self, tree):
"""Construct a dummy object to provide mandatory parameter.""" """Construct a dummy object to provide mandatory parameter."""
@ -33,26 +33,26 @@ class PluginClass:
def run(self): def run(self):
"""Run class yielding one element containing the expected report.""" """Run class yielding one element containing the expected report."""
yield EXPECTED_REPORT + (type(self), ) yield EXPECTED_REPORT + (type(self),)
def plugin_func(func): def plugin_func(func):
"""Decorate file plugins which are implemented as functions.""" """Decorate file plugins which are implemented as functions."""
func.name = 'test' func.name = "test"
func.version = '1.0.0' func.version = "1.0.0"
return func return func
@plugin_func @plugin_func
def plugin_func_gen(tree): def plugin_func_gen(tree):
"""Yield the expected report.""" """Yield the expected report."""
yield EXPECTED_REPORT + (type(plugin_func_gen), ) yield EXPECTED_REPORT + (type(plugin_func_gen),)
@plugin_func @plugin_func
def plugin_func_list(tree): def plugin_func_list(tree):
"""Return a list of expected reports.""" """Return a list of expected reports."""
return [EXPECTED_REPORT + (type(plugin_func_list), )] return [EXPECTED_REPORT + (type(plugin_func_list),)]
@plugin_func @plugin_func
@ -98,35 +98,37 @@ def mock_file_checker_with_plugin(plugin_target):
Useful as a starting point for mocking reports/results. Useful as a starting point for mocking reports/results.
""" """
# Mock an entry point returning the plugin target # 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.name = plugin_target.name
entry_point.load.return_value = plugin_target 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 # Load the checker plugins using the entry point mock
with mock.patch.object( with mock.patch.object(
importlib_metadata, importlib_metadata,
'entry_points', "entry_points",
return_value={'flake8.extension': [entry_point]}, return_value={"flake8.extension": [entry_point]},
): ):
checks = manager.Checkers() checks = manager.Checkers()
# Prevent it from reading lines from stdin or somewhere else # Prevent it from reading lines from stdin or somewhere else
with mock.patch('flake8.processor.FileProcessor.read_lines', with mock.patch(
return_value=['Line 1']): "flake8.processor.FileProcessor.read_lines", return_value=["Line 1"]
):
file_checker = checker.FileChecker( file_checker = checker.FileChecker(
'-', "-", checks.to_dictionary(), mock.MagicMock()
checks.to_dictionary(),
mock.MagicMock()
) )
return file_checker return file_checker
@pytest.mark.parametrize('plugin_target', [ @pytest.mark.parametrize(
PluginClass, "plugin_target",
plugin_func_gen, [
plugin_func_list, PluginClass,
]) plugin_func_gen,
plugin_func_list,
],
)
def test_handle_file_plugins(plugin_target): def test_handle_file_plugins(plugin_target):
"""Test the FileChecker class handling different file plugin types.""" """Test the FileChecker class handling different file plugin types."""
file_checker = mock_file_checker_with_plugin(plugin_target) file_checker = mock_file_checker_with_plugin(plugin_target)
@ -138,20 +140,25 @@ def test_handle_file_plugins(plugin_target):
report = mock.Mock() report = mock.Mock()
file_checker.report = report file_checker.report = report
file_checker.run_ast_checks() file_checker.run_ast_checks()
report.assert_called_once_with(error_code=None, report.assert_called_once_with(
line_number=EXPECTED_REPORT[0], error_code=None,
column=EXPECTED_REPORT[1], line_number=EXPECTED_REPORT[0],
text=EXPECTED_REPORT[2]) column=EXPECTED_REPORT[1],
text=EXPECTED_REPORT[2],
)
@pytest.mark.parametrize('plugin_target,len_results', [ @pytest.mark.parametrize(
(plugin_func_physical_ret, 1), "plugin_target,len_results",
(plugin_func_physical_none, 0), [
(plugin_func_physical_list_single, 1), (plugin_func_physical_ret, 1),
(plugin_func_physical_list_multiple, 2), (plugin_func_physical_none, 0),
(plugin_func_physical_gen_single, 1), (plugin_func_physical_list_single, 1),
(plugin_func_physical_gen_multiple, 3), (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): def test_line_check_results(plugin_target, len_results):
"""Test the FileChecker class handling results from line checks.""" """Test the FileChecker class handling results from line checks."""
file_checker = mock_file_checker_with_plugin(plugin_target) file_checker = mock_file_checker_with_plugin(plugin_target)
@ -167,54 +174,100 @@ def test_logical_line_offset_out_of_bounds():
@plugin_func @plugin_func
def _logical_line_out_of_bounds(logical_line): 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) file_checker = mock_file_checker_with_plugin(_logical_line_out_of_bounds)
logical_ret = ( logical_ret = (
'', "",
'print("xxxxxxxxxxx")', 'print("xxxxxxxxxxx")',
[(0, (1, 0)), (5, (1, 5)), (6, (1, 6)), (19, (1, 19)), (20, (1, 20))], [(0, (1, 0)), (5, (1, 5)), (6, (1, 6)), (19, (1, 19)), (20, (1, 20))],
) )
with mock.patch.object( 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() 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' PLACEHOLDER_CODE = 'some_line = "of" * code'
@pytest.mark.parametrize('results, expected_order', [ @pytest.mark.parametrize(
# No entries should be added "results, expected_order",
([], []), [
# Results are correctly ordered # No entries should be added
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE), ([], []),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1]), # Results are correctly ordered
# Reversed order of lines (
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE), [
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0]), ("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
# Columns are not ordered correctly (when reports are ordered correctly) ("A101", 2, 1, "placeholder error", PLACEHOLDER_CODE),
([('A101', 1, 2, 'placeholder error', PLACEHOLDER_CODE), ],
('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE), [0, 1],
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [1, 0, 2]), ),
([('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE), # Reversed order of lines
('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, 1, "placeholder error", PLACEHOLDER_CODE),
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE), ("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
('A101', 2, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 2, 1]), ],
([('A101', 1, 3, 'placeholder error', PLACEHOLDER_CODE), [1, 0],
('A101', 2, 2, 'placeholder error', PLACEHOLDER_CODE), ),
('A101', 3, 1, 'placeholder error', PLACEHOLDER_CODE)], [0, 1, 2]), # Columns are not ordered correctly
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE), # (when reports are ordered correctly)
('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, 2, "placeholder error", PLACEHOLDER_CODE),
([('A101', 1, 1, 'placeholder error', PLACEHOLDER_CODE), ("A101", 1, 1, "placeholder error", PLACEHOLDER_CODE),
('A101', 2, 1, 'charlie error', PLACEHOLDER_CODE)], [0, 1]), ("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],
),
],
)
def test_report_order(results, expected_order): def test_report_order(results, expected_order):
""" """
Test in which order the results will be reported. 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 It gets a list of reports from the file checkers and verifies that the
result will be ordered independent from the original report. result will be ordered independent from the original report.
""" """
def count_side_effect(name, sorted_results): def count_side_effect(name, sorted_results):
"""Side effect for the result handler to tell all are reported.""" """Side effect for the result handler to tell all are reported."""
return len(sorted_results) 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 # tuples to create the expected result lists from the indexes
expected_results = [results[index] for index in expected_order] 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.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 # Create a placeholder manager without arguments or plugins
# Just add one custom file checker which just provides the results # 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 # _handle_results is the first place which gets the sorted result
# Should something non-private be mocked instead? # Should something non-private be mocked instead?
handler = mock.Mock(side_effect=count_side_effect) 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)) 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(): 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): def test_diff_option(tmpdir, capsys):
"""Ensure that `flake8 --diff` works.""" """Ensure that `flake8 --diff` works."""
t_py_contents = '''\ t_py_contents = """\
import os import os
import sys # unused but not part of diff 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')) print(os.path.join('foo', 'bar'))
y # part of the diff and an error y # part of the diff and an error
''' """
diff = '''\ diff = """\
diff --git a/t.py b/t.py diff --git a/t.py b/t.py
index d64ac39..7d943de 100644 index d64ac39..7d943de 100644
--- a/t.py --- a/t.py
@ -39,39 +39,39 @@ index d64ac39..7d943de 100644
print(os.path.join('foo', 'bar')) print(os.path.join('foo', 'bar'))
+ +
+y # part of the diff and an error +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(): with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_contents) tmpdir.join("t.py").write(t_py_contents)
_call_main(['--diff'], retv=1) _call_main(["--diff"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == "t.py:8:1: F821 undefined name 'y'\n" assert out == "t.py:8:1: F821 undefined name 'y'\n"
assert err == '' assert err == ""
def test_form_feed_line_split(tmpdir, capsys): def test_form_feed_line_split(tmpdir, capsys):
"""Test that form feed is treated the same for stdin.""" """Test that form feed is treated the same for stdin."""
src = 'x=1\n\f\ny=1\n' src = "x=1\n\f\ny=1\n"
expected_out = '''\ expected_out = """\
t.py:1:2: E225 missing whitespace around operator t.py:1:2: E225 missing whitespace around operator
t.py:3:2: E225 missing whitespace around operator t.py:3:2: E225 missing whitespace around operator
''' """
with tmpdir.as_cwd(): 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): with mock.patch.object(utils, "stdin_get_value", return_value=src):
_call_main(['-', '--stdin-display-name=t.py'], retv=1) _call_main(["-", "--stdin-display-name=t.py"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == expected_out assert out == expected_out
assert err == '' assert err == ""
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == expected_out assert out == expected_out
assert err == '' assert err == ""
def test_e101_indent_char_does_not_reset(tmpdir, capsys): def test_e101_indent_char_does_not_reset(tmpdir, capsys):
@ -89,82 +89,79 @@ if True:
""" """
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_contents) tmpdir.join("t.py").write(t_py_contents)
_call_main(['t.py']) _call_main(["t.py"])
def test_statistics_option(tmpdir, capsys): def test_statistics_option(tmpdir, capsys):
"""Ensure that `flake8 --statistics` works.""" """Ensure that `flake8 --statistics` works."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write('import os\nimport sys\n') tmpdir.join("t.py").write("import os\nimport sys\n")
_call_main(['--statistics', 't.py'], retv=1) _call_main(["--statistics", "t.py"], retv=1)
out, err = capsys.readouterr() expected = """\
assert out == '''\
t.py:1:1: F401 'os' imported but unused t.py:1:1: F401 'os' imported but unused
t.py:2:1: F401 'sys' imported but unused t.py:2:1: F401 'sys' imported but unused
2 F401 'os' 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): def test_show_source_option(tmpdir, capsys):
"""Ensure that --show-source and --no-show-source work.""" """Ensure that --show-source and --no-show-source work."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('tox.ini').write('[flake8]\nshow_source = true\n') tmpdir.join("tox.ini").write("[flake8]\nshow_source = true\n")
tmpdir.join('t.py').write('import os\n') tmpdir.join("t.py").write("import os\n")
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() expected = """\
assert out == '''\
t.py:1:1: F401 'os' imported but unused t.py:1:1: F401 'os' imported but unused
import os import os
^ ^
''' """
assert err == '' out, err = capsys.readouterr()
assert out == expected
assert err == ""
with tmpdir.as_cwd(): 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() expected = """\
assert out == '''\
t.py:1:1: F401 'os' imported but unused 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): def test_extend_exclude(tmpdir, capsys):
"""Ensure that `flake8 --extend-exclude` works.""" """Ensure that `flake8 --extend-exclude` works."""
for d in ['project', 'vendor', 'legacy', '.git', '.tox', '.hg']: for d in ["project", "vendor", "legacy", ".git", ".tox", ".hg"]:
tmpdir.mkdir(d).join('t.py').write('import os\nimport sys\n') tmpdir.mkdir(d).join("t.py").write("import os\nimport sys\n")
with tmpdir.as_cwd(): with tmpdir.as_cwd():
_call_main(['--extend-exclude=vendor,legacy/'], retv=1) _call_main(["--extend-exclude=vendor,legacy/"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
expected_out = '''\ expected_out = """\
./project/t.py:1:1: F401 'os' imported but unused ./project/t.py:1:1: F401 'os' imported but unused
./project/t.py:2:1: F401 'sys' imported but unused ./project/t.py:2:1: F401 'sys' imported but unused
''' """
assert out == expected_out.replace('/', os.sep) assert out == expected_out.replace("/", os.sep)
assert err == '' assert err == ""
def test_malformed_per_file_ignores_error(tmpdir, capsys): def test_malformed_per_file_ignores_error(tmpdir, capsys):
"""Test the error message for malformed `per-file-ignores`.""" """Test the error message for malformed `per-file-ignores`."""
setup_cfg = '''\ setup_cfg = """\
[flake8] [flake8]
per-file-ignores = per-file-ignores =
incorrect/* incorrect/*
values/* values/*
''' """
expected = """\
with tmpdir.as_cwd():
tmpdir.join('setup.cfg').write(setup_cfg)
_call_main(['.'], retv=1)
out, err = capsys.readouterr()
assert out == '''\
There was a critical error during execution of Flake8: There was a critical error during execution of Flake8:
Expected `per-file-ignores` to be a mapping from file exclude patterns to ignore codes. 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/* incorrect/*
values/* 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): def test_tokenization_error_but_not_syntax_error(tmpdir, capsys):
"""Test that flake8 does not crash on tokenization errors.""" """Test that flake8 does not crash on tokenization errors."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
# this is a crash in the tokenizer, but not in the ast # this is a crash in the tokenizer, but not in the ast
tmpdir.join('t.py').write("b'foo' \\\n") tmpdir.join("t.py").write("b'foo' \\\n")
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == 't.py:1:1: E902 TokenError: EOF in multi-line statement\n' assert out == "t.py:1:1: E902 TokenError: EOF in multi-line statement\n"
assert err == '' assert err == ""
def test_tokenization_error_is_a_syntax_error(tmpdir, capsys): def test_tokenization_error_is_a_syntax_error(tmpdir, capsys):
"""Test when tokenize raises a SyntaxError.""" """Test when tokenize raises a SyntaxError."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write('if True:\n pass\n pass\n') tmpdir.join("t.py").write("if True:\n pass\n pass\n")
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == 't.py:1:1: E902 IndentationError: unindent does not match any outer indentation level\n' # noqa: E501 expected = "t.py:1:1: E902 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
assert err == '' assert out == expected
assert err == ""
def test_bug_report_successful(capsys): def test_bug_report_successful(capsys):
"""Test that --bug-report does not crash.""" """Test that --bug-report does not crash."""
_call_main(['--bug-report']) _call_main(["--bug-report"])
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert json.loads(out) assert json.loads(out)
assert err == '' assert err == ""
def test_specific_noqa_does_not_clobber_pycodestyle_noqa(tmpdir, capsys): def test_specific_noqa_does_not_clobber_pycodestyle_noqa(tmpdir, capsys):
"""See https://github.com/pycqa/flake8/issues/1104.""" """See https://github.com/pycqa/flake8/issues/1104."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write("test = ('ABC' == None) # noqa: E501\n") tmpdir.join("t.py").write("test = ('ABC' == None) # noqa: E501\n")
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() expected = """\
assert out == '''\
t.py:1:15: E711 comparison to None should be 'if cond is None:' 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): def test_specific_noqa_on_line_with_continuation(tmpdir, capsys):
@ -230,60 +236,64 @@ x = """
''' '''
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(['t.py'], retv=0) _call_main(["t.py"], retv=0)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == err == '' assert out == err == ""
def test_physical_line_file_not_ending_in_newline(tmpdir, capsys): def test_physical_line_file_not_ending_in_newline(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960.""" """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(): with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() expected = """\
assert out == '''\
t.py:2:1: W191 indentation contains tabs t.py:2:1: W191 indentation contains tabs
t.py:2:6: W292 no newline at end of file 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): def test_physical_line_file_not_ending_in_newline_trailing_ws(tmpdir, capsys):
"""See https://github.com/PyCQA/pycodestyle/issues/960.""" """See https://github.com/PyCQA/pycodestyle/issues/960."""
t_py_src = 'x = 1 ' t_py_src = "x = 1 "
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join('t.py').write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(['t.py'], retv=1) _call_main(["t.py"], retv=1)
out, err = capsys.readouterr() expected = """\
assert out == '''\
t.py:1:6: W291 trailing whitespace t.py:1:6: W291 trailing whitespace
t.py:1:9: W292 no newline at end of file 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): def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys):
"""Test that arguments are obtained from 'sys.argv'.""" """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) _call_main(None)
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out.startswith('usage: flake8 [options] file file ...\n') assert out.startswith("usage: flake8 [options] file file ...\n")
assert err == '' assert err == ""
def test_cli_config_option_respected(tmp_path): def test_cli_config_option_respected(tmp_path):
"""Test --config is used.""" """Test --config is used."""
config = tmp_path / "flake8.ini" config = tmp_path / "flake8.ini"
config.write_text("""\ config.write_text(
"""\
[flake8] [flake8]
ignore = F401 ignore = F401
""") """
)
py_file = tmp_path / "t.py" py_file = tmp_path / "t.py"
py_file.write_text("import os\n") py_file.write_text("import os\n")
@ -294,10 +304,12 @@ ignore = F401
def test_cli_isolated_overrides_config_option(tmp_path): def test_cli_isolated_overrides_config_option(tmp_path):
"""Test --isolated overrides --config.""" """Test --isolated overrides --config."""
config = tmp_path / "flake8.ini" config = tmp_path / "flake8.ini"
config.write_text("""\ config.write_text(
"""\
[flake8] [flake8]
ignore = F401 ignore = F401
""") """
)
py_file = tmp_path / "t.py" py_file = tmp_path / "t.py"
py_file.write_text("import os\n") py_file.write_text("import os\n")
@ -316,13 +328,13 @@ def test_file_not_found(tmpdir, capsys):
def test_output_file(tmpdir, capsys): def test_output_file(tmpdir, capsys):
"""Ensure that --output-file is honored.""" """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(): 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() out, err = capsys.readouterr()
assert out == err == "" assert out == err == ""
expected = "t.py:1:1: F401 'os' imported but unused\n" 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.""" """Integration tests for plugin loading."""
from flake8.main import application from flake8.main import application
LOCAL_PLUGIN_CONFIG = 'tests/fixtures/config_files/local-plugin.ini' LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.ini"
LOCAL_PLUGIN_PATH_CONFIG = 'tests/fixtures/config_files/local-plugin-path.ini' LOCAL_PLUGIN_PATH_CONFIG = "tests/fixtures/config_files/local-plugin-path.ini"
class ExtensionTestPlugin: class ExtensionTestPlugin:
"""Extension test plugin.""" """Extension test plugin."""
name = 'ExtensionTestPlugin' name = "ExtensionTestPlugin"
version = '1.0.0' version = "1.0.0"
def __init__(self, tree): def __init__(self, tree):
"""Construct an instance of test plugin.""" """Construct an instance of test plugin."""
@ -20,14 +20,14 @@ class ExtensionTestPlugin:
@classmethod @classmethod
def add_options(cls, parser): def add_options(cls, parser):
"""Register options.""" """Register options."""
parser.add_option('--anopt') parser.add_option("--anopt")
class ReportTestPlugin: class ReportTestPlugin:
"""Report test plugin.""" """Report test plugin."""
name = 'ReportTestPlugin' name = "ReportTestPlugin"
version = '1.0.0' version = "1.0.0"
def __init__(self, tree): def __init__(self, tree):
"""Construct an instance of test plugin.""" """Construct an instance of test plugin."""
@ -39,28 +39,29 @@ class ReportTestPlugin:
def test_enable_local_plugin_from_config(): def test_enable_local_plugin_from_config():
"""App can load a local plugin from config file.""" """App can load a local plugin from config file."""
app = application.Application() 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 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 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(): def test_local_plugin_can_add_option():
"""A local plugin can add a CLI option.""" """A local plugin can add a CLI option."""
app = application.Application() app = application.Application()
app.initialize( 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 is not None
assert app.options.anopt == 'foo' assert app.options.anopt == "foo"
def test_enable_local_plugin_at_non_installed_path(): def test_enable_local_plugin_at_non_installed_path():
"""Can add a paths option in local-plugins config section for finding.""" """Can add a paths option in local-plugins config section for finding."""
app = application.Application() 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 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): def options_from(**kwargs):
"""Generate a Values instances with our kwargs.""" """Generate a Values instances with our kwargs."""
kwargs.setdefault('hang_closing', True) kwargs.setdefault("hang_closing", True)
kwargs.setdefault('max_line_length', 79) kwargs.setdefault("max_line_length", 79)
kwargs.setdefault('max_doc_length', None) kwargs.setdefault("max_doc_length", None)
kwargs.setdefault('indent_size', 4) kwargs.setdefault("indent_size", 4)
kwargs.setdefault('verbose', False) kwargs.setdefault("verbose", False)
kwargs.setdefault('stdin_display_name', 'stdin') kwargs.setdefault("stdin_display_name", "stdin")
kwargs.setdefault('disable_noqa', False) kwargs.setdefault("disable_noqa", False)
return argparse.Namespace(**kwargs) return argparse.Namespace(**kwargs)

View file

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

View file

@ -10,23 +10,23 @@ from flake8.formatting import base
def options(**kwargs): def options(**kwargs):
"""Create an argparse.Namespace instance.""" """Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None) kwargs.setdefault("output_file", None)
kwargs.setdefault('tee', False) kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs) return argparse.Namespace(**kwargs)
@pytest.mark.parametrize('filename', [None, 'out.txt']) @pytest.mark.parametrize("filename", [None, "out.txt"])
def test_start(filename): def test_start(filename):
"""Verify we open a new file in the start method.""" """Verify we open a new file in the start method."""
mock_open = mock.mock_open() mock_open = mock.mock_open()
formatter = base.BaseFormatter(options(output_file=filename)) 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() formatter.start()
if filename is None: if filename is None:
assert mock_open.called is False assert mock_open.called is False
else: else:
mock_open.assert_called_once_with(filename, 'a') mock_open.assert_called_once_with(filename, "a")
def test_stop(): def test_stop():
@ -45,68 +45,79 @@ def test_format_needs_to_be_implemented():
formatter = base.BaseFormatter(options()) formatter = base.BaseFormatter(options())
with pytest.raises(NotImplementedError): with pytest.raises(NotImplementedError):
formatter.format( 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(): def test_show_source_returns_nothing_when_not_showing_source():
"""Ensure we return nothing when users want nothing.""" """Ensure we return nothing when users want nothing."""
formatter = base.BaseFormatter(options(show_source=False)) formatter = base.BaseFormatter(options(show_source=False))
assert formatter.show_source( assert (
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', 'line') formatter.show_source(
) == '' style_guide.Violation(
"A000", "file.py", 1, 1, "error text", "line"
)
)
== ""
)
def test_show_source_returns_nothing_when_there_is_source(): def test_show_source_returns_nothing_when_there_is_source():
"""Ensure we return nothing when there is no line.""" """Ensure we return nothing when there is no line."""
formatter = base.BaseFormatter(options(show_source=True)) formatter = base.BaseFormatter(options(show_source=True))
assert formatter.show_source( assert (
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', None) 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', [
' ^', (
2, "x=1\n",
), " ^",
( 2,
' x=(1\n +2)\n', ),
' ^', (
5, " x=(1\n +2)\n",
), " ^",
( 5,
'\tx\t=\ty\n', ),
'\t \t \t^', (
6, "\tx\t=\ty\n",
), "\t \t \t^",
]) 6,
),
],
)
def test_show_source_updates_physical_line_appropriately(line1, line2, column): def test_show_source_updates_physical_line_appropriately(line1, line2, column):
"""Ensure the error column is appropriately indicated.""" """Ensure the error column is appropriately indicated."""
formatter = base.BaseFormatter(options(show_source=True)) 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) output = formatter.show_source(error)
assert output == line1 + line2 assert output == line1 + line2
@pytest.mark.parametrize('tee', [False, True]) @pytest.mark.parametrize("tee", [False, True])
def test_write_uses_an_output_file(tee): def test_write_uses_an_output_file(tee):
"""Verify that we use the output file when it's present.""" """Verify that we use the output file when it's present."""
line = 'Something to write' line = "Something to write"
source = 'source' source = "source"
filemock = mock.Mock() filemock = mock.Mock()
formatter = base.BaseFormatter(options(tee=tee)) formatter = base.BaseFormatter(options(tee=tee))
formatter.output_fd = filemock 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) formatter.write(line, source)
if tee: if tee:
assert print_func.called assert print_func.called
assert print_func.mock_calls == [ assert print_func.mock_calls == [
mock.call(line, end='\n'), mock.call(line, end="\n"),
mock.call(source, end='\n'), mock.call(source, end="\n"),
] ]
else: else:
assert not print_func.called 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): def test_write_uses_print(print_function):
"""Verify that we use the print function without an output file.""" """Verify that we use the print function without an output file."""
line = 'Something to write' line = "Something to write"
source = 'source' source = "source"
formatter = base.BaseFormatter(options()) formatter = base.BaseFormatter(options())
formatter.write(line, source) formatter.write(line, source)
@ -131,8 +142,8 @@ def test_write_uses_print(print_function):
assert print_function.called is True assert print_function.called is True
assert print_function.call_count == 2 assert print_function.call_count == 2
assert print_function.mock_calls == [ assert print_function.mock_calls == [
mock.call(line, end='\n'), mock.call(line, end="\n"),
mock.call(source, end='\n'), mock.call(source, end="\n"),
] ]
@ -163,14 +174,14 @@ def test_handle_formats_the_error():
formatter = FormatFormatter(options(show_source=False)) formatter = FormatFormatter(options(show_source=False))
filemock = formatter.output_fd = mock.Mock() filemock = formatter.output_fd = mock.Mock()
error = style_guide.Violation( error = style_guide.Violation(
code='A001', code="A001",
filename='example.py', filename="example.py",
line_number=1, line_number=1,
column_number=1, column_number=1,
text='Fake error', text="Fake error",
physical_line='a = 1', physical_line="a = 1",
) )
formatter.handle(error) 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(): def style_guide_mock():
"""Create a mock StyleGuide object.""" """Create a mock StyleGuide object."""
return mock.MagicMock(**{ return mock.MagicMock(
'options.diff': False, **{
'options.jobs': JobsArgument("4"), "options.diff": False,
}) "options.jobs": JobsArgument("4"),
}
)
def _parallel_checker_manager(): def _parallel_checker_manager():
@ -27,21 +29,21 @@ def _parallel_checker_manager():
def test_oserrors_cause_serial_fall_back(): def test_oserrors_cause_serial_fall_back():
"""Verify that OSErrors will cause the Manager to fallback to serial.""" """Verify that OSErrors will cause the Manager to fallback to serial."""
err = OSError(errno.ENOSPC, 'Ominous message about spaceeeeee') err = OSError(errno.ENOSPC, "Ominous message about spaceeeeee")
with mock.patch('_multiprocessing.SemLock', side_effect=err): with mock.patch("_multiprocessing.SemLock", side_effect=err):
manager = _parallel_checker_manager() manager = _parallel_checker_manager()
with mock.patch.object(manager, 'run_serial') as serial: with mock.patch.object(manager, "run_serial") as serial:
manager.run() manager.run()
assert serial.call_count == 1 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): def test_oserrors_are_reraised(is_windows):
"""Verify that unexpected OSErrors will cause the Manager to reraise.""" """Verify that unexpected OSErrors will cause the Manager to reraise."""
err = OSError(errno.EAGAIN, 'Ominous message') err = OSError(errno.EAGAIN, "Ominous message")
with mock.patch('_multiprocessing.SemLock', side_effect=err): with mock.patch("_multiprocessing.SemLock", side_effect=err):
manager = _parallel_checker_manager() 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): with pytest.raises(OSError):
manager.run() manager.run()
assert serial.call_count == 0 assert serial.call_count == 0
@ -50,7 +52,7 @@ def test_oserrors_are_reraised(is_windows):
def test_multiprocessing_is_disabled(): def test_multiprocessing_is_disabled():
"""Verify not being able to import multiprocessing forces jobs to 0.""" """Verify not being able to import multiprocessing forces jobs to 0."""
style_guide = style_guide_mock() style_guide = style_guide_mock()
with mock.patch('flake8.checker.multiprocessing', None): with mock.patch("flake8.checker.multiprocessing", None):
manager = checker.Manager(style_guide, [], []) manager = checker.Manager(style_guide, [], [])
assert manager.jobs == 0 assert manager.jobs == 0
@ -58,20 +60,20 @@ def test_multiprocessing_is_disabled():
def test_make_checkers(): def test_make_checkers():
"""Verify that we create a list of FileChecker instances.""" """Verify that we create a list of FileChecker instances."""
style_guide = style_guide_mock() style_guide = style_guide_mock()
files = ['file1', 'file2'] files = ["file1", "file2"]
checkplugins = mock.Mock() checkplugins = mock.Mock()
checkplugins.to_dictionary.return_value = { checkplugins.to_dictionary.return_value = {
'ast_plugins': [], "ast_plugins": [],
'logical_line_plugins': [], "logical_line_plugins": [],
'physical_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) manager = checker.Manager(style_guide, files, checkplugins)
with mock.patch('flake8.utils.filenames_from') as filenames_from: with mock.patch("flake8.utils.filenames_from") as filenames_from:
filenames_from.side_effect = [['file1'], ['file2']] filenames_from.side_effect = [["file1"], ["file2"]]
with mock.patch('flake8.utils.fnmatch', return_value=True): with mock.patch("flake8.utils.fnmatch", return_value=True):
with mock.patch('flake8.processor.FileProcessor'): with mock.patch("flake8.processor.FileProcessor"):
manager.make_checkers() manager.make_checkers()
assert manager._all_checkers assert manager._all_checkers

View file

@ -7,73 +7,93 @@ import pytest
from flake8.options import config from flake8.options import config
CLI_SPECIFIED_FILEPATH = 'tests/fixtures/config_files/cli-specified.ini' CLI_SPECIFIED_FILEPATH = "tests/fixtures/config_files/cli-specified.ini"
BROKEN_CONFIG_PATH = 'tests/fixtures/config_files/broken.ini' BROKEN_CONFIG_PATH = "tests/fixtures/config_files/broken.ini"
def test_cli_config(): def test_cli_config():
"""Verify opening and reading the file specified via the cli.""" """Verify opening and reading the file specified via the cli."""
cli_filepath = CLI_SPECIFIED_FILEPATH cli_filepath = CLI_SPECIFIED_FILEPATH
finder = config.ConfigFileFinder('flake8') finder = config.ConfigFileFinder("flake8")
parsed_config = finder.cli_config(cli_filepath) 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(
# Root directory of project "cwd,expected",
(os.path.abspath('.'), [
[os.path.abspath('setup.cfg'), # Root directory of project
os.path.abspath('tox.ini')]), (
# Subdirectory of project directory os.path.abspath("."),
(os.path.abspath('src'), [os.path.abspath("setup.cfg"), os.path.abspath("tox.ini")],
[os.path.abspath('setup.cfg'), ),
os.path.abspath('tox.ini')]), # Subdirectory of project directory
# Outside of project directory (
(os.path.abspath('/'), os.path.abspath("src"),
[]), [os.path.abspath("setup.cfg"), os.path.abspath("tox.ini")],
]) ),
# Outside of project directory
(os.path.abspath("/"), []),
],
)
def test_generate_possible_local_files(cwd, expected): def test_generate_possible_local_files(cwd, expected):
"""Verify generation of all possible config paths.""" """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()) config_files = list(finder.generate_possible_local_files())
assert config_files == expected assert config_files == expected
@pytest.mark.parametrize('extra_config_files,expected', [ @pytest.mark.parametrize(
# Extra config files specified "extra_config_files,expected",
([CLI_SPECIFIED_FILEPATH], [
[os.path.abspath('setup.cfg'), # Extra config files specified
os.path.abspath('tox.ini'), (
os.path.abspath(CLI_SPECIFIED_FILEPATH)]), [CLI_SPECIFIED_FILEPATH],
# Missing extra config files specified [
([CLI_SPECIFIED_FILEPATH, os.path.abspath("setup.cfg"),
'tests/fixtures/config_files/missing.ini'], os.path.abspath("tox.ini"),
[os.path.abspath('setup.cfg'), os.path.abspath(CLI_SPECIFIED_FILEPATH),
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),
],
),
],
)
def test_local_config_files(extra_config_files, expected): def test_local_config_files(extra_config_files, expected):
"""Verify discovery of local config files.""" """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 assert list(finder.local_config_files()) == expected
def test_local_configs(): def test_local_configs():
"""Verify we return a ConfigParser.""" """Verify we return a ConfigParser."""
finder = config.ConfigFileFinder('flake8') finder = config.ConfigFileFinder("flake8")
assert isinstance(finder.local_configs(), configparser.RawConfigParser) assert isinstance(finder.local_configs(), configparser.RawConfigParser)
@pytest.mark.parametrize('files', [ @pytest.mark.parametrize(
[BROKEN_CONFIG_PATH], "files",
[CLI_SPECIFIED_FILEPATH, BROKEN_CONFIG_PATH], [
]) [BROKEN_CONFIG_PATH],
[CLI_SPECIFIED_FILEPATH, BROKEN_CONFIG_PATH],
],
)
def test_read_config_catches_broken_config_files(files): def test_read_config_catches_broken_config_files(files):
"""Verify that we do not allow the exception to bubble up.""" """Verify that we do not allow the exception to bubble up."""
_, parsed = config.ConfigFileFinder._read_config(*files) _, 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): def test_read_config_catches_decoding_errors(tmpdir):
"""Verify that we do not allow the exception to bubble up.""" """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 # 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) _, parsed = config.ConfigFileFinder._read_config(setup_cfg.strpath)
assert parsed == [] assert parsed == []
def test_config_file_default_value(): def test_config_file_default_value():
"""Verify the default 'config_file' attribute value.""" """Verify the default 'config_file' attribute value."""
finder = config.ConfigFileFinder('flake8') finder = config.ConfigFileFinder("flake8")
assert finder.config_file is None assert finder.config_file is None
def test_setting_config_file_value(): def test_setting_config_file_value():
"""Verify the 'config_file' attribute matches constructed value.""" """Verify the 'config_file' attribute matches constructed value."""
config_file_value = 'flake8.ini' config_file_value = "flake8.ini"
finder = config.ConfigFileFinder('flake8', config_file=config_file_value) finder = config.ConfigFileFinder("flake8", config_file=config_file_value)
assert finder.config_file == config_file_value assert finder.config_file == config_file_value
def test_ignore_config_files_default_value(): def test_ignore_config_files_default_value():
"""Verify the default 'ignore_config_files' attribute value.""" """Verify the default 'ignore_config_files' attribute value."""
finder = config.ConfigFileFinder('flake8') finder = config.ConfigFileFinder("flake8")
assert finder.ignore_config_files is False assert finder.ignore_config_files is False
@pytest.mark.parametrize('ignore_config_files_arg', [ @pytest.mark.parametrize(
False, "ignore_config_files_arg",
True, [
]) False,
True,
],
)
def test_setting_ignore_config_files_value(ignore_config_files_arg): def test_setting_ignore_config_files_value(ignore_config_files_arg):
"""Verify the 'ignore_config_files' attribute matches constructed value.""" """Verify the 'ignore_config_files' attribute matches constructed value."""
finder = config.ConfigFileFinder( finder = config.ConfigFileFinder(
'flake8', "flake8", ignore_config_files=ignore_config_files_arg
ignore_config_files=ignore_config_files_arg
) )
assert finder.ignore_config_files is 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() 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)], [manager.PluginVersion("pycodestyle", "2.0.0", 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), "plugin": "pycodestyle",
manager.PluginVersion('my-local', '0.0.1', True), "version": "2.0.0",
manager.PluginVersion('mccabe', '0.5.9', False)], "is_local": 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),
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): def test_plugins_from(plugins, expected):
"""Test that we format plugins appropriately.""" """Test that we format plugins appropriately."""
option_manager = mock.Mock(registered_plugins=set(plugins)) option_manager = mock.Mock(registered_plugins=set(plugins))
assert expected == debug.plugins_from(option_manager) assert expected == debug.plugins_from(option_manager)
@mock.patch('platform.python_implementation', return_value='CPython') @mock.patch("platform.python_implementation", return_value="CPython")
@mock.patch('platform.python_version', return_value='3.5.3') @mock.patch("platform.python_version", return_value="3.5.3")
@mock.patch('platform.system', return_value='Linux') @mock.patch("platform.system", return_value="Linux")
def test_information(system, pyversion, pyimpl): def test_information(system, pyversion, pyimpl):
"""Verify that we return all the information we care about.""" """Verify that we return all the information we care about."""
expected = { expected = {
'version': '3.1.0', "version": "3.1.0",
'plugins': [{'plugin': 'mccabe', 'version': '0.5.9', "plugins": [
'is_local': False}, {"plugin": "mccabe", "version": "0.5.9", "is_local": False},
{'plugin': 'pycodestyle', 'version': '2.0.0', {"plugin": "pycodestyle", "version": "2.0.0", "is_local": False},
'is_local': False}], ],
'dependencies': [], "dependencies": [],
'platform': { "platform": {
'python_implementation': 'CPython', "python_implementation": "CPython",
'python_version': '3.5.3', "python_version": "3.5.3",
'system': 'Linux', "system": "Linux",
}, },
} }
option_manager = mock.Mock( option_manager = mock.Mock(
registered_plugins={ registered_plugins={
manager.PluginVersion('pycodestyle', '2.0.0', False), manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion('mccabe', '0.5.9', False), manager.PluginVersion("mccabe", "0.5.9", False),
}, },
version='3.1.0', version="3.1.0",
) )
assert expected == debug.information(option_manager) assert expected == debug.information(option_manager)
pyimpl.assert_called_once_with() pyimpl.assert_called_once_with()
@ -64,14 +95,16 @@ def test_information(system, pyversion, pyimpl):
system.assert_called_once_with() system.assert_called_once_with()
@mock.patch('flake8.main.debug.print') @mock.patch("flake8.main.debug.print")
@mock.patch('flake8.main.debug.information', return_value={}) @mock.patch("flake8.main.debug.information", return_value={})
@mock.patch('json.dumps', return_value='{}') @mock.patch("json.dumps", return_value="{}")
def test_print_information_no_plugins(dumps, information, print_mock): def test_print_information_no_plugins(dumps, information, print_mock):
"""Verify we print and exit only when we have plugins.""" """Verify we print and exit only when we have plugins."""
option_manager = mock.Mock(registered_plugins=set()) option_manager = mock.Mock(registered_plugins=set())
action = debug.DebugAction( 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 action(None, None, None, None) is None
assert dumps.called is False 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 assert print_mock.called is False
@mock.patch('flake8.main.debug.print') @mock.patch("flake8.main.debug.print")
@mock.patch('flake8.main.debug.information', return_value={}) @mock.patch("flake8.main.debug.information", return_value={})
@mock.patch('json.dumps', return_value='{}') @mock.patch("json.dumps", return_value="{}")
def test_print_information(dumps, information, print_mock): def test_print_information(dumps, information, print_mock):
"""Verify we print and exit only when we have plugins.""" """Verify we print and exit only when we have plugins."""
plugins = [ plugins = [
manager.PluginVersion('pycodestyle', '2.0.0', False), manager.PluginVersion("pycodestyle", "2.0.0", False),
manager.PluginVersion('mccabe', '0.5.9', False), manager.PluginVersion("mccabe", "0.5.9", False),
] ]
option_manager = mock.Mock(registered_plugins=set(plugins)) option_manager = mock.Mock(registered_plugins=set(plugins))
action = debug.DebugAction( 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): with pytest.raises(SystemExit):
action(None, None, None, None) 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) dumps.assert_called_once_with({}, indent=2, sort_keys=True)
information.assert_called_once_with(option_manager) information.assert_called_once_with(option_manager)

View file

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

View file

@ -7,7 +7,7 @@ import flake8
from flake8 import checker 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 def test_run_ast_checks_handles_SyntaxErrors(FileProcessor): # noqa: N802,N803
"""Stress our SyntaxError handling. """Stress our SyntaxError handling.
@ -15,26 +15,31 @@ def test_run_ast_checks_handles_SyntaxErrors(FileProcessor): # noqa: N802,N803
""" """
processor = mock.Mock(lines=[]) processor = mock.Mock(lines=[])
FileProcessor.return_value = processor FileProcessor.return_value = processor
processor.build_ast.side_effect = SyntaxError('Failed to build ast', processor.build_ast.side_effect = SyntaxError(
('', 1, 5, 'foo(\n')) "Failed to build ast", ("", 1, 5, "foo(\n")
)
file_checker = checker.FileChecker(__file__, checks={}, options=object()) 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() file_checker.run_ast_checks()
report.assert_called_once_with( report.assert_called_once_with(
'E999', 1, 3, "E999",
'SyntaxError: Failed to build ast', 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): def test_repr(*args):
"""Verify we generate a correct repr.""" """Verify we generate a correct repr."""
file_checker = checker.FileChecker( 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(): def test_nonexistent_file():
@ -50,7 +55,7 @@ def test_nonexistent_file():
def test_raises_exception_on_failed_plugin(tmp_path, default_options): def test_raises_exception_on_failed_plugin(tmp_path, default_options):
"""Checks that a failing plugin results in PluginExecutionFailed.""" """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 foobar.write_text("I exist!") # Create temp file
plugin = { plugin = {
"name": "failure", "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""" """Verify a failing plugin results in an plugin error"""
fchecker = checker.FileChecker( fchecker = checker.FileChecker(
str(foobar), checks=[], options=default_options) str(foobar), checks=[], options=default_options
)
with pytest.raises(flake8.exceptions.PluginExecutionFailed): with pytest.raises(flake8.exceptions.PluginExecutionFailed):
fchecker.run_check(plugin) 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): 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 # be careful to write the bytes exactly to avoid newline munging
f.write_binary(contents) f.write_binary(contents)
return processor.FileProcessor(f.strpath, options).lines 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): def test_read_lines_universal_newlines(tmpdir, default_options):
r"""Verify that line endings are translated to \n.""" r"""Verify that line endings are translated to \n."""
lines = _lines_from_file( lines = _lines_from_file(
tmpdir, b'# coding: utf-8\r\nx = 1\r\n', default_options) tmpdir, b"# coding: utf-8\r\nx = 1\r\n", default_options
assert lines == ['# coding: utf-8\n', 'x = 1\n'] )
assert lines == ["# coding: utf-8\n", "x = 1\n"]
def test_read_lines_incorrect_utf_16(tmpdir, default_options): def test_read_lines_incorrect_utf_16(tmpdir, default_options):
"""Verify that an incorrectly encoded file is read as latin-1.""" """Verify that an incorrectly encoded file is read as latin-1."""
lines = _lines_from_file( lines = _lines_from_file(
tmpdir, b'# coding: utf16\nx = 1\n', default_options) tmpdir, b"# coding: utf16\nx = 1\n", default_options
assert lines == ['# coding: utf16\n', 'x = 1\n'] )
assert lines == ["# coding: utf16\n", "x = 1\n"]
def test_read_lines_unknown_encoding(tmpdir, default_options): def test_read_lines_unknown_encoding(tmpdir, default_options):
"""Verify that an unknown encoding is still read as latin-1.""" """Verify that an unknown encoding is still read as latin-1."""
lines = _lines_from_file( lines = _lines_from_file(
tmpdir, b'# coding: fake-encoding\nx = 1\n', default_options) tmpdir, b"# coding: fake-encoding\nx = 1\n", default_options
assert lines == ['# coding: fake-encoding\n', 'x = 1\n'] )
assert lines == ["# coding: fake-encoding\n", "x = 1\n"]
@pytest.mark.parametrize('first_line', [ @pytest.mark.parametrize(
'\xEF\xBB\xBF"""Module docstring."""\n', "first_line",
'\uFEFF"""Module docstring."""\n', [
]) '\xEF\xBB\xBF"""Module docstring."""\n',
'\uFEFF"""Module docstring."""\n',
],
)
def test_strip_utf_bom(first_line, default_options): def test_strip_utf_bom(first_line, default_options):
r"""Verify that we strip '\xEF\xBB\xBF' from the first line.""" r"""Verify that we strip '\xEF\xBB\xBF' from the first line."""
lines = [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 != lines
assert file_processor.lines[0] == '"""Module docstring."""\n' assert file_processor.lines[0] == '"""Module docstring."""\n'
@pytest.mark.parametrize('lines, expected', [ @pytest.mark.parametrize(
(['\xEF\xBB\xBF"""Module docstring."""\n'], False), "lines, expected",
(['\uFEFF"""Module docstring."""\n'], False), [
(['#!/usr/bin/python', '# flake8 is great', 'a = 1'], False), (['\xEF\xBB\xBF"""Module docstring."""\n'], False),
(['#!/usr/bin/python', '# flake8: noqa', 'a = 1'], True), (['\uFEFF"""Module docstring."""\n'], False),
(['#!/usr/bin/python', '# flake8:noqa', 'a = 1'], True), (["#!/usr/bin/python", "# flake8 is great", "a = 1"], False),
(['# flake8: noqa', '#!/usr/bin/python', 'a = 1'], True), (["#!/usr/bin/python", "# flake8: noqa", "a = 1"], True),
(['# flake8:noqa', '#!/usr/bin/python', 'a = 1'], True), (["#!/usr/bin/python", "# flake8:noqa", "a = 1"], True),
(['#!/usr/bin/python', 'a = 1', '# flake8: noqa'], True), (["# flake8: noqa", "#!/usr/bin/python", "a = 1"], True),
(['#!/usr/bin/python', 'a = 1', '# flake8:noqa'], True), (["# flake8:noqa", "#!/usr/bin/python", "a = 1"], True),
(['#!/usr/bin/python', 'a = 1 # flake8: noqa'], False), (["#!/usr/bin/python", "a = 1", "# flake8: noqa"], True),
(['#!/usr/bin/python', 'a = 1 # flake8:noqa'], False), (["#!/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): def test_should_ignore_file(lines, expected, default_options):
"""Verify that we ignore a file if told to.""" """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 assert file_processor.should_ignore_file() is expected
def test_should_ignore_file_to_handle_disable_noqa(default_options): def test_should_ignore_file_to_handle_disable_noqa(default_options):
"""Verify that we ignore a file if told to.""" """Verify that we ignore a file if told to."""
lines = ['# flake8: noqa'] lines = ["# flake8: noqa"]
file_processor = processor.FileProcessor('-', default_options, lines) file_processor = processor.FileProcessor("-", default_options, lines)
assert file_processor.should_ignore_file() is True assert file_processor.should_ignore_file() is True
default_options.disable_noqa = 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 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): def test_read_lines_from_stdin(stdin_get_value, default_options):
"""Verify that we use our own utility function to retrieve stdin.""" """Verify that we use our own utility function to retrieve stdin."""
stdin_get_value.return_value = '' stdin_get_value.return_value = ""
processor.FileProcessor('-', default_options) processor.FileProcessor("-", default_options)
stdin_get_value.assert_called_once_with() 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): def test_stdin_filename_attribute(stdin_get_value, default_options):
"""Verify that we update the filename attribute.""" """Verify that we update the filename attribute."""
stdin_get_value.return_value = '' stdin_get_value.return_value = ""
file_processor = processor.FileProcessor('-', default_options) file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == 'stdin' 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): def test_read_lines_uses_display_name(stdin_get_value, default_options):
"""Verify that when processing stdin we use a display name if present.""" """Verify that when processing stdin we use a display name if present."""
default_options.stdin_display_name = 'display_name.py' default_options.stdin_display_name = "display_name.py"
stdin_get_value.return_value = '' stdin_get_value.return_value = ""
file_processor = processor.FileProcessor('-', default_options) file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == 'display_name.py' 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( 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.""" """Verify that when processing stdin we use a display name if present."""
stdin_get_value.return_value = '' stdin_get_value.return_value = ""
default_options.stdin_display_name = '' default_options.stdin_display_name = ""
file_processor = processor.FileProcessor('-', default_options) file_processor = processor.FileProcessor("-", default_options)
assert file_processor.filename == 'stdin' assert file_processor.filename == "stdin"
def test_noqa_line_for(default_options): def test_noqa_line_for(default_options):
"""Verify we grab the correct line from the cached lines.""" """Verify we grab the correct line from the cached lines."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'Line 1\n', "-",
'Line 2\n', default_options,
'Line 3\n', lines=[
]) "Line 1\n",
"Line 2\n",
"Line 3\n",
],
)
for i in range(1, 4): 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): def test_noqa_line_for_continuation(default_options):
@ -145,15 +159,15 @@ world
""" # 7 """ # 7
''' '''
lines = src.splitlines(True) 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 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(1) == l_1_2
assert file_processor.noqa_line_for(2) == 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' l_4_7 = 'x = """\nhello\nworld\n""" # 7\n'
for i in (4, 5, 6, 7): for i in (4, 5, 6, 7):
@ -164,76 +178,104 @@ world
def test_noqa_line_for_no_eol_at_end_of_file(default_options): 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.""" """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) 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(1) == l_1_2
assert file_processor.noqa_line_for(2) == l_1_2 assert file_processor.noqa_line_for(2) == l_1_2
def test_next_line(default_options): def test_next_line(default_options):
"""Verify we update the file_processor state for each new line.""" """Verify we update the file_processor state for each new line."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'Line 1', "-",
'Line 2', default_options,
'Line 3', lines=[
]) "Line 1",
"Line 2",
"Line 3",
],
)
for i in range(1, 4): 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 assert file_processor.line_number == i
@pytest.mark.parametrize('params, args, expected_kwargs', [ @pytest.mark.parametrize(
({'blank_before': True, 'blank_lines': True}, "params, args, expected_kwargs",
None, [
{'blank_before': 0, 'blank_lines': 0}), (
({'noqa': True, 'fake': True}, {"blank_before": True, "blank_lines": True},
{'fake': 'foo'}, None,
{'noqa': False, 'fake': 'foo'}), {"blank_before": 0, "blank_lines": 0},
({'blank_before': True, 'blank_lines': True, 'noqa': True}, ),
{'blank_before': 10, 'blank_lines': 5, 'noqa': True}, (
{'blank_before': 10, 'blank_lines': 5, 'noqa': True}), {"noqa": True, "fake": True},
({}, {'fake': 'foo'}, {'fake': 'foo'}), {"fake": "foo"},
({'non-existent': False}, {'fake': 'foo'}, {'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): def test_keyword_arguments_for(params, args, expected_kwargs, default_options):
"""Verify the keyword args are generated properly.""" """Verify the keyword args are generated properly."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'Line 1', "-",
]) default_options,
lines=[
"Line 1",
],
)
kwargs_for = file_processor.keyword_arguments_for kwargs_for = file_processor.keyword_arguments_for
assert kwargs_for(params, args) == expected_kwargs assert kwargs_for(params, args) == expected_kwargs
def test_keyword_arguments_for_does_not_handle_attribute_errors( def test_keyword_arguments_for_does_not_handle_attribute_errors(
default_options, default_options,
): ):
"""Verify we re-raise AttributeErrors.""" """Verify we re-raise AttributeErrors."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'Line 1', "-",
]) default_options,
lines=[
"Line 1",
],
)
with pytest.raises(AttributeError): 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', [ @pytest.mark.parametrize(
('line', []), "unsplit_line, expected_lines",
('line 1\n', ['line 1']), [
('line 1\nline 2\n', ['line 1', 'line 2']), ("line", []),
('line 1\n\nline 2\n', ['line 1', '', 'line 2']), ("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): def test_split_line(unsplit_line, expected_lines, default_options):
"""Verify the token line splitting.""" """Verify the token line splitting."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'Line 1', "-",
]) 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)) actual_lines = list(file_processor.split_line(token))
assert expected_lines == actual_lines 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): def test_build_ast(default_options):
"""Verify the logic for how we build an AST for plugins.""" """Verify the logic for how we build an AST for plugins."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'a = 1\n' "-", default_options, lines=["a = 1\n"]
]) )
module = file_processor.build_ast() module = file_processor.build_ast()
assert isinstance(module, ast.Module) 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): def test_next_logical_line_updates_the_previous_logical_line(default_options):
"""Verify that we update our tracking of the previous logical line.""" """Verify that we update our tracking of the previous logical line."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'a = 1\n' "-", default_options, lines=["a = 1\n"]
]) )
file_processor.indent_level = 1 file_processor.indent_level = 1
file_processor.logical_line = 'a = 1' file_processor.logical_line = "a = 1"
assert file_processor.previous_logical == '' assert file_processor.previous_logical == ""
assert file_processor.previous_indent_level == 0 assert file_processor.previous_indent_level == 0
file_processor.next_logical_line() 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 assert file_processor.previous_indent_level == 1
def test_visited_new_blank_line(default_options): def test_visited_new_blank_line(default_options):
"""Verify we update the number of blank lines seen.""" """Verify we update the number of blank lines seen."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'a = 1\n' "-", default_options, lines=["a = 1\n"]
]) )
assert file_processor.blank_lines == 0 assert file_processor.blank_lines == 0
file_processor.visited_new_blank_line() file_processor.visited_new_blank_line()
@ -279,9 +321,9 @@ def test_visited_new_blank_line(default_options):
def test_inside_multiline(default_options): def test_inside_multiline(default_options):
"""Verify we update the line number and reset multiline.""" """Verify we update the line number and reset multiline."""
file_processor = processor.FileProcessor('-', default_options, lines=[ file_processor = processor.FileProcessor(
'a = 1\n' "-", default_options, lines=["a = 1\n"]
]) )
assert file_processor.multiline is False assert file_processor.multiline is False
assert file_processor.line_number == 0 assert file_processor.line_number == 0
@ -292,63 +334,87 @@ def test_inside_multiline(default_options):
assert file_processor.multiline is False assert file_processor.multiline is False
@pytest.mark.parametrize('string, expected', [ @pytest.mark.parametrize(
('""', '""'), "string, expected",
("''", "''"), [
('"a"', '"x"'), ('""', '""'),
("'a'", "'x'"), ("''", "''"),
('"x"', '"x"'), ('"a"', '"x"'),
("'x'", "'x'"), ("'a'", "'x'"),
('"abcdef"', '"xxxxxx"'), ('"x"', '"x"'),
("'abcdef'", "'xxxxxx'"), ("'x'", "'x'"),
('""""""', '""""""'), ('"abcdef"', '"xxxxxx"'),
("''''''", "''''''"), ("'abcdef'", "'xxxxxx'"),
('"""a"""', '"""x"""'), ('""""""', '""""""'),
("'''a'''", "'''x'''"), ("''''''", "''''''"),
('"""x"""', '"""x"""'), ('"""a"""', '"""x"""'),
("'''x'''", "'''x'''"), ("'''a'''", "'''x'''"),
('"""abcdef"""', '"""xxxxxx"""'), ('"""x"""', '"""x"""'),
("'''abcdef'''", "'''xxxxxx'''"), ("'''x'''", "'''x'''"),
('"""xxxxxx"""', '"""xxxxxx"""'), ('"""abcdef"""', '"""xxxxxx"""'),
("'''xxxxxx'''", "'''xxxxxx'''"), ("'''abcdef'''", "'''xxxxxx'''"),
]) ('"""xxxxxx"""', '"""xxxxxx"""'),
("'''xxxxxx'''", "'''xxxxxx'''"),
],
)
def test_mutate_string(string, expected, default_options): def test_mutate_string(string, expected, default_options):
"""Verify we appropriately mutate the string to sanitize it.""" """Verify we appropriately mutate the string to sanitize it."""
actual = processor.mutate_string(string) actual = processor.mutate_string(string)
assert expected == actual assert expected == actual
@pytest.mark.parametrize('string, expected', [ @pytest.mark.parametrize(
(' ', 4), "string, expected",
(' ', 6), [
('\t', 8), (" ", 4),
('\t\t', 16), (" ", 6),
(' \t', 8), ("\t", 8),
(' \t', 16), ("\t\t", 16),
]) (" \t", 8),
(" \t", 16),
],
)
def test_expand_indent(string, expected): def test_expand_indent(string, expected):
"""Verify we correctly measure the amount of indentation.""" """Verify we correctly measure the amount of indentation."""
actual = processor.expand_indent(string) actual = processor.expand_indent(string)
assert expected == actual assert expected == actual
@pytest.mark.parametrize('token, log_string', [ @pytest.mark.parametrize(
[(tokenize.COMMENT, '# this is a comment', "token, log_string",
(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,
[(tokenize.COMMENT, '# this is a comment', "# this is a comment",
(1, 5), # (start_row, start_column) (1, 0), # (start_row, start_column)
(1, 19), # (end_ro, end_column) (1, 19), # (end_ro, end_column)
'# 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', "l.1\t[:19]\tCOMMENT\t'# 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'"], 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",
(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'",
],
],
)
def test_log_token(token, log_string): def test_log_token(token, log_string):
"""Verify we use the log object passed in.""" """Verify we use the log object passed in."""
log = mock.Mock() log = mock.Mock()
@ -359,15 +425,18 @@ def test_log_token(token, log_string):
) )
@pytest.mark.parametrize('current_count, token_text, expected', [ @pytest.mark.parametrize(
(0, '(', 1), "current_count, token_text, expected",
(0, '[', 1), [
(0, '{', 1), (0, "(", 1),
(1, ')', 0), (0, "[", 1),
(1, ']', 0), (0, "{", 1),
(1, '}', 0), (1, ")", 0),
(10, '+', 10), (1, "]", 0),
]) (1, "}", 0),
(10, "+", 10),
],
)
def test_count_parentheses(current_count, token_text, expected): def test_count_parentheses(current_count, token_text, expected):
"""Verify our arithmetic is correct.""" """Verify our arithmetic is correct."""
assert processor.count_parentheses(current_count, token_text) == expected assert processor.count_parentheses(current_count, token_text) == expected

View file

@ -7,8 +7,8 @@ from flake8.formatting import default
def options(**kwargs): def options(**kwargs):
"""Create an argparse.Namespace instance.""" """Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None) kwargs.setdefault("output_file", None)
kwargs.setdefault('tee', False) kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs) return argparse.Namespace(**kwargs)
@ -18,22 +18,23 @@ def test_caches_filenames_already_printed():
assert formatter.filenames_already_printed == set() assert formatter.filenames_already_printed == set()
formatter.format( formatter.format(
style_guide.Violation('code', 'file.py', 1, 1, 'text', 'l')) style_guide.Violation("code", "file.py", 1, 1, "text", "l")
assert formatter.filenames_already_printed == {'file.py'} )
assert formatter.filenames_already_printed == {"file.py"}
def test_only_returns_a_string_once_from_format(): def test_only_returns_a_string_once_from_format():
"""Verify format ignores the second error with the same filename.""" """Verify format ignores the second error with the same filename."""
formatter = default.FilenameOnly(options()) 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 assert formatter.format(error) is None
def test_show_source_returns_nothing(): def test_show_source_returns_nothing():
"""Verify show_source returns nothing.""" """Verify show_source returns nothing."""
formatter = default.FilenameOnly(options()) 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 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 = mock.MagicMock()
config_finder.cli_config.return_value = config_obj config_finder.cli_config.return_value = config_obj
config_finder.ignore_config_files = False config_finder.ignore_config_files = False
config_obj.get.return_value = '' config_obj.get.return_value = ""
config_file_value = 'foo.ini' config_file_value = "foo.ini"
config_finder.config_file = config_file_value config_finder.config_file = config_file_value
config.get_local_plugins(config_finder) config.get_local_plugins(config_finder)
@ -34,12 +34,12 @@ def test_get_local_plugins_uses_cli_config():
def test_get_local_plugins(): def test_get_local_plugins():
"""Verify get_local_plugins returns expected plugins.""" """Verify get_local_plugins returns expected plugins."""
config_fixture_path = 'tests/fixtures/config_files/local-plugin.ini' config_fixture_path = "tests/fixtures/config_files/local-plugin.ini"
config_finder = config.ConfigFileFinder('flake8') 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] localcfs.return_value = [config_fixture_path]
local_plugins = config.get_local_plugins(config_finder) local_plugins = config.get_local_plugins(config_finder)
assert local_plugins.extension == ['XE = test_plugins:ExtensionTestPlugin'] assert local_plugins.extension == ["XE = test_plugins:ExtensionTestPlugin"]
assert local_plugins.report == ['XR = test_plugins:ReportTestPlugin'] assert local_plugins.report == ["XR = test_plugins:ReportTestPlugin"]

View file

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

View file

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

View file

@ -7,15 +7,15 @@ from flake8.formatting import default
def options(**kwargs): def options(**kwargs):
"""Create an argparse.Namespace instance.""" """Create an argparse.Namespace instance."""
kwargs.setdefault('output_file', None) kwargs.setdefault("output_file", None)
kwargs.setdefault('tee', False) kwargs.setdefault("tee", False)
return argparse.Namespace(**kwargs) return argparse.Namespace(**kwargs)
def test_format_returns_nothing(): def test_format_returns_nothing():
"""Verify Nothing.format returns None.""" """Verify Nothing.format returns None."""
formatter = default.Nothing(options()) 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 assert formatter.format(error) is None
@ -23,6 +23,6 @@ def test_format_returns_nothing():
def test_show_source_returns_nothing(): def test_show_source_returns_nothing():
"""Verify Nothing.show_source returns None.""" """Verify Nothing.show_source returns None."""
formatter = default.Nothing(options()) 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 assert formatter.show_source(error) is None

View file

@ -10,9 +10,9 @@ from flake8.options import manager
def test_to_argparse(): def test_to_argparse():
"""Test conversion to an argparse arguments.""" """Test conversion to an argparse arguments."""
opt = manager.Option( opt = manager.Option(
short_option_name='-t', short_option_name="-t",
long_option_name='--test', long_option_name="--test",
action='count', action="count",
parse_from_config=True, parse_from_config=True,
normalize_paths=True, normalize_paths=True,
) )
@ -20,42 +20,44 @@ def test_to_argparse():
assert opt.parse_from_config is True assert opt.parse_from_config is True
args, kwargs = opt.to_argparse() args, kwargs = opt.to_argparse()
assert args == ['-t', '--test'] assert args == ["-t", "--test"]
assert kwargs == {'action': 'count', 'type': mock.ANY} assert kwargs == {"action": "count", "type": mock.ANY}
assert isinstance(kwargs['type'], functools.partial) assert isinstance(kwargs["type"], functools.partial)
def test_to_optparse(): def test_to_optparse():
"""Test that .to_optparse() produces a useful error message.""" """Test that .to_optparse() produces a useful error message."""
with pytest.raises(AttributeError) as excinfo: with pytest.raises(AttributeError) as excinfo:
manager.Option('--foo').to_optparse manager.Option("--foo").to_optparse
msg, = excinfo.value.args (msg,) = excinfo.value.args
assert msg == 'to_optparse: flake8 now uses argparse' assert msg == "to_optparse: flake8 now uses argparse"
def test_to_argparse_creates_an_option_as_we_expect(): def test_to_argparse_creates_an_option_as_we_expect():
"""Show that we pass all keyword args to argparse.""" """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() args, kwargs = opt.to_argparse()
assert args == ['-t', '--test'] assert args == ["-t", "--test"]
assert kwargs == {'action': 'count'} assert kwargs == {"action": "count"}
def test_config_name_generation(): def test_config_name_generation():
"""Show that we generate the config name deterministically.""" """Show that we generate the config name deterministically."""
opt = manager.Option(long_option_name='--some-very-long-option-name', opt = manager.Option(
parse_from_config=True) 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(): def test_config_name_needs_long_option_name():
"""Show that we error out if the Option should be parsed from config.""" """Show that we error out if the Option should be parsed from config."""
with pytest.raises(ValueError): with pytest.raises(ValueError):
manager.Option('-s', parse_from_config=True) manager.Option("-s", parse_from_config=True)
def test_dest_is_not_overridden(): def test_dest_is_not_overridden():
"""Show that we do not override custom destinations.""" """Show that we do not override custom destinations."""
opt = manager.Option('-s', '--short', dest='something_not_short') opt = manager.Option("-s", "--short", dest="something_not_short")
assert opt.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.main.options import JobsArgument
from flake8.options import manager from flake8.options import manager
TEST_VERSION = '3.0.0b1' TEST_VERSION = "3.0.0b1"
@pytest.fixture @pytest.fixture
def optmanager(): def optmanager():
"""Generate a simple OptionManager with default test arguments.""" """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): 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.""" """Verify parent options are included in the parsed options."""
# GIVEN # GIVEN
parent_parser = argparse.ArgumentParser(add_help=False) parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('--parent') parent_parser.add_argument("--parent")
# WHEN # WHEN
optmanager = manager.OptionManager( optmanager = manager.OptionManager(
prog='flake8', prog="flake8", version=TEST_VERSION, parents=[parent_parser]
version=TEST_VERSION, )
parents=[parent_parser]) option, _ = optmanager.parse_args(["--parent", "foo"])
option, _ = optmanager.parse_args(['--parent', 'foo'])
# THEN # THEN
assert option.parent == 'foo' assert option.parent == "foo"
def test_parse_args_forwarding_default_values(optmanager): def test_parse_args_forwarding_default_values(optmanager):
"""Verify default provided values are present in the final result.""" """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) options, args = optmanager.parse_args([], namespace)
assert options.foo == 'bar' assert options.foo == "bar"
def test_parse_args_forwarding_type_coercion(optmanager): def test_parse_args_forwarding_type_coercion(optmanager):
"""Verify default provided values are type converted from add_option.""" """Verify default provided values are type converted from add_option."""
optmanager.add_option('--foo', type=int) optmanager.add_option("--foo", type=int)
namespace = argparse.Namespace(foo='5') namespace = argparse.Namespace(foo="5")
options, args = optmanager.parse_args([], namespace) options, args = optmanager.parse_args([], namespace)
assert options.foo == 5 assert options.foo == 5
@ -60,8 +59,8 @@ def test_add_option_short_option_only(optmanager):
assert optmanager.options == [] assert optmanager.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('-s', help='Test short opt') optmanager.add_option("-s", help="Test short opt")
assert optmanager.options[0].short_option_name == '-s' assert optmanager.options[0].short_option_name == "-s"
def test_add_option_long_option_only(optmanager): 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.options == []
assert optmanager.config_options_dict == {} 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].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): 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.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('-b', '--both', help='Test both opts') optmanager.add_option("-b", "--both", help="Test both opts")
assert optmanager.options[0].short_option_name == '-b' assert optmanager.options[0].short_option_name == "-b"
assert optmanager.options[0].long_option_name == '--both' assert optmanager.options[0].long_option_name == "--both"
def test_add_option_with_custom_args(optmanager): 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.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('--parse', parse_from_config=True) optmanager.add_option("--parse", parse_from_config=True)
optmanager.add_option('--commas', comma_separated_list=True) optmanager.add_option("--commas", comma_separated_list=True)
optmanager.add_option('--files', normalize_paths=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): for option, attr in zip(optmanager.options, attrs):
assert getattr(option, attr) is True assert getattr(option, attr) is True
@ -103,10 +102,10 @@ def test_parse_args_normalize_path(optmanager):
assert optmanager.options == [] assert optmanager.options == []
assert optmanager.config_options_dict == {} 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']) options, args = optmanager.parse_args(["--config", "../config.ini"])
assert options.config == os.path.abspath('../config.ini') assert options.config == os.path.abspath("../config.ini")
def test_parse_args_handles_comma_separated_defaults(optmanager): 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.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('--exclude', default='E123,W234', optmanager.add_option(
comma_separated_list=True) "--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args([]) options, args = optmanager.parse_args([])
assert options.exclude == ['E123', 'W234'] assert options.exclude == ["E123", "W234"]
def test_parse_args_handles_comma_separated_lists(optmanager): 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.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('--exclude', default='E123,W234', optmanager.add_option(
comma_separated_list=True) "--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args(['--exclude', 'E201,W111,F280']) options, args = optmanager.parse_args(["--exclude", "E201,W111,F280"])
assert options.exclude == ['E201', 'W111', 'F280'] assert options.exclude == ["E201", "W111", "F280"]
def test_parse_args_normalize_paths(optmanager): def test_parse_args_normalize_paths(optmanager):
@ -138,57 +139,61 @@ def test_parse_args_normalize_paths(optmanager):
assert optmanager.options == [] assert optmanager.options == []
assert optmanager.config_options_dict == {} assert optmanager.config_options_dict == {}
optmanager.add_option('--extra-config', normalize_paths=True, optmanager.add_option(
comma_separated_list=True) "--extra-config", normalize_paths=True, comma_separated_list=True
)
options, args = optmanager.parse_args([ options, args = optmanager.parse_args(
'--extra-config', '../config.ini,tox.ini,flake8/some-other.cfg' ["--extra-config", "../config.ini,tox.ini,flake8/some-other.cfg"]
]) )
assert options.extra_config == [ assert options.extra_config == [
os.path.abspath('../config.ini'), os.path.abspath("../config.ini"),
'tox.ini', "tox.ini",
os.path.abspath('flake8/some-other.cfg'), os.path.abspath("flake8/some-other.cfg"),
] ]
def test_generate_versions(optmanager): def test_generate_versions(optmanager):
"""Verify a comma-separated string is generated of registered plugins.""" """Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins = [ optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False), manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion('Testing 101', '0.0.0', False), manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion('Testing 300', '0.0.0', True), manager.PluginVersion("Testing 300", "0.0.0", True),
] ]
assert (optmanager.generate_versions() assert (
== 'Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0') 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): def test_plugins_are_sorted_in_generate_versions(optmanager):
"""Verify we sort before joining strings in generate_versions.""" """Verify we sort before joining strings in generate_versions."""
optmanager.registered_plugins = [ optmanager.registered_plugins = [
manager.PluginVersion('pyflakes', '1.5.0', False), manager.PluginVersion("pyflakes", "1.5.0", False),
manager.PluginVersion('mccabe', '0.7.0', False), manager.PluginVersion("mccabe", "0.7.0", False),
manager.PluginVersion('pycodestyle', '2.2.0', False), manager.PluginVersion("pycodestyle", "2.2.0", False),
manager.PluginVersion('flake8-docstrings', '0.6.1', False), manager.PluginVersion("flake8-docstrings", "0.6.1", False),
manager.PluginVersion('flake8-bugbear', '2016.12.1', False), manager.PluginVersion("flake8-bugbear", "2016.12.1", False),
] ]
assert (optmanager.generate_versions() assert (
== 'flake8-bugbear: 2016.12.1, ' optmanager.generate_versions() == "flake8-bugbear: 2016.12.1, "
'flake8-docstrings: 0.6.1, ' "flake8-docstrings: 0.6.1, "
'mccabe: 0.7.0, ' "mccabe: 0.7.0, "
'pycodestyle: 2.2.0, ' "pycodestyle: 2.2.0, "
'pyflakes: 1.5.0') "pyflakes: 1.5.0"
)
def test_generate_versions_with_format_string(optmanager): def test_generate_versions_with_format_string(optmanager):
"""Verify a comma-separated string is generated of registered plugins.""" """Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins.update([ 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),
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'
) )
assert optmanager.generate_versions() == "Testing: 0.0.0"
def test_update_version_string(optmanager): def test_update_version_string(optmanager):
@ -197,17 +202,20 @@ def test_update_version_string(optmanager):
assert optmanager.version_action.version == TEST_VERSION assert optmanager.version_action.version == TEST_VERSION
optmanager.registered_plugins = [ optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False), manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion('Testing 101', '0.0.0', False), manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion('Testing 300', '0.0.0', False), manager.PluginVersion("Testing 300", "0.0.0", False),
] ]
optmanager.update_version_string() optmanager.update_version_string()
assert optmanager.version == TEST_VERSION assert optmanager.version == TEST_VERSION
assert (optmanager.version_action.version == TEST_VERSION assert (
+ ' (Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0) ' optmanager.version_action.version
+ utils.get_python_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): def test_generate_epilog(optmanager):
@ -215,14 +223,14 @@ def test_generate_epilog(optmanager):
assert optmanager.parser.epilog is None assert optmanager.parser.epilog is None
optmanager.registered_plugins = [ optmanager.registered_plugins = [
manager.PluginVersion('Testing 100', '0.0.0', False), manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion('Testing 101', '0.0.0', False), manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion('Testing 300', '0.0.0', False), manager.PluginVersion("Testing 300", "0.0.0", False),
] ]
expected_value = ( expected_value = (
'Installed plugins: Testing 100: 0.0.0, Testing 101: 0.0.0, Testing' "Installed plugins: Testing 100: 0.0.0, Testing 101: 0.0.0, Testing"
' 300: 0.0.0' " 300: 0.0.0"
) )
optmanager.generate_epilog() optmanager.generate_epilog()
@ -233,14 +241,14 @@ def test_extend_default_ignore(optmanager):
"""Verify that we update the extended default ignore list.""" """Verify that we update the extended default ignore list."""
assert optmanager.extended_default_ignore == set() assert optmanager.extended_default_ignore == set()
optmanager.extend_default_ignore(['T100', 'T101', 'T102']) optmanager.extend_default_ignore(["T100", "T101", "T102"])
assert optmanager.extended_default_ignore == {'T100', 'T101', 'T102'} assert optmanager.extended_default_ignore == {"T100", "T101", "T102"}
def test_parse_known_args(optmanager): def test_parse_known_args(optmanager):
"""Verify we ignore unknown options.""" """Verify we ignore unknown options."""
with mock.patch('sys.exit') as sysexit: with mock.patch("sys.exit") as sysexit:
optmanager.parse_known_args(['--max-complexity', '5']) optmanager.parse_known_args(["--max-complexity", "5"])
assert sysexit.called is False assert sysexit.called is False
@ -249,101 +257,101 @@ def test_optparse_normalize_callback_option_legacy(optmanager):
"""Test the optparse shim for `callback=`.""" """Test the optparse shim for `callback=`."""
callback_foo = mock.Mock() callback_foo = mock.Mock()
optmanager.add_option( optmanager.add_option(
'--foo', "--foo",
action='callback', action="callback",
callback=callback_foo, callback=callback_foo,
callback_args=(1, 2), callback_args=(1, 2),
callback_kwargs={'a': 'b'}, callback_kwargs={"a": "b"},
) )
callback_bar = mock.Mock() callback_bar = mock.Mock()
optmanager.add_option( optmanager.add_option(
'--bar', "--bar",
action='callback', action="callback",
type='string', type="string",
callback=callback_bar, callback=callback_bar,
) )
callback_baz = mock.Mock() callback_baz = mock.Mock()
optmanager.add_option( optmanager.add_option(
'--baz', "--baz",
action='callback', action="callback",
type='string', type="string",
nargs=2, nargs=2,
callback=callback_baz, 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( callback_foo.assert_called_once_with(
mock.ANY, # the option / action instance mock.ANY, # the option / action instance
'--foo', "--foo",
None, None,
mock.ANY, # the OptionParser / ArgumentParser mock.ANY, # the OptionParser / ArgumentParser
1, 1,
2, 2,
a='b', a="b",
) )
callback_bar.assert_called_once_with( callback_bar.assert_called_once_with(
mock.ANY, # the option / action instance mock.ANY, # the option / action instance
'--bar', "--bar",
'bararg', "bararg",
mock.ANY, # the OptionParser / ArgumentParser mock.ANY, # the OptionParser / ArgumentParser
) )
callback_baz.assert_called_once_with( callback_baz.assert_called_once_with(
mock.ANY, # the option / action instance mock.ANY, # the option / action instance
'--baz', "--baz",
('1', '2'), ("1", "2"),
mock.ANY, # the OptionParser / ArgumentParser mock.ANY, # the OptionParser / ArgumentParser
) )
@pytest.mark.parametrize( @pytest.mark.parametrize(
('type_s', 'input_val', 'expected'), ("type_s", "input_val", "expected"),
( (
('int', '5', 5), ("int", "5", 5),
('long', '6', 6), ("long", "6", 6),
('string', 'foo', 'foo'), ("string", "foo", "foo"),
('float', '1.5', 1.5), ("float", "1.5", 1.5),
('complex', '1+5j', 1 + 5j), ("complex", "1+5j", 1 + 5j),
# optparse allows this but does not document it # 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): def test_optparse_normalize_types(optmanager, type_s, input_val, expected):
"""Test the optparse shim for type="typename".""" """Test the optparse shim for type="typename"."""
optmanager.add_option('--foo', type=type_s) optmanager.add_option("--foo", type=type_s)
opts, args = optmanager.parse_args(['--foo', input_val]) opts, args = optmanager.parse_args(["--foo", input_val])
assert opts.foo == expected assert opts.foo == expected
def test_optparse_normalize_choice_type(optmanager): def test_optparse_normalize_choice_type(optmanager):
"""Test the optparse shim for type="choice".""" """Test the optparse shim for type="choice"."""
optmanager.add_option('--foo', type='choice', choices=('1', '2', '3')) optmanager.add_option("--foo", type="choice", choices=("1", "2", "3"))
opts, args = optmanager.parse_args(['--foo', '1']) opts, args = optmanager.parse_args(["--foo", "1"])
assert opts.foo == '1' assert opts.foo == "1"
# fails to parse # fails to parse
with pytest.raises(SystemExit): with pytest.raises(SystemExit):
optmanager.parse_args(['--foo', '4']) optmanager.parse_args(["--foo", "4"])
def test_optparse_normalize_help(optmanager, capsys): def test_optparse_normalize_help(optmanager, capsys):
"""Test the optparse shim for %default in help text.""" """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): with pytest.raises(SystemExit):
optmanager.parse_args(['--help']) optmanager.parse_args(["--help"])
out, err = capsys.readouterr() out, err = capsys.readouterr()
output = out + err output = out + err
assert 'default: bar' in output assert "default: bar" in output
def test_optmanager_group(optmanager, capsys): def test_optmanager_group(optmanager, capsys):
"""Test that group(...) causes options to be assigned to a group.""" """Test that group(...) causes options to be assigned to a group."""
with optmanager.group('groupname'): with optmanager.group("groupname"):
optmanager.add_option('--foo') optmanager.add_option("--foo")
with pytest.raises(SystemExit): with pytest.raises(SystemExit):
optmanager.parse_args(['--help']) optmanager.parse_args(["--help"])
out, err = capsys.readouterr() out, err = capsys.readouterr()
output = out + err output = out + err
assert '\ngroupname:\n' in output assert "\ngroupname:\n" in output
@pytest.mark.parametrize( @pytest.mark.parametrize(

View file

@ -11,8 +11,8 @@ from flake8.plugins import manager
def test_load_plugin_fallsback_on_old_setuptools(): def test_load_plugin_fallsback_on_old_setuptools():
"""Verify we fallback gracefully to on old versions of setuptools.""" """Verify we fallback gracefully to on old versions of setuptools."""
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin() plugin.load_plugin()
entry_point.load.assert_called_once_with() 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(): def test_load_plugin_is_idempotent():
"""Verify we use the preferred methods on new versions of setuptools.""" """Verify we use the preferred methods on new versions of setuptools."""
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin.load_plugin() plugin.load_plugin()
plugin.load_plugin() plugin.load_plugin()
@ -31,9 +31,9 @@ def test_load_plugin_is_idempotent():
def test_load_plugin_catches_and_reraises_exceptions(): def test_load_plugin_catches_and_reraises_exceptions():
"""Verify we raise our own FailedToLoadPlugin.""" """Verify we raise our own FailedToLoadPlugin."""
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
entry_point.load.side_effect = ValueError('Test failure') entry_point.load.side_effect = ValueError("Test failure")
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
with pytest.raises(exceptions.FailedToLoadPlugin): with pytest.raises(exceptions.FailedToLoadPlugin):
plugin.load_plugin() plugin.load_plugin()
@ -41,9 +41,9 @@ def test_load_plugin_catches_and_reraises_exceptions():
def test_load_noncallable_plugin(): def test_load_noncallable_plugin():
"""Verify that we do not load a non-callable 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() entry_point.load.return_value = mock.NonCallableMock()
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
with pytest.raises(exceptions.FailedToLoadPlugin): with pytest.raises(exceptions.FailedToLoadPlugin):
plugin.load_plugin() plugin.load_plugin()
@ -52,8 +52,8 @@ def test_load_noncallable_plugin():
def test_plugin_property_loads_plugin_on_first_use(): def test_plugin_property_loads_plugin_on_first_use():
"""Verify that we load our plugin when we first try to use it.""" """Verify that we load our plugin when we first try to use it."""
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
assert plugin.plugin is not None assert plugin.plugin is not None
entry_point.load.assert_called_once_with() 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(): def test_execute_calls_plugin_with_passed_arguments():
"""Verify that we pass arguments directly to the plugin.""" """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_obj = mock.Mock()
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj 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( plugin_obj.assert_called_once_with(
'arg1', 'arg2', kwarg1='value1', kwarg2='value2' "arg1", "arg2", kwarg1="value1", kwarg2="value2"
) )
# Extra assertions # Extra assertions
@ -77,23 +77,24 @@ def test_execute_calls_plugin_with_passed_arguments():
def test_version_proxies_to_the_plugin(): def test_version_proxies_to_the_plugin():
"""Verify that we pass arguments directly to the plugin.""" """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(spec_set=['version']) plugin_obj = mock.Mock(spec_set=["version"])
plugin_obj.version = 'a.b.c' plugin_obj.version = "a.b.c"
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj plugin._plugin = plugin_obj
assert plugin.version == 'a.b.c' assert plugin.version == "a.b.c"
def test_register_options(): def test_register_options():
"""Verify we call add_options on the plugin only if it exists.""" """Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object # Set up our mocks and Plugin object
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(spec_set=['name', 'version', 'add_options', plugin_obj = mock.Mock(
'parse_options']) spec_set=["name", "version", "add_options", "parse_options"]
)
option_manager = mock.MagicMock(spec=options_manager.OptionManager) option_manager = mock.MagicMock(spec=options_manager.OptionManager)
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj plugin._plugin = plugin_obj
# Call the method we're testing. # Call the method we're testing.
@ -106,10 +107,10 @@ def test_register_options():
def test_register_options_checks_plugin_for_method(): def test_register_options_checks_plugin_for_method():
"""Verify we call add_options on the plugin only if it exists.""" """Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object # Set up our mocks and Plugin object
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(spec_set=['name', 'version', 'parse_options']) plugin_obj = mock.Mock(spec_set=["name", "version", "parse_options"])
option_manager = mock.Mock(spec=['register_plugin']) option_manager = mock.Mock(spec=["register_plugin"])
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj plugin._plugin = plugin_obj
# Call the method we're testing. # Call the method we're testing.
@ -122,12 +123,13 @@ def test_register_options_checks_plugin_for_method():
def test_provide_options(): def test_provide_options():
"""Verify we call add_options on the plugin only if it exists.""" """Verify we call add_options on the plugin only if it exists."""
# Set up our mocks and Plugin object # Set up our mocks and Plugin object
entry_point = mock.Mock(spec=['load']) entry_point = mock.Mock(spec=["load"])
plugin_obj = mock.Mock(spec_set=['name', 'version', 'add_options', plugin_obj = mock.Mock(
'parse_options']) spec_set=["name", "version", "add_options", "parse_options"]
)
option_values = argparse.Namespace(enable_extensions=[]) option_values = argparse.Namespace(enable_extensions=[])
option_manager = mock.Mock() option_manager = mock.Mock()
plugin = manager.Plugin('T000', entry_point) plugin = manager.Plugin("T000", entry_point)
plugin._plugin = plugin_obj plugin._plugin = plugin_obj
# Call the method we're testing. # Call the method we're testing.
@ -139,10 +141,13 @@ def test_provide_options():
) )
@pytest.mark.parametrize('ignore_list, code, expected_list', [ @pytest.mark.parametrize(
(['E', 'W', 'F', 'C9'], 'W', ['E', 'F', 'C9']), "ignore_list, code, expected_list",
(['E', 'W', 'F'], 'C9', ['E', 'W', 'F']), [
]) (["E", "W", "F", "C9"], "W", ["E", "F", "C9"]),
(["E", "W", "F"], "C9", ["E", "W", "F"]),
],
)
def test_enable(ignore_list, code, expected_list): def test_enable(ignore_list, code, expected_list):
"""Verify that enabling a plugin removes it from the ignore list.""" """Verify that enabling a plugin removes it from the ignore list."""
options = mock.Mock(ignore=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(): def test_enable_without_providing_parsed_options():
"""Verify that enabling a plugin removes it from the ignore list.""" """Verify that enabling a plugin removes it from the ignore list."""
optmanager = mock.Mock() optmanager = mock.Mock()
plugin = manager.Plugin('U4', mock.Mock()) plugin = manager.Plugin("U4", mock.Mock())
plugin.enable(optmanager) 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 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): def test_calls_entrypoints_on_instantiation(entry_points_mck):
"""Verify that we call entry_points() when we create a manager.""" """Verify that we call entry_points() when we create a manager."""
entry_points_mck.return_value = {} entry_points_mck.return_value = {}
manager.PluginManager(namespace='testing.entrypoints') manager.PluginManager(namespace="testing.entrypoints")
entry_points_mck.assert_called_once_with() 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): def test_calls_entrypoints_creates_plugins_automaticaly(entry_points_mck):
"""Verify that we create Plugins on instantiation.""" """Verify that we create Plugins on instantiation."""
entry_points_mck.return_value = { entry_points_mck.return_value = {
'testing.entrypoints': [ "testing.entrypoints": [
importlib_metadata.EntryPoint('T100', '', 'testing.entrypoints'), importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint('T200', '', '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() entry_points_mck.assert_called_once_with()
assert 'T100' in plugin_mgr.plugins assert "T100" in plugin_mgr.plugins
assert 'T200' in plugin_mgr.plugins assert "T200" in plugin_mgr.plugins
assert isinstance(plugin_mgr.plugins['T100'], manager.Plugin) assert isinstance(plugin_mgr.plugins["T100"], manager.Plugin)
assert isinstance(plugin_mgr.plugins['T200'], 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): def test_handles_mapping_functions_across_plugins(entry_points_mck):
"""Verify we can use the PluginManager call functions on all plugins.""" """Verify we can use the PluginManager call functions on all plugins."""
entry_points_mck.return_value = { entry_points_mck.return_value = {
'testing.entrypoints': [ "testing.entrypoints": [
importlib_metadata.EntryPoint('T100', '', 'testing.entrypoints'), importlib_metadata.EntryPoint("T100", "", "testing.entrypoints"),
importlib_metadata.EntryPoint('T200', '', '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] plugins = [plugin_mgr.plugins[name] for name in plugin_mgr.names]
assert list(plugin_mgr.map(lambda x: x)) == plugins 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): def test_local_plugins(entry_points_mck):
"""Verify PluginManager can load given local plugins.""" """Verify PluginManager can load given local plugins."""
entry_points_mck.return_value = {} entry_points_mck.return_value = {}
plugin_mgr = manager.PluginManager( plugin_mgr = manager.PluginManager(
namespace='testing.entrypoints', namespace="testing.entrypoints", local_plugins=["X = path.to:Plugin"]
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) plugin = mock.create_autospec(manager.Plugin, instance=True)
if raise_exception: if raise_exception:
plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin( plugin.load_plugin.side_effect = exceptions.FailedToLoadPlugin(
plugin_name='T101', plugin_name="T101",
exception=ValueError('Test failure'), exception=ValueError("Test failure"),
) )
return plugin return plugin
@ -28,7 +28,7 @@ def create_mapping_manager_mock(plugins):
yield func(plugin) yield func(plugin)
# Mock out the PluginManager instance # Mock out the PluginManager instance
manager_mock = mock.Mock(spec=['map']) manager_mock = mock.Mock(spec=["map"])
# Replace the map method # Replace the map method
manager_mock.map = fake_map manager_mock.map = fake_map
return manager_mock return manager_mock
@ -47,7 +47,7 @@ class FakeTestType(manager.PluginTypeManager):
namespace = TEST_NAMESPACE namespace = TEST_NAMESPACE
@mock.patch('flake8.plugins.manager.PluginManager') @mock.patch("flake8.plugins.manager.PluginManager")
def test_instantiates_a_manager(PluginManager): # noqa: N803 def test_instantiates_a_manager(PluginManager): # noqa: N803
"""Verify we create a PluginManager on instantiation.""" """Verify we create a PluginManager on instantiation."""
FakeTestType() FakeTestType()
@ -55,26 +55,22 @@ def test_instantiates_a_manager(PluginManager): # noqa: N803
PluginManager.assert_called_once_with(TEST_NAMESPACE, local_plugins=None) 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 def test_proxies_names_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the names attribute.""" """Verify we proxy the names attribute."""
PluginManager.return_value = mock.Mock(names=[ PluginManager.return_value = mock.Mock(names=["T100", "T200", "T300"])
'T100', 'T200', 'T300'
])
type_mgr = FakeTestType() 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 def test_proxies_plugins_to_manager(PluginManager): # noqa: N803
"""Verify we proxy the plugins attribute.""" """Verify we proxy the plugins attribute."""
PluginManager.return_value = mock.Mock(plugins=[ PluginManager.return_value = mock.Mock(plugins=["T100", "T200", "T300"])
'T100', 'T200', 'T300'
])
type_mgr = FakeTestType() type_mgr = FakeTestType()
assert type_mgr.plugins == ['T100', 'T200', 'T300'] assert type_mgr.plugins == ["T100", "T200", "T300"]
def test_generate_call_function(): def test_generate_call_function():
@ -82,21 +78,28 @@ def test_generate_call_function():
optmanager = object() optmanager = object()
plugin = mock.Mock(method_name=lambda x: x) plugin = mock.Mock(method_name=lambda x: x)
func = manager.PluginTypeManager._generate_call_function( func = manager.PluginTypeManager._generate_call_function(
'method_name', optmanager, "method_name",
optmanager,
) )
assert callable(func) assert callable(func)
assert func(plugin) is optmanager assert func(plugin) is optmanager
@mock.patch('flake8.plugins.manager.PluginManager') @mock.patch("flake8.plugins.manager.PluginManager")
def test_load_plugins(PluginManager): # noqa: N803 def test_load_plugins(PluginManager): # noqa: N803
"""Verify load plugins loads *every* plugin.""" """Verify load plugins loads *every* plugin."""
# Create a bunch of fake plugins # Create a bunch of fake plugins
plugins = [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()] create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock # Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins) 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 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 def test_load_plugins_fails(PluginManager): # noqa: N803
"""Verify load plugins bubbles up exceptions.""" """Verify load plugins bubbles up exceptions."""
plugins = [create_plugin_mock(), create_plugin_mock(True), plugins = [
create_plugin_mock(), create_plugin_mock(), create_plugin_mock(),
create_plugin_mock(), 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(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock # Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins) 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 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 def test_register_options(PluginManager): # noqa: N803
"""Test that we map over every plugin to register options.""" """Test that we map over every plugin to register options."""
plugins = [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()] create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock # Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins) PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object() optmanager = object()
@ -151,13 +166,19 @@ def test_register_options(PluginManager): # noqa: N803
plugin.register_options.assert_called_with(optmanager) 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 def test_provide_options(PluginManager): # noqa: N803
"""Test that we map over every plugin to provide parsed options.""" """Test that we map over every plugin to provide parsed options."""
plugins = [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()] create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
create_plugin_mock(),
]
# Return our PluginManager mock # Return our PluginManager mock
PluginManager.return_value = create_mapping_manager_mock(plugins) PluginManager.return_value = create_mapping_manager_mock(plugins)
optmanager = object() optmanager = object()
@ -167,32 +188,30 @@ def test_provide_options(PluginManager): # noqa: N803
type_mgr.provide_options(optmanager, options, []) type_mgr.provide_options(optmanager, options, [])
for plugin in plugins: for plugin in plugins:
plugin.provide_options.assert_called_with(optmanager, plugin.provide_options.assert_called_with(optmanager, options, [])
options,
[])
@mock.patch('flake8.plugins.manager.PluginManager') @mock.patch("flake8.plugins.manager.PluginManager")
def test_proxy_contains_to_managers_plugins_dict(PluginManager): # noqa: N803 def test_proxy_contains_to_managers_plugins_dict(PluginManager): # noqa: N803
"""Verify that we proxy __contains__ to the manager's dictionary.""" """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 # Return our PluginManager mock
PluginManager.return_value = create_manager_with_plugins(plugins) PluginManager.return_value = create_manager_with_plugins(plugins)
type_mgr = FakeTestType() type_mgr = FakeTestType()
for i in range(8): for i in range(8):
key = 'T10%i' % i key = "T10%i" % i
assert key in type_mgr 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 def test_proxies_getitem_to_managers_plugins_dict(PluginManager): # noqa: N803
"""Verify that we can use the PluginTypeManager like a dictionary.""" """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 # Return our PluginManager mock
PluginManager.return_value = create_manager_with_plugins(plugins) PluginManager.return_value = create_manager_with_plugins(plugins)
type_mgr = FakeTestType() type_mgr = FakeTestType()
for i in range(8): for i in range(8):
key = 'T10%i' % i key = "T10%i" % i
assert type_mgr[key] is plugins[key] 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(): def test_undefined_local_code():
"""In pyflakes 2.1.0 this code's string formatting was changed.""" """In pyflakes 2.1.0 this code's string formatting was changed."""
src = '''\ src = """\
import sys import sys
def f(): def f():
sys = sys sys = sys
''' """
tree = ast.parse(src) 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()] message_texts = [s for _, _, s, _ in checker.run()]
assert message_texts == [ assert message_texts == [
"F823 local variable 'sys' defined in enclosing scope on line 1 referenced before assignment", # noqa: E501 "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 statistics as stats
from flake8 import style_guide from flake8 import style_guide
DEFAULT_ERROR_CODE = 'E100' DEFAULT_ERROR_CODE = "E100"
DEFAULT_FILENAME = 'file.py' DEFAULT_FILENAME = "file.py"
DEFAULT_TEXT = 'Default text' DEFAULT_TEXT = "Default text"
def make_error(**kwargs): def make_error(**kwargs):
"""Create errors with a bunch of default values.""" """Create errors with a bunch of default values."""
return style_guide.Violation( return style_guide.Violation(
code=kwargs.pop('code', DEFAULT_ERROR_CODE), code=kwargs.pop("code", DEFAULT_ERROR_CODE),
filename=kwargs.pop('filename', DEFAULT_FILENAME), filename=kwargs.pop("filename", DEFAULT_FILENAME),
line_number=kwargs.pop('line_number', 1), line_number=kwargs.pop("line_number", 1),
column_number=kwargs.pop('column_number', 1), column_number=kwargs.pop("column_number", 1),
text=kwargs.pop('text', DEFAULT_TEXT), text=kwargs.pop("text", DEFAULT_TEXT),
physical_line=None, physical_line=None,
) )
@ -29,26 +29,29 @@ def test_key_creation():
assert key.code == DEFAULT_ERROR_CODE assert key.code == DEFAULT_ERROR_CODE
@pytest.mark.parametrize('code, filename, args, expected_result', [ @pytest.mark.parametrize(
# Error prefix matches "code, filename, args, expected_result",
('E123', 'file000.py', ('E', None), True), [
('E123', 'file000.py', ('E1', None), True), # Error prefix matches
('E123', 'file000.py', ('E12', None), True), ("E123", "file000.py", ("E", None), True),
('E123', 'file000.py', ('E123', None), True), ("E123", "file000.py", ("E1", None), True),
# Error prefix and filename match ("E123", "file000.py", ("E12", None), True),
('E123', 'file000.py', ('E', 'file000.py'), True), ("E123", "file000.py", ("E123", None), True),
('E123', 'file000.py', ('E1', 'file000.py'), True), # Error prefix and filename match
('E123', 'file000.py', ('E12', 'file000.py'), True), ("E123", "file000.py", ("E", "file000.py"), True),
('E123', 'file000.py', ('E123', 'file000.py'), True), ("E123", "file000.py", ("E1", "file000.py"), True),
# Error prefix does not match ("E123", "file000.py", ("E12", "file000.py"), True),
('E123', 'file000.py', ('W', None), False), ("E123", "file000.py", ("E123", "file000.py"), True),
# Error prefix matches but filename does not # Error prefix does not match
('E123', 'file000.py', ('E', 'file001.py'), False), ("E123", "file000.py", ("W", None), False),
# Error prefix does not match but filename does # Error prefix matches but filename does not
('E123', 'file000.py', ('W', 'file000.py'), False), ("E123", "file000.py", ("E", "file001.py"), False),
# Neither error prefix match nor filename # Error prefix does not match but filename does
('E123', 'file000.py', ('W', 'file001.py'), False), ("E123", "file000.py", ("W", "file000.py"), False),
]) # Neither error prefix match nor filename
("E123", "file000.py", ("W", "file001.py"), False),
],
)
def test_key_matching(code, filename, args, expected_result): def test_key_matching(code, filename, args, expected_result):
"""Verify Key#matches behaves as we expect with fthe above input.""" """Verify Key#matches behaves as we expect with fthe above input."""
key = stats.Key.create_from(make_error(code=code, filename=filename)) key = stats.Key.create_from(make_error(code=code, filename=filename))
@ -75,7 +78,7 @@ def test_statistic_increment():
def test_recording_statistics(): def test_recording_statistics():
"""Verify that we appropriately create a new Statistic and store it.""" """Verify that we appropriately create a new Statistic and store it."""
aggregator = stats.Statistics() aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == [] assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error()) aggregator.record(make_error())
storage = aggregator._store storage = aggregator._store
for key, value in storage.items(): for key, value in storage.items():
@ -88,9 +91,9 @@ def test_recording_statistics():
def test_statistics_for_single_record(): def test_statistics_for_single_record():
"""Show we can retrieve the only statistic recorded.""" """Show we can retrieve the only statistic recorded."""
aggregator = stats.Statistics() aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == [] assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error()) aggregator.record(make_error())
statistics = list(aggregator.statistics_for('E')) statistics = list(aggregator.statistics_for("E"))
assert len(statistics) == 1 assert len(statistics) == 1
assert isinstance(statistics[0], stats.Statistic) assert isinstance(statistics[0], stats.Statistic)
@ -98,11 +101,11 @@ def test_statistics_for_single_record():
def test_statistics_for_filters_by_filename(): def test_statistics_for_filters_by_filename():
"""Show we can retrieve the only statistic recorded.""" """Show we can retrieve the only statistic recorded."""
aggregator = stats.Statistics() aggregator = stats.Statistics()
assert list(aggregator.statistics_for('E')) == [] assert list(aggregator.statistics_for("E")) == []
aggregator.record(make_error()) 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 len(statistics) == 1
assert isinstance(statistics[0], stats.Statistic) 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.""" """Show this works for more than a couple statistic values."""
aggregator = stats.Statistics() aggregator = stats.Statistics()
for i in range(50): for i in range(50):
aggregator.record(make_error(code=f'E1{i:02d}')) aggregator.record(make_error(code=f"E1{i:02d}"))
aggregator.record(make_error(code=f'W2{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 assert len(statistics) == 50
statistics = list(aggregator.statistics_for('W22')) statistics = list(aggregator.statistics_for("W22"))
assert len(statistics) == 10 assert len(statistics) == 10

View file

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

View file

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