mirror of
https://github.com/PyCQA/flake8.git
synced 2026-03-31 19:26:52 +00:00
mypy now passes
This commit is contained in:
parent
b6ba6d4d03
commit
fb7e9338cd
32 changed files with 255 additions and 212 deletions
|
|
@ -35,7 +35,7 @@ python36:
|
|||
script: tox -e py36
|
||||
|
||||
python37:
|
||||
image: python:3.7-rc
|
||||
image: python:3.7
|
||||
stage: test
|
||||
script: tox -e py37
|
||||
|
||||
|
|
@ -44,6 +44,11 @@ linters:
|
|||
stage: test
|
||||
script: tox -e linters
|
||||
|
||||
pre-commit:
|
||||
image: python:3.7
|
||||
stage: test
|
||||
script: tox -e pre-commit
|
||||
|
||||
docs:
|
||||
stage: test
|
||||
script: tox -e docs
|
||||
|
|
|
|||
6
.pre-commit-config.yaml
Normal file
6
.pre-commit-config.yaml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v0.701
|
||||
hooks:
|
||||
- id: mypy
|
||||
exclude: ^(docs/|example-plugin/|tests/fixtures)
|
||||
2
mypy.ini
2
mypy.ini
|
|
@ -1,2 +0,0 @@
|
|||
[mypy]
|
||||
ignore_missing_imports = true
|
||||
25
setup.cfg
25
setup.cfg
|
|
@ -16,3 +16,28 @@ requires-dist =
|
|||
pyflakes >= 2.1.0, < 2.2.0
|
||||
pycodestyle >= 2.5.0, < 2.6.0
|
||||
mccabe >= 0.6.0, < 0.7.0
|
||||
|
||||
[mypy]
|
||||
check_untyped_defs = true
|
||||
disallow_any_generics = true
|
||||
disallow_incomplete_defs = true
|
||||
# TODO: disallow_untyped_defs = true
|
||||
no_implicit_optional = true
|
||||
warn_unused_ignores = true
|
||||
|
||||
# TODO: until we opt in all the modules
|
||||
[mypy-flake8.defaults]
|
||||
disallow_untyped_defs = true
|
||||
[mypy-flake8.exceptions]
|
||||
disallow_untyped_defs = true
|
||||
[mypy-flake8.formatting.*]
|
||||
disallow_untyped_defs = true
|
||||
[mypy-flake8.main.cli]
|
||||
disallow_untyped_defs = true
|
||||
[mypy-flake8.statistics]
|
||||
disallow_untyped_defs = true
|
||||
[mypy-flake8.utils]
|
||||
disallow_untyped_defs = true
|
||||
|
||||
[mypy-tests.*]
|
||||
disallow_untyped_defs = false
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ This module
|
|||
import logging
|
||||
import sys
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
from typing import Type # `typing.Type` was introduced in 3.5.2
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
LOG.addHandler(logging.NullHandler())
|
||||
|
||||
|
|
@ -61,7 +64,7 @@ def configure_logging(verbosity, filename=None, logformat=LOG_FORMAT):
|
|||
|
||||
if not filename or filename in ("stderr", "stdout"):
|
||||
fileobj = getattr(sys, filename or "stderr")
|
||||
handler_cls = logging.StreamHandler
|
||||
handler_cls = logging.StreamHandler # type: Type[logging.Handler]
|
||||
else:
|
||||
fileobj = filename
|
||||
handler_cls = logging.FileHandler
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ import collections
|
|||
import errno
|
||||
import logging
|
||||
import signal
|
||||
import sys
|
||||
import tokenize
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
import multiprocessing
|
||||
except ImportError:
|
||||
multiprocessing = None
|
||||
multiprocessing = None # type: ignore
|
||||
|
||||
from flake8 import defaults
|
||||
from flake8 import exceptions
|
||||
|
|
@ -73,8 +72,7 @@ class Manager(object):
|
|||
self.options = style_guide.options
|
||||
self.checks = checker_plugins
|
||||
self.jobs = self._job_count()
|
||||
self.processes = []
|
||||
self.checkers = []
|
||||
self.checkers = [] # type: List[FileChecker]
|
||||
self.statistics = {
|
||||
"files": 0,
|
||||
"logical lines": 0,
|
||||
|
|
@ -195,7 +193,7 @@ class Manager(object):
|
|||
)
|
||||
|
||||
def make_checkers(self, paths=None):
|
||||
# type: (List[str]) -> None
|
||||
# type: (Optional[List[str]]) -> None
|
||||
"""Create checkers for each file."""
|
||||
if paths is None:
|
||||
paths = self.arguments
|
||||
|
|
@ -270,8 +268,10 @@ class Manager(object):
|
|||
|
||||
def run_parallel(self):
|
||||
"""Run the checkers in parallel."""
|
||||
final_results = collections.defaultdict(list)
|
||||
final_statistics = collections.defaultdict(dict)
|
||||
# fmt: off
|
||||
final_results = collections.defaultdict(list) # type: Dict[str, List[Tuple[str, int, int, str, Optional[str]]]] # noqa: E501
|
||||
final_statistics = collections.defaultdict(dict) # type: Dict[str, Dict[str, None]] # noqa: E501
|
||||
# fmt: on
|
||||
|
||||
try:
|
||||
pool = multiprocessing.Pool(self.jobs, _pool_init)
|
||||
|
|
@ -281,6 +281,7 @@ class Manager(object):
|
|||
self.run_serial()
|
||||
return
|
||||
|
||||
pool_closed = False
|
||||
try:
|
||||
pool_map = pool.imap_unordered(
|
||||
_run_checks,
|
||||
|
|
@ -295,9 +296,9 @@ class Manager(object):
|
|||
final_statistics[filename] = statistics
|
||||
pool.close()
|
||||
pool.join()
|
||||
pool = None
|
||||
pool_closed = True
|
||||
finally:
|
||||
if pool is not None:
|
||||
if not pool_closed:
|
||||
pool.terminate()
|
||||
pool.join()
|
||||
|
||||
|
|
@ -345,9 +346,6 @@ class Manager(object):
|
|||
def stop(self):
|
||||
"""Stop checking files."""
|
||||
self._process_statistics()
|
||||
for proc in self.processes:
|
||||
LOG.info("Joining %s to the main process", proc.name)
|
||||
proc.join()
|
||||
|
||||
|
||||
class FileChecker(object):
|
||||
|
|
@ -370,7 +368,9 @@ class FileChecker(object):
|
|||
self.options = options
|
||||
self.filename = filename
|
||||
self.checks = checks
|
||||
self.results = []
|
||||
# fmt: off
|
||||
self.results = [] # type: List[Tuple[str, int, int, str, Optional[str]]] # noqa: E501
|
||||
# fmt: on
|
||||
self.statistics = {
|
||||
"tokens": 0,
|
||||
"logical lines": 0,
|
||||
|
|
@ -389,17 +389,17 @@ class FileChecker(object):
|
|||
return "FileChecker for {}".format(self.filename)
|
||||
|
||||
def _make_processor(self):
|
||||
# type: () -> Optional[processor.FileProcessor]
|
||||
try:
|
||||
return processor.FileProcessor(self.filename, self.options)
|
||||
except IOError:
|
||||
except IOError as e:
|
||||
# If we can not read the file due to an IOError (e.g., the file
|
||||
# does not exist or we do not have the permissions to open it)
|
||||
# then we need to format that exception for the user.
|
||||
# NOTE(sigmavirus24): Historically, pep8 has always reported this
|
||||
# as an E902. We probably *want* a better error code for this
|
||||
# going forward.
|
||||
(exc_type, exception) = sys.exc_info()[:2]
|
||||
message = "{0}: {1}".format(exc_type.__name__, exception)
|
||||
message = "{0}: {1}".format(type(e).__name__, e)
|
||||
self.report("E902", 0, 0, message)
|
||||
return None
|
||||
|
||||
|
|
@ -446,7 +446,7 @@ class FileChecker(object):
|
|||
token = ()
|
||||
if len(exception.args) > 1:
|
||||
token = exception.args[1]
|
||||
if len(token) > 2:
|
||||
if token and len(token) > 2:
|
||||
row, column = token[1:3]
|
||||
else:
|
||||
row, column = (1, 0)
|
||||
|
|
@ -482,14 +482,10 @@ class FileChecker(object):
|
|||
"""Run all checks expecting an abstract syntax tree."""
|
||||
try:
|
||||
ast = self.processor.build_ast()
|
||||
except (ValueError, SyntaxError, TypeError):
|
||||
(exc_type, exception) = sys.exc_info()[:2]
|
||||
row, column = self._extract_syntax_information(exception)
|
||||
except (ValueError, SyntaxError, TypeError) as e:
|
||||
row, column = self._extract_syntax_information(e)
|
||||
self.report(
|
||||
"E999",
|
||||
row,
|
||||
column,
|
||||
"%s: %s" % (exc_type.__name__, exception.args[0]),
|
||||
"E999", row, column, "%s: %s" % (type(e).__name__, e.args[0])
|
||||
)
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
"""Exception classes for all of Flake8."""
|
||||
|
||||
from typing import Dict
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
from flake8.plugins.manager import Plugin
|
||||
|
||||
|
||||
class Flake8Exception(Exception):
|
||||
"""Plain Flake8 exception."""
|
||||
|
|
@ -19,13 +24,14 @@ class FailedToLoadPlugin(Flake8Exception):
|
|||
FORMAT = 'Flake8 failed to load plugin "%(name)s" due to %(exc)s.'
|
||||
|
||||
def __init__(self, plugin, exception):
|
||||
# type: (Plugin, Exception) -> None
|
||||
"""Initialize our FailedToLoadPlugin exception."""
|
||||
self.plugin = plugin
|
||||
self.ep_name = self.plugin.name
|
||||
self.original_exception = exception
|
||||
super(FailedToLoadPlugin, self).__init__(plugin, exception)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self): # type: () -> str
|
||||
"""Format our exception message."""
|
||||
return self.FORMAT % {
|
||||
"name": self.ep_name,
|
||||
|
|
@ -47,7 +53,7 @@ class InvalidSyntax(Flake8Exception):
|
|||
self.column_number = 0
|
||||
super(InvalidSyntax, self).__init__(exception)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self): # type: () -> str
|
||||
"""Format our exception message."""
|
||||
return self.error_message
|
||||
|
||||
|
|
@ -58,6 +64,7 @@ class PluginRequestedUnknownParameters(Flake8Exception):
|
|||
FORMAT = '"%(name)s" requested unknown parameters causing %(exc)s'
|
||||
|
||||
def __init__(self, plugin, exception):
|
||||
# type: (Dict[str, str], Exception) -> None
|
||||
"""Pop certain keyword arguments for initialization."""
|
||||
self.plugin = plugin
|
||||
self.original_exception = exception
|
||||
|
|
@ -65,7 +72,7 @@ class PluginRequestedUnknownParameters(Flake8Exception):
|
|||
plugin, exception
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self): # type: () -> str
|
||||
"""Format our exception message."""
|
||||
return self.FORMAT % {
|
||||
"name": self.plugin["plugin_name"],
|
||||
|
|
@ -79,12 +86,13 @@ class PluginExecutionFailed(Flake8Exception):
|
|||
FORMAT = '"%(name)s" failed during execution due to "%(exc)s"'
|
||||
|
||||
def __init__(self, plugin, exception):
|
||||
# type: (Dict[str, str], Exception) -> None
|
||||
"""Utilize keyword arguments for message generation."""
|
||||
self.plugin = plugin
|
||||
self.original_exception = exception
|
||||
super(PluginExecutionFailed, self).__init__(plugin, exception)
|
||||
|
||||
def __str__(self):
|
||||
def __str__(self): # type: () -> str
|
||||
"""Format our exception message."""
|
||||
return self.FORMAT % {
|
||||
"name": self.plugin["plugin_name"],
|
||||
|
|
@ -99,40 +107,33 @@ class HookInstallationError(Flake8Exception):
|
|||
class GitHookAlreadyExists(HookInstallationError):
|
||||
"""Exception raised when the git pre-commit hook file already exists."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""Initialize the path attribute."""
|
||||
self.path = kwargs.pop("path")
|
||||
super(GitHookAlreadyExists, self).__init__(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
"""Provide a nice message regarding the exception."""
|
||||
msg = (
|
||||
def __init__(self, path): # type: (str) -> None
|
||||
"""Initialize the exception message from the `path`."""
|
||||
self.path = path
|
||||
tmpl = (
|
||||
"The Git pre-commit hook ({0}) already exists. To convince "
|
||||
"Flake8 to install the hook, please remove the existing "
|
||||
"hook."
|
||||
)
|
||||
return msg.format(self.path)
|
||||
super(GitHookAlreadyExists, self).__init__(tmpl.format(self.path))
|
||||
|
||||
|
||||
class MercurialHookAlreadyExists(HookInstallationError):
|
||||
"""Exception raised when a mercurial hook is already configured."""
|
||||
|
||||
hook_name = None
|
||||
hook_name = None # type: str
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, path, value): # type: (str, str) -> None
|
||||
"""Initialize the relevant attributes."""
|
||||
self.path = kwargs.pop("path")
|
||||
self.value = kwargs.pop("value")
|
||||
super(MercurialHookAlreadyExists, self).__init__(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
"""Return a nicely formatted string for these errors."""
|
||||
msg = (
|
||||
self.path = path
|
||||
self.value = value
|
||||
tmpl = (
|
||||
'The Mercurial {0} hook already exists with "{1}" in {2}. '
|
||||
"To convince Flake8 to install the hook, please remove the "
|
||||
"{0} configuration from the [hooks] section of your hgrc."
|
||||
)
|
||||
return msg.format(self.hook_name, self.value, self.path)
|
||||
msg = tmpl.format(self.hook_name, self.value, self.path)
|
||||
super(MercurialHookAlreadyExists, self).__init__(msg)
|
||||
|
||||
|
||||
class MercurialCommitHookAlreadyExists(MercurialHookAlreadyExists):
|
||||
|
|
|
|||
|
|
@ -1,6 +1,13 @@
|
|||
"""The base class and interface for all formatting plugins."""
|
||||
from __future__ import print_function
|
||||
|
||||
import optparse
|
||||
from typing import IO, List, Optional, Tuple
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
from flake8.statistics import Statistics
|
||||
from flake8.style_guide import Violation
|
||||
|
||||
|
||||
class BaseFormatter(object):
|
||||
"""Class defining the formatter interface.
|
||||
|
|
@ -25,6 +32,7 @@ class BaseFormatter(object):
|
|||
"""
|
||||
|
||||
def __init__(self, options):
|
||||
# type: (optparse.Values) -> None
|
||||
"""Initialize with the options parsed from config and cli.
|
||||
|
||||
This also calls a hook, :meth:`after_init`, so subclasses do not need
|
||||
|
|
@ -36,33 +44,30 @@ class BaseFormatter(object):
|
|||
"""
|
||||
self.options = options
|
||||
self.filename = options.output_file
|
||||
self.output_fd = None
|
||||
self.output_fd = None # type: Optional[IO[str]]
|
||||
self.newline = "\n"
|
||||
self.after_init()
|
||||
|
||||
def after_init(self):
|
||||
def after_init(self): # type: () -> None
|
||||
"""Initialize the formatter further."""
|
||||
pass
|
||||
|
||||
def beginning(self, filename):
|
||||
def beginning(self, filename): # type: (str) -> None
|
||||
"""Notify the formatter that we're starting to process a file.
|
||||
|
||||
:param str filename:
|
||||
The name of the file that Flake8 is beginning to report results
|
||||
from.
|
||||
"""
|
||||
pass
|
||||
|
||||
def finished(self, filename):
|
||||
def finished(self, filename): # type: (str) -> None
|
||||
"""Notify the formatter that we've finished processing a file.
|
||||
|
||||
:param str filename:
|
||||
The name of the file that Flake8 has finished reporting results
|
||||
from.
|
||||
"""
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
def start(self): # type: () -> None
|
||||
"""Prepare the formatter to receive input.
|
||||
|
||||
This defaults to initializing :attr:`output_fd` if :attr:`filename`
|
||||
|
|
@ -70,7 +75,7 @@ class BaseFormatter(object):
|
|||
if self.filename:
|
||||
self.output_fd = open(self.filename, "a")
|
||||
|
||||
def handle(self, error):
|
||||
def handle(self, error): # type: (Violation) -> None
|
||||
"""Handle an error reported by Flake8.
|
||||
|
||||
This defaults to calling :meth:`format`, :meth:`show_source`, and
|
||||
|
|
@ -87,7 +92,7 @@ class BaseFormatter(object):
|
|||
source = self.show_source(error)
|
||||
self.write(line, source)
|
||||
|
||||
def format(self, error):
|
||||
def format(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Format an error reported by Flake8.
|
||||
|
||||
This method **must** be implemented by subclasses.
|
||||
|
|
@ -106,7 +111,7 @@ class BaseFormatter(object):
|
|||
"Subclass of BaseFormatter did not implement" " format."
|
||||
)
|
||||
|
||||
def show_statistics(self, statistics):
|
||||
def show_statistics(self, statistics): # type: (Statistics) -> None
|
||||
"""Format and print the statistics."""
|
||||
for error_code in statistics.error_codes():
|
||||
stats_for_error_code = statistics.statistics_for(error_code)
|
||||
|
|
@ -122,6 +127,7 @@ class BaseFormatter(object):
|
|||
)
|
||||
|
||||
def show_benchmarks(self, benchmarks):
|
||||
# type: (List[Tuple[str, float]]) -> None
|
||||
"""Format and print the benchmarks."""
|
||||
# NOTE(sigmavirus24): The format strings are a little confusing, even
|
||||
# to me, so here's a quick explanation:
|
||||
|
|
@ -142,7 +148,7 @@ class BaseFormatter(object):
|
|||
benchmark = float_format(statistic=statistic, value=value)
|
||||
self._write(benchmark)
|
||||
|
||||
def show_source(self, error):
|
||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Show the physical line generating the error.
|
||||
|
||||
This also adds an indicator for the particular part of the line that
|
||||
|
|
@ -170,7 +176,7 @@ class BaseFormatter(object):
|
|||
# one
|
||||
return error.physical_line + pointer
|
||||
|
||||
def _write(self, output):
|
||||
def _write(self, output): # type: (str) -> None
|
||||
"""Handle logic of whether to use an output file or print()."""
|
||||
if self.output_fd is not None:
|
||||
self.output_fd.write(output + self.newline)
|
||||
|
|
@ -178,6 +184,7 @@ class BaseFormatter(object):
|
|||
print(output, end=self.newline)
|
||||
|
||||
def write(self, line, source):
|
||||
# type: (Optional[str], Optional[str]) -> None
|
||||
"""Write the line either to the output file or stdout.
|
||||
|
||||
This handles deciding whether to write to a file or print to standard
|
||||
|
|
@ -195,7 +202,7 @@ class BaseFormatter(object):
|
|||
if source:
|
||||
self._write(source)
|
||||
|
||||
def stop(self):
|
||||
def stop(self): # type: () -> None
|
||||
"""Clean up after reporting is finished."""
|
||||
if self.output_fd is not None:
|
||||
self.output_fd.close()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
"""Default formatting class for Flake8."""
|
||||
from typing import Optional, Set
|
||||
|
||||
from flake8.formatting import base
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
from flake8.style_guide import Violation
|
||||
|
||||
|
||||
class SimpleFormatter(base.BaseFormatter):
|
||||
"""Simple abstraction for Default and Pylint formatter commonality.
|
||||
|
|
@ -18,9 +23,9 @@ class SimpleFormatter(base.BaseFormatter):
|
|||
|
||||
"""
|
||||
|
||||
error_format = None
|
||||
error_format = None # type: str
|
||||
|
||||
def format(self, error):
|
||||
def format(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Format and write error out.
|
||||
|
||||
If an output filename is specified, write formatted errors to that
|
||||
|
|
@ -44,7 +49,7 @@ class Default(SimpleFormatter):
|
|||
|
||||
error_format = "%(path)s:%(row)d:%(col)d: %(code)s %(text)s"
|
||||
|
||||
def after_init(self):
|
||||
def after_init(self): # type: () -> None
|
||||
"""Check for a custom format string."""
|
||||
if self.options.format.lower() != "default":
|
||||
self.error_format = self.options.format
|
||||
|
|
@ -61,28 +66,27 @@ class FilenameOnly(SimpleFormatter):
|
|||
|
||||
error_format = "%(path)s"
|
||||
|
||||
def after_init(self):
|
||||
def after_init(self): # type: () -> None
|
||||
"""Initialize our set of filenames."""
|
||||
self.filenames_already_printed = set()
|
||||
self.filenames_already_printed = set() # type: Set[str]
|
||||
|
||||
def show_source(self, error):
|
||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Do not include the source code."""
|
||||
pass
|
||||
|
||||
def format(self, error):
|
||||
def format(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Ensure we only print each error once."""
|
||||
if error.filename not in self.filenames_already_printed:
|
||||
self.filenames_already_printed.add(error.filename)
|
||||
return super(FilenameOnly, self).format(error)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Nothing(base.BaseFormatter):
|
||||
"""Print absolutely nothing."""
|
||||
|
||||
def format(self, error):
|
||||
def format(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Do nothing."""
|
||||
pass
|
||||
|
||||
def show_source(self, error):
|
||||
def show_source(self, error): # type: (Violation) -> Optional[str]
|
||||
"""Do not print the source."""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import optparse
|
||||
import sys
|
||||
import time
|
||||
from typing import List, Optional
|
||||
from typing import Dict, List, Optional, Set
|
||||
|
||||
import flake8
|
||||
from flake8 import checker
|
||||
|
|
@ -18,11 +19,8 @@ from flake8.options import manager
|
|||
from flake8.plugins import manager as plugin_manager
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
# fmt: off
|
||||
# `typing.Type` as introduced in 3.5.2
|
||||
from typing import Type # noqa: F401 (until flake8 3.7)
|
||||
from flake8.formatting.base import BaseFormatter # noqa: F401, E501 (until flake8 3.7)
|
||||
# fmt: on
|
||||
from typing import Type # `typing.Type` was introduced in 3.5.2
|
||||
from flake8.formatting.base import BaseFormatter
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
|
@ -32,7 +30,6 @@ class Application(object):
|
|||
"""Abstract our application into a class."""
|
||||
|
||||
def __init__(self, program="flake8", version=flake8.__version__):
|
||||
# type: (str, str) -> None
|
||||
"""Initialize our application.
|
||||
|
||||
:param str program:
|
||||
|
|
@ -43,7 +40,7 @@ class Application(object):
|
|||
#: The timestamp when the Application instance was instantiated.
|
||||
self.start_time = time.time()
|
||||
#: The timestamp when the Application finished reported errors.
|
||||
self.end_time = None
|
||||
self.end_time = None # type: float
|
||||
#: The name of the program being run
|
||||
self.program = program
|
||||
#: The version of the program being run
|
||||
|
|
@ -56,33 +53,35 @@ class Application(object):
|
|||
options.register_default_options(self.option_manager)
|
||||
#: The preliminary options parsed from CLI before plugins are loaded,
|
||||
#: into a :class:`optparse.Values` instance
|
||||
self.prelim_opts = None
|
||||
self.prelim_opts = None # type: optparse.Values
|
||||
#: The preliminary arguments parsed from CLI before plugins are loaded
|
||||
self.prelim_args = None
|
||||
self.prelim_args = None # type: List[str]
|
||||
#: The instance of :class:`flake8.options.config.ConfigFileFinder`
|
||||
self.config_finder = None
|
||||
|
||||
#: The :class:`flake8.options.config.LocalPlugins` found in config
|
||||
self.local_plugins = None
|
||||
self.local_plugins = None # type: config.LocalPlugins
|
||||
#: The instance of :class:`flake8.plugins.manager.Checkers`
|
||||
self.check_plugins = None
|
||||
self.check_plugins = None # type: plugin_manager.Checkers
|
||||
# fmt: off
|
||||
#: The instance of :class:`flake8.plugins.manager.ReportFormatters`
|
||||
self.formatting_plugins = None
|
||||
self.formatting_plugins = None # type: plugin_manager.ReportFormatters
|
||||
# fmt: on
|
||||
#: The user-selected formatter from :attr:`formatting_plugins`
|
||||
self.formatter = None
|
||||
self.formatter = None # type: BaseFormatter
|
||||
#: The :class:`flake8.style_guide.StyleGuideManager` built from the
|
||||
#: user's options
|
||||
self.guide = None
|
||||
self.guide = None # type: style_guide.StyleGuideManager
|
||||
#: The :class:`flake8.checker.Manager` that will handle running all of
|
||||
#: the checks selected by the user.
|
||||
self.file_checker_manager = None
|
||||
self.file_checker_manager = None # type: checker.Manager
|
||||
|
||||
#: The user-supplied options parsed into an instance of
|
||||
#: :class:`optparse.Values`
|
||||
self.options = None
|
||||
self.options = None # type: optparse.Values
|
||||
#: The left over arguments that were not parsed by
|
||||
#: :attr:`option_manager`
|
||||
self.args = None
|
||||
self.args = None # type: List[str]
|
||||
#: The number of errors, warnings, and other messages after running
|
||||
#: flake8 and taking into account ignored errors and lines.
|
||||
self.result_count = 0
|
||||
|
|
@ -96,7 +95,7 @@ class Application(object):
|
|||
#: Whether the program is processing a diff or not
|
||||
self.running_against_diff = False
|
||||
#: The parsed diff information
|
||||
self.parsed_diff = {}
|
||||
self.parsed_diff = {} # type: Dict[str, Set[int]]
|
||||
|
||||
def parse_preliminary_options_and_args(self, argv=None):
|
||||
# type: (Optional[List[str]]) -> None
|
||||
|
|
|
|||
|
|
@ -90,9 +90,7 @@ def install():
|
|||
os.path.join(hooks_directory, "pre-commit")
|
||||
)
|
||||
if os.path.exists(pre_commit_file):
|
||||
raise exceptions.GitHookAlreadyExists(
|
||||
"File already exists", path=pre_commit_file
|
||||
)
|
||||
raise exceptions.GitHookAlreadyExists(path=pre_commit_file)
|
||||
|
||||
executable = get_executable()
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import configparser
|
||||
import os
|
||||
import subprocess
|
||||
from typing import Set
|
||||
|
||||
from flake8 import exceptions as exc
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ def install():
|
|||
|
||||
|
||||
def get_filenames_from(repository, kwargs):
|
||||
seen_filenames = set()
|
||||
seen_filenames = set() # type: Set[str]
|
||||
node = kwargs["node"]
|
||||
for revision in range(repository[node], len(repository)):
|
||||
for filename in repository[revision].files():
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"""The logic for Flake8's integration with setuptools."""
|
||||
import os
|
||||
from typing import List
|
||||
from typing import List, Tuple
|
||||
|
||||
import setuptools
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class Flake8(setuptools.Command):
|
|||
|
||||
def package_files(self):
|
||||
"""Collect the files/dirs included in the registered modules."""
|
||||
seen_package_directories = ()
|
||||
seen_package_directories = () # type: Tuple[str, ...]
|
||||
directories = self.distribution.package_dir or {}
|
||||
empty_directory_exists = "" in directories
|
||||
packages = self.distribution.packages or []
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ def install(option, option_string, value, parser):
|
|||
For more information about the callback signature, see:
|
||||
https://docs.python.org/3/library/optparse.html#optparse-option-callbacks
|
||||
"""
|
||||
installer = _INSTALLERS.get(value)
|
||||
installer = _INSTALLERS[value]
|
||||
errored = False
|
||||
successful = False
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import configparser
|
|||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
from typing import Dict, List, Sequence, Tuple, Union
|
||||
|
||||
from flake8 import utils
|
||||
|
||||
|
|
@ -54,12 +55,15 @@ class ConfigFileFinder(object):
|
|||
|
||||
# caches to avoid double-reading config files
|
||||
self._local_configs = None
|
||||
self._local_found_files = []
|
||||
self._local_found_files = [] # type: List[str]
|
||||
self._user_config = None
|
||||
self._cli_configs = {}
|
||||
# fmt: off
|
||||
self._cli_configs = {} # type: Dict[str, configparser.RawConfigParser]
|
||||
# fmt: on
|
||||
|
||||
@staticmethod
|
||||
def _read_config(files):
|
||||
# type: (Union[Sequence[str], str]) -> Tuple[configparser.RawConfigParser, List[str]] # noqa: E501
|
||||
config = configparser.RawConfigParser()
|
||||
if isinstance(files, (str, type(u""))):
|
||||
files = [files]
|
||||
|
|
@ -83,6 +87,7 @@ class ConfigFileFinder(object):
|
|||
return (config, found_files)
|
||||
|
||||
def cli_config(self, files):
|
||||
# type: (str) -> configparser.RawConfigParser
|
||||
"""Read and parse the config file specified on the command-line."""
|
||||
if files not in self._cli_configs:
|
||||
config, found_files = self._read_config(files)
|
||||
|
|
@ -379,7 +384,7 @@ def get_local_plugins(config_finder, cli_config=None, isolated=False):
|
|||
raw_paths = utils.parse_comma_separated_list(
|
||||
config.get(section, "paths").strip()
|
||||
)
|
||||
norm_paths = []
|
||||
norm_paths = [] # type: List[str]
|
||||
for base_dir in base_dirs:
|
||||
norm_paths.extend(
|
||||
path
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import collections
|
||||
import logging
|
||||
import optparse # pylint: disable=deprecated-module
|
||||
from typing import Any, Callable, Dict, List, Optional, Set
|
||||
|
||||
from flake8 import utils
|
||||
|
||||
|
|
@ -108,7 +109,7 @@ class Option(object):
|
|||
self.comma_separated_list = comma_separated_list
|
||||
self.normalize_paths = normalize_paths
|
||||
|
||||
self.config_name = None
|
||||
self.config_name = None # type: Optional[str]
|
||||
if parse_from_config:
|
||||
if not long_option_name:
|
||||
raise ValueError(
|
||||
|
|
@ -143,7 +144,7 @@ class Option(object):
|
|||
"""Normalize the value based on the option configuration."""
|
||||
if self.normalize_paths:
|
||||
# Decide whether to parse a list of paths or a single path
|
||||
normalize = utils.normalize_path
|
||||
normalize = utils.normalize_path # type: Callable[..., Any]
|
||||
if self.comma_separated_list:
|
||||
normalize = utils.normalize_paths
|
||||
return normalize(value, *normalize_args)
|
||||
|
|
@ -200,13 +201,13 @@ class OptionManager(object):
|
|||
self.parser = optparse.OptionParser(
|
||||
prog=prog, version=version, usage=usage
|
||||
)
|
||||
self.config_options_dict = {}
|
||||
self.options = []
|
||||
self.config_options_dict = {} # type: Dict[str, Option]
|
||||
self.options = [] # type: List[Option]
|
||||
self.program_name = prog
|
||||
self.version = version
|
||||
self.registered_plugins = set()
|
||||
self.extended_default_ignore = set()
|
||||
self.extended_default_select = set()
|
||||
self.registered_plugins = set() # type: Set[PluginVersion]
|
||||
self.extended_default_ignore = set() # type: Set[str]
|
||||
self.extended_default_select = set() # type: Set[str]
|
||||
|
||||
@staticmethod
|
||||
def format_plugin(plugin):
|
||||
|
|
@ -231,6 +232,7 @@ class OptionManager(object):
|
|||
self.options.append(option)
|
||||
if option.parse_from_config:
|
||||
name = option.config_name
|
||||
assert name is not None # nosec (for mypy)
|
||||
self.config_options_dict[name] = option
|
||||
self.config_options_dict[name.replace("_", "-")] = option
|
||||
LOG.debug('Registered option "%s".', option)
|
||||
|
|
@ -326,7 +328,7 @@ class OptionManager(object):
|
|||
values = self.parser.get_default_values()
|
||||
|
||||
self.parser.rargs = rargs
|
||||
self.parser.largs = largs = []
|
||||
largs = [] # type: List[str]
|
||||
self.parser.values = values
|
||||
|
||||
while rargs:
|
||||
|
|
@ -340,7 +342,8 @@ class OptionManager(object):
|
|||
optparse.BadOptionError,
|
||||
optparse.OptionValueError,
|
||||
) as err:
|
||||
self.parser.largs.append(err.opt_str)
|
||||
# TODO: https://gitlab.com/pycqa/flake8/issues/541
|
||||
largs.append(err.opt_str) # type: ignore
|
||||
|
||||
args = largs + rargs
|
||||
options, xargs = self.parser.check_values(values, args)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,12 @@
|
|||
"""Plugin loading and management logic and classes."""
|
||||
import logging
|
||||
import sys
|
||||
from typing import Any, Dict, List, Set
|
||||
|
||||
import entrypoints
|
||||
|
||||
from flake8 import exceptions
|
||||
from flake8 import utils
|
||||
|
||||
if sys.version_info >= (3, 3):
|
||||
import collections.abc as collections_abc
|
||||
else:
|
||||
import collections as collections_abc
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
__all__ = ("Checkers", "Plugin", "PluginManager", "ReportFormatters")
|
||||
|
|
@ -37,7 +32,7 @@ class Plugin(object):
|
|||
self.name = name
|
||||
self.entry_point = entry_point
|
||||
self.local = local
|
||||
self._plugin = None
|
||||
self._plugin = None # type: Any
|
||||
self._parameters = None
|
||||
self._parameter_names = None
|
||||
self._group = None
|
||||
|
|
@ -236,8 +231,8 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
|
|||
Plugins from config (as "X = path.to:Plugin" strings).
|
||||
"""
|
||||
self.namespace = namespace
|
||||
self.plugins = {}
|
||||
self.names = []
|
||||
self.plugins = {} # type: Dict[str, Plugin]
|
||||
self.names = [] # type: List[str]
|
||||
self._load_local_plugins(local_plugins or [])
|
||||
self._load_entrypoint_plugins()
|
||||
|
||||
|
|
@ -310,7 +305,7 @@ class PluginManager(object): # pylint: disable=too-few-public-methods
|
|||
:rtype:
|
||||
tuple
|
||||
"""
|
||||
plugins_seen = set()
|
||||
plugins_seen = set() # type: Set[str]
|
||||
for entry_point_name in self.names:
|
||||
plugin = self.plugins[entry_point_name]
|
||||
plugin_name = plugin.plugin_name
|
||||
|
|
@ -345,7 +340,7 @@ def version_for(plugin):
|
|||
class PluginTypeManager(object):
|
||||
"""Parent class for most of the specific plugin types."""
|
||||
|
||||
namespace = None
|
||||
namespace = None # type: str
|
||||
|
||||
def __init__(self, local_plugins=None):
|
||||
"""Initialize the plugin type's manager.
|
||||
|
|
@ -398,9 +393,7 @@ class PluginTypeManager(object):
|
|||
def _generate_call_function(method_name, optmanager, *args, **kwargs):
|
||||
def generated_function(plugin): # noqa: D105
|
||||
method = getattr(plugin, method_name, None)
|
||||
if method is not None and isinstance(
|
||||
method, collections_abc.Callable
|
||||
):
|
||||
if method is not None and callable(method):
|
||||
return method(optmanager, *args, **kwargs)
|
||||
|
||||
return generated_function
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ except ImportError:
|
|||
else:
|
||||
demandimport.disable()
|
||||
import os
|
||||
from typing import List
|
||||
|
||||
import pyflakes
|
||||
import pyflakes.checker
|
||||
|
|
@ -59,8 +60,8 @@ class FlakesChecker(pyflakes.checker.Checker):
|
|||
name = "pyflakes"
|
||||
version = pyflakes.__version__
|
||||
with_doctest = False
|
||||
include_in_doctest = []
|
||||
exclude_from_doctest = []
|
||||
include_in_doctest = [] # type: List[str]
|
||||
exclude_from_doctest = [] # type: List[str]
|
||||
|
||||
def __init__(self, tree, file_tokens, filename):
|
||||
"""Initialize the PyFlakes plugin with an AST tree and filename."""
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import contextlib
|
|||
import logging
|
||||
import sys
|
||||
import tokenize
|
||||
from typing import List
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
import flake8
|
||||
from flake8 import defaults
|
||||
|
|
@ -66,9 +66,9 @@ class FileProcessor(object):
|
|||
#: Number of blank lines
|
||||
self.blank_lines = 0
|
||||
#: Checker states for each plugin?
|
||||
self._checker_states = {}
|
||||
self._checker_states = {} # type: Dict[str, Dict[Any, Any]]
|
||||
#: Current checker state
|
||||
self.checker_state = None
|
||||
self.checker_state = None # type: Dict[Any, Any]
|
||||
#: User provided option for hang closing
|
||||
self.hang_closing = options.hang_closing
|
||||
#: Character used for indentation
|
||||
|
|
@ -93,8 +93,10 @@ class FileProcessor(object):
|
|||
self.previous_logical = ""
|
||||
#: Previous unindented (i.e. top-level) logical line
|
||||
self.previous_unindented_logical_line = ""
|
||||
# fmt: off
|
||||
#: Current set of tokens
|
||||
self.tokens = []
|
||||
self.tokens = [] # type: List[Tuple[int, str, Tuple[int, int], Tuple[int, int], str]] # noqa: E501
|
||||
# fmt: on
|
||||
#: Total number of lines in the file
|
||||
self.total_lines = len(self.lines)
|
||||
#: Verbosity level of Flake8
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
"""Statistic collection logic for Flake8."""
|
||||
import collections
|
||||
from typing import Dict, Generator, List, Optional
|
||||
|
||||
if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
||||
from flake8.style_guide import Violation
|
||||
|
||||
|
||||
class Statistics(object):
|
||||
"""Manager of aggregated statistics for a run of Flake8."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self): # type: () -> None
|
||||
"""Initialize the underlying dictionary for our statistics."""
|
||||
self._store = {}
|
||||
self._store = {} # type: Dict[Key, Statistic]
|
||||
|
||||
def error_codes(self):
|
||||
def error_codes(self): # type: () -> List[str]
|
||||
"""Return all unique error codes stored.
|
||||
|
||||
:returns:
|
||||
|
|
@ -19,7 +23,7 @@ class Statistics(object):
|
|||
"""
|
||||
return sorted({key.code for key in self._store})
|
||||
|
||||
def record(self, error):
|
||||
def record(self, error): # type: (Violation) -> None
|
||||
"""Add the fact that the error was seen in the file.
|
||||
|
||||
:param error:
|
||||
|
|
@ -34,6 +38,7 @@ class Statistics(object):
|
|||
self._store[key].increment()
|
||||
|
||||
def statistics_for(self, prefix, filename=None):
|
||||
# type: (str, Optional[str]) -> Generator[Statistic, None, None]
|
||||
"""Generate statistics for the prefix and filename.
|
||||
|
||||
If you have a :class:`Statistics` object that has recorded errors,
|
||||
|
|
@ -74,11 +79,11 @@ class Key(collections.namedtuple("Key", ["filename", "code"])):
|
|||
__slots__ = ()
|
||||
|
||||
@classmethod
|
||||
def create_from(cls, error):
|
||||
def create_from(cls, error): # type: (Violation) -> Key
|
||||
"""Create a Key from :class:`flake8.style_guide.Violation`."""
|
||||
return cls(filename=error.filename, code=error.code)
|
||||
|
||||
def matches(self, prefix, filename):
|
||||
def matches(self, prefix, filename): # type: (str, Optional[str]) -> bool
|
||||
"""Determine if this key matches some constraints.
|
||||
|
||||
:param str prefix:
|
||||
|
|
@ -106,6 +111,7 @@ class Statistic(object):
|
|||
"""
|
||||
|
||||
def __init__(self, error_code, filename, message, count):
|
||||
# type: (str, str, str, int) -> None
|
||||
"""Initialize our Statistic."""
|
||||
self.error_code = error_code
|
||||
self.filename = filename
|
||||
|
|
@ -113,7 +119,7 @@ class Statistic(object):
|
|||
self.count = count
|
||||
|
||||
@classmethod
|
||||
def create_from(cls, error):
|
||||
def create_from(cls, error): # type: (Violation) -> Statistic
|
||||
"""Create a Statistic from a :class:`flake8.style_guide.Violation`."""
|
||||
return cls(
|
||||
error_code=error.code,
|
||||
|
|
@ -122,6 +128,6 @@ class Statistic(object):
|
|||
count=0,
|
||||
)
|
||||
|
||||
def increment(self):
|
||||
def increment(self): # type: () -> None
|
||||
"""Increment the number of times we've seen this error in this file."""
|
||||
self.count += 1
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import itertools
|
|||
import linecache
|
||||
import logging
|
||||
import sys
|
||||
from typing import Optional, Union
|
||||
from typing import Dict, List, Optional, Set, Union
|
||||
|
||||
from flake8 import defaults
|
||||
from flake8 import statistics
|
||||
|
|
@ -68,7 +68,7 @@ class Violation(_Violation):
|
|||
"""Class representing a violation reported by Flake8."""
|
||||
|
||||
def is_inline_ignored(self, disable_noqa):
|
||||
# type: (Violation) -> bool
|
||||
# type: (bool) -> bool
|
||||
"""Determine if a comment has been added to ignore this line.
|
||||
|
||||
:param bool disable_noqa:
|
||||
|
|
@ -154,7 +154,7 @@ class DecisionEngine(object):
|
|||
|
||||
def __init__(self, options):
|
||||
"""Initialize the engine."""
|
||||
self.cache = {}
|
||||
self.cache = {} # type: Dict[str, Decision]
|
||||
self.selected = tuple(options.select)
|
||||
self.extended_selected = tuple(
|
||||
sorted(options.extended_default_select, reverse=True)
|
||||
|
|
@ -332,7 +332,7 @@ class StyleGuideManager(object):
|
|||
self.formatter = formatter
|
||||
self.stats = statistics.Statistics()
|
||||
self.decider = decider or DecisionEngine(options)
|
||||
self.style_guides = []
|
||||
self.style_guides = [] # type: List[StyleGuide]
|
||||
self.default_style_guide = StyleGuide(
|
||||
options, formatter, self.stats, decider=decider
|
||||
)
|
||||
|
|
@ -390,7 +390,7 @@ class StyleGuideManager(object):
|
|||
text,
|
||||
physical_line=None,
|
||||
):
|
||||
# type: (str, str, int, int, str, Optional[str]) -> int
|
||||
# type: (str, str, int, Optional[int], str, Optional[str]) -> int
|
||||
"""Handle an error reported by a check.
|
||||
|
||||
:param str code:
|
||||
|
|
@ -419,6 +419,7 @@ class StyleGuideManager(object):
|
|||
)
|
||||
|
||||
def add_diff_ranges(self, diffinfo):
|
||||
# type: (Dict[str, Set[int]]) -> None
|
||||
"""Update the StyleGuides to filter out information not in the diff.
|
||||
|
||||
This provides information to the underlying StyleGuides so that only
|
||||
|
|
@ -448,7 +449,7 @@ class StyleGuide(object):
|
|||
self.filename = filename
|
||||
if self.filename:
|
||||
self.filename = utils.normalize_path(self.filename)
|
||||
self._parsed_diff = {}
|
||||
self._parsed_diff = {} # type: Dict[str, Set[int]]
|
||||
|
||||
def __repr__(self):
|
||||
"""Make it easier to debug which StyleGuide we're using."""
|
||||
|
|
@ -514,7 +515,7 @@ class StyleGuide(object):
|
|||
text,
|
||||
physical_line=None,
|
||||
):
|
||||
# type: (str, str, int, int, str, Optional[str]) -> int
|
||||
# type: (str, str, int, Optional[int], str, Optional[str]) -> int
|
||||
"""Handle an error reported by a check.
|
||||
|
||||
:param str code:
|
||||
|
|
@ -567,6 +568,7 @@ class StyleGuide(object):
|
|||
return 0
|
||||
|
||||
def add_diff_ranges(self, diffinfo):
|
||||
# type: (Dict[str, Set[int]]) -> None
|
||||
"""Update the StyleGuide to filter out information not in the diff.
|
||||
|
||||
This provides information to the StyleGuide so that only the errors
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@ import collections
|
|||
import fnmatch as _fnmatch
|
||||
import inspect
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import tokenize
|
||||
from typing import Callable, Dict, Generator, List, Pattern, Sequence, Set
|
||||
from typing import Tuple, Union
|
||||
from typing import Callable, Dict, Generator, List, Optional, Pattern
|
||||
from typing import Sequence, Set, Tuple, Union
|
||||
|
||||
from flake8 import exceptions
|
||||
|
||||
|
|
@ -19,6 +20,7 @@ if False: # `typing.TYPE_CHECKING` was introduced in 3.5.2
|
|||
DIFF_HUNK_REGEXP = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$")
|
||||
COMMA_SEPARATED_LIST_RE = re.compile(r"[,\s]")
|
||||
LOCAL_PLUGIN_LIST_RE = re.compile(r"[,\t\n\r\f\v]")
|
||||
string_types = (str, type(u""))
|
||||
|
||||
|
||||
def parse_comma_separated_list(value, regexp=COMMA_SEPARATED_LIST_RE):
|
||||
|
|
@ -40,7 +42,7 @@ def parse_comma_separated_list(value, regexp=COMMA_SEPARATED_LIST_RE):
|
|||
if not value:
|
||||
return []
|
||||
|
||||
if not isinstance(value, (list, tuple)):
|
||||
if isinstance(value, string_types):
|
||||
value = regexp.split(value)
|
||||
|
||||
item_gen = (item.strip() for item in value)
|
||||
|
|
@ -77,8 +79,8 @@ def _tokenize_files_to_codes_mapping(value):
|
|||
return tokens
|
||||
|
||||
|
||||
def parse_files_to_codes_mapping(value): # noqa: C901
|
||||
# type: (Union[Sequence[str], str]) -> List[Tuple[List[str], List[str]]]
|
||||
def parse_files_to_codes_mapping(value_): # noqa: C901
|
||||
# type: (Union[Sequence[str], str]) -> List[Tuple[str, List[str]]]
|
||||
"""Parse a files-to-codes maping.
|
||||
|
||||
A files-to-codes mapping a sequence of values specified as
|
||||
|
|
@ -88,20 +90,22 @@ def parse_files_to_codes_mapping(value): # noqa: C901
|
|||
:param value: String to be parsed and normalized.
|
||||
:type value: str
|
||||
"""
|
||||
if isinstance(value, (list, tuple)):
|
||||
value = "\n".join(value)
|
||||
if not isinstance(value_, string_types):
|
||||
value = "\n".join(value_)
|
||||
else:
|
||||
value = value_
|
||||
|
||||
ret = []
|
||||
ret = [] # type: List[Tuple[str, List[str]]]
|
||||
if not value.strip():
|
||||
return ret
|
||||
|
||||
class State:
|
||||
seen_sep = True
|
||||
seen_colon = False
|
||||
filenames = []
|
||||
codes = []
|
||||
filenames = [] # type: List[str]
|
||||
codes = [] # type: List[str]
|
||||
|
||||
def _reset():
|
||||
def _reset(): # type: () -> None
|
||||
if State.codes:
|
||||
for filename in State.filenames:
|
||||
ret.append((filename, State.codes))
|
||||
|
|
@ -110,11 +114,8 @@ def parse_files_to_codes_mapping(value): # noqa: C901
|
|||
State.filenames = []
|
||||
State.codes = []
|
||||
|
||||
def _unexpected_token():
|
||||
# type: () -> exceptions.ExecutionError
|
||||
|
||||
def _indent(s):
|
||||
# type: (str) -> str
|
||||
def _unexpected_token(): # type: () -> exceptions.ExecutionError
|
||||
def _indent(s): # type: (str) -> str
|
||||
return " " + s.strip().replace("\n", "\n ")
|
||||
|
||||
return exceptions.ExecutionError(
|
||||
|
|
@ -192,7 +193,7 @@ def normalize_path(path, parent=os.curdir):
|
|||
return path.rstrip(separator + alternate_separator)
|
||||
|
||||
|
||||
def _stdin_get_value_py3():
|
||||
def _stdin_get_value_py3(): # type: () -> io.StringIO
|
||||
stdin_value = sys.stdin.buffer.read()
|
||||
fd = io.BytesIO(stdin_value)
|
||||
try:
|
||||
|
|
@ -211,13 +212,13 @@ def stdin_get_value():
|
|||
stdin_value = io.BytesIO(sys.stdin.read())
|
||||
else:
|
||||
stdin_value = _stdin_get_value_py3()
|
||||
stdin_get_value.cached_stdin = stdin_value
|
||||
cached_value = stdin_get_value.cached_stdin
|
||||
stdin_get_value.cached_stdin = stdin_value # type: ignore
|
||||
cached_value = stdin_get_value.cached_stdin # type: ignore
|
||||
return cached_value.getvalue()
|
||||
|
||||
|
||||
def parse_unified_diff(diff=None):
|
||||
# type: (str) -> Dict[str, Set[int]]
|
||||
# type: (Optional[str]) -> Dict[str, Set[int]]
|
||||
"""Parse the unified diff passed on stdin.
|
||||
|
||||
:returns:
|
||||
|
|
@ -231,7 +232,7 @@ def parse_unified_diff(diff=None):
|
|||
|
||||
number_of_rows = None
|
||||
current_path = None
|
||||
parsed_paths = collections.defaultdict(set)
|
||||
parsed_paths = collections.defaultdict(set) # type: Dict[str, Set[int]]
|
||||
for line in diff.splitlines():
|
||||
if number_of_rows:
|
||||
# NOTE(sigmavirus24): Below we use a slice because stdin may be
|
||||
|
|
@ -279,6 +280,7 @@ def parse_unified_diff(diff=None):
|
|||
1 if not group else int(group)
|
||||
for group in hunk_match.groups()
|
||||
]
|
||||
assert current_path is not None # nosec (for mypy)
|
||||
parsed_paths[current_path].update(
|
||||
range(row, row + number_of_rows)
|
||||
)
|
||||
|
|
@ -338,12 +340,12 @@ def is_using_stdin(paths):
|
|||
return "-" in paths
|
||||
|
||||
|
||||
def _default_predicate(*args):
|
||||
def _default_predicate(*args): # type: (*str) -> bool
|
||||
return False
|
||||
|
||||
|
||||
def filenames_from(arg, predicate=None):
|
||||
# type: (str, Callable[[str], bool]) -> Generator
|
||||
# type: (str, Optional[Callable[[str], bool]]) -> Generator[str, None, None] # noqa: E501
|
||||
"""Generate filenames from an argument.
|
||||
|
||||
:param str arg:
|
||||
|
|
@ -384,8 +386,8 @@ def filenames_from(arg, predicate=None):
|
|||
yield arg
|
||||
|
||||
|
||||
def fnmatch(filename, patterns, default=True):
|
||||
# type: (str, List[str], bool) -> bool
|
||||
def fnmatch(filename, patterns):
|
||||
# type: (str, List[str]) -> bool
|
||||
"""Wrap :func:`fnmatch.fnmatch` to add some functionality.
|
||||
|
||||
:param str filename:
|
||||
|
|
@ -399,7 +401,7 @@ def fnmatch(filename, patterns, default=True):
|
|||
``default`` if patterns is empty.
|
||||
"""
|
||||
if not patterns:
|
||||
return default
|
||||
return True
|
||||
return any(_fnmatch.fnmatch(filename, pattern) for pattern in patterns)
|
||||
|
||||
|
||||
|
|
@ -452,6 +454,7 @@ def parameters_for(plugin):
|
|||
|
||||
|
||||
def matches_filename(path, patterns, log_message, logger):
|
||||
# type: (str, List[str], str, logging.Logger) -> bool
|
||||
"""Use fnmatch to discern if a path exists in patterns.
|
||||
|
||||
:param str path:
|
||||
|
|
@ -483,7 +486,7 @@ def matches_filename(path, patterns, log_message, logger):
|
|||
return match
|
||||
|
||||
|
||||
def get_python_version():
|
||||
def get_python_version(): # type: () -> str
|
||||
"""Find and format the python implementation and version.
|
||||
|
||||
:returns:
|
||||
|
|
|
|||
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
"""This is here because mypy doesn't understand PEP 420."""
|
||||
|
|
@ -216,9 +216,7 @@ def test_report_order(results, expected_order):
|
|||
|
||||
# _handle_results is the first place which gets the sorted result
|
||||
# Should something non-private be mocked instead?
|
||||
handler = mock.Mock()
|
||||
handler.side_effect = count_side_effect
|
||||
manager._handle_results = handler
|
||||
|
||||
assert manager.report() == (len(results), len(results))
|
||||
handler.assert_called_once_with('placeholder', expected_results)
|
||||
handler = mock.Mock(side_effect=count_side_effect)
|
||||
with mock.patch.object(manager, '_handle_results', handler):
|
||||
assert manager.report() == (len(results), len(results))
|
||||
handler.assert_called_once_with('placeholder', expected_results)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ def test_format_needs_to_be_implemented():
|
|||
"""Ensure BaseFormatter#format raises a NotImplementedError."""
|
||||
formatter = base.BaseFormatter(options())
|
||||
with pytest.raises(NotImplementedError):
|
||||
formatter.format('foo')
|
||||
formatter.format(
|
||||
style_guide.Violation('A000', 'file.py', 1, 1, 'error text', None)
|
||||
)
|
||||
|
||||
|
||||
def test_show_source_returns_nothing_when_not_showing_source():
|
||||
|
|
@ -73,6 +75,7 @@ def test_show_source_updates_physical_line_appropriately(line, column):
|
|||
formatter = base.BaseFormatter(options(show_source=True))
|
||||
error = style_guide.Violation('A000', 'file.py', 1, column, 'error', line)
|
||||
output = formatter.show_source(error)
|
||||
assert output
|
||||
_, pointer = output.rsplit('\n', 1)
|
||||
assert pointer.count(' ') == (column - 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -72,8 +72,7 @@ def test_information(system, pyversion, pyimpl):
|
|||
@mock.patch('json.dumps', return_value='{}')
|
||||
def test_print_information_no_plugins(dumps, information, print_mock):
|
||||
"""Verify we print and exit only when we have plugins."""
|
||||
plugins = []
|
||||
option_manager = mock.Mock(registered_plugins=set(plugins))
|
||||
option_manager = mock.Mock(registered_plugins=set())
|
||||
assert debug.print_information(
|
||||
None, None, None, None, option_manager=option_manager,
|
||||
) is None
|
||||
|
|
|
|||
|
|
@ -74,11 +74,10 @@ def test_was_selected_selects_errors(select_list, enable_extensions,
|
|||
|
||||
def test_was_selected_implicitly_selects_errors():
|
||||
"""Verify we detect users implicitly selecting an error."""
|
||||
select_list = []
|
||||
error_code = 'E121'
|
||||
decider = style_guide.DecisionEngine(
|
||||
create_options(
|
||||
select=select_list,
|
||||
select=[],
|
||||
extended_default_select=['E'],
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -75,4 +75,4 @@ def test_config_name_needs_long_option_name():
|
|||
def test_dest_is_not_overridden():
|
||||
"""Show that we do not override custom destinations."""
|
||||
opt = manager.Option('-s', '--short', dest='something_not_short')
|
||||
assert opt.dest == 'something_not_short'
|
||||
assert opt.dest == 'something_not_short' # type: ignore
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
"""Tests for flake8.plugins.manager.PluginTypeManager."""
|
||||
import sys
|
||||
|
||||
import mock
|
||||
import pytest
|
||||
|
||||
from flake8 import exceptions
|
||||
from flake8.plugins import manager
|
||||
|
||||
if sys.version_info >= (3, 3):
|
||||
import collections.abc as collections_abc
|
||||
else:
|
||||
import collections as collections_abc
|
||||
|
||||
TEST_NAMESPACE = "testing.plugin-type-manager"
|
||||
|
||||
|
||||
|
|
@ -91,7 +84,7 @@ def test_generate_call_function():
|
|||
'method_name', optmanager,
|
||||
)
|
||||
|
||||
assert isinstance(func, collections_abc.Callable)
|
||||
assert callable(func)
|
||||
assert func(plugin) is optmanager
|
||||
|
||||
|
||||
|
|
@ -168,15 +161,14 @@ def test_provide_options(PluginManager): # noqa: N803
|
|||
PluginManager.return_value = create_mapping_manager_mock(plugins)
|
||||
optmanager = object()
|
||||
options = object()
|
||||
extra_args = []
|
||||
|
||||
type_mgr = FakeTestType()
|
||||
type_mgr.provide_options(optmanager, options, extra_args)
|
||||
type_mgr.provide_options(optmanager, options, [])
|
||||
|
||||
for plugin in plugins:
|
||||
plugin.provide_options.assert_called_with(optmanager,
|
||||
options,
|
||||
extra_args)
|
||||
[])
|
||||
|
||||
|
||||
@mock.patch('flake8.plugins.manager.PluginManager')
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ def test_recording_statistics():
|
|||
assert isinstance(key, stats.Key)
|
||||
assert isinstance(value, stats.Statistic)
|
||||
|
||||
assert storage[(DEFAULT_FILENAME, DEFAULT_ERROR_CODE)].count == 1
|
||||
assert storage[stats.Key(DEFAULT_FILENAME, DEFAULT_ERROR_CODE)].count == 1
|
||||
|
||||
|
||||
def test_statistics_for_single_record():
|
||||
|
|
|
|||
|
|
@ -163,12 +163,6 @@ def test_fnmatch(filename, patterns, expected):
|
|||
assert utils.fnmatch(filename, patterns) is expected
|
||||
|
||||
|
||||
def test_fnmatch_returns_the_default_with_empty_default():
|
||||
"""The default parameter should be returned when no patterns are given."""
|
||||
sentinel = object()
|
||||
assert utils.fnmatch('file.py', [], default=sentinel) is sentinel
|
||||
|
||||
|
||||
def test_filenames_from_a_directory():
|
||||
"""Verify that filenames_from walks a directory."""
|
||||
filenames = list(utils.filenames_from('src/flake8/'))
|
||||
|
|
|
|||
7
tox.ini
7
tox.ini
|
|
@ -70,13 +70,12 @@ deps =
|
|||
commands =
|
||||
doc8 docs/source/
|
||||
|
||||
[testenv:mypy]
|
||||
[testenv:pre-commit]
|
||||
basepython = python3
|
||||
skip_install = true
|
||||
deps =
|
||||
mypy
|
||||
deps = pre-commit
|
||||
commands =
|
||||
mypy src
|
||||
pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
[testenv:bandit]
|
||||
basepython = python3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue