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