mirror of
https://github.com/PyCQA/flake8.git
synced 2026-04-10 06:44:18 +00:00
Merge branch 'christianmlong/issue/8'
This commit is contained in:
commit
a66815ffa6
6 changed files with 242 additions and 7 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import re
|
import re
|
||||||
import platform
|
import platform
|
||||||
|
import warnings
|
||||||
|
|
||||||
import pep8
|
import pep8
|
||||||
|
|
||||||
|
|
@ -8,7 +9,7 @@ from flake8 import __version__
|
||||||
from flake8 import callbacks
|
from flake8 import callbacks
|
||||||
from flake8.reporter import (multiprocessing, BaseQReport, FileQReport,
|
from flake8.reporter import (multiprocessing, BaseQReport, FileQReport,
|
||||||
QueueReport)
|
QueueReport)
|
||||||
from flake8.util import OrderedSet, is_windows, is_using_stdin
|
from flake8 import util
|
||||||
|
|
||||||
_flake8_noqa = re.compile(r'\s*# flake8[:=]\s*noqa', re.I).search
|
_flake8_noqa = re.compile(r'\s*# flake8[:=]\s*noqa', re.I).search
|
||||||
|
|
||||||
|
|
@ -17,7 +18,7 @@ EXTRA_EXCLUDE = ['.tox', '.eggs', '*.egg']
|
||||||
|
|
||||||
def _register_extensions():
|
def _register_extensions():
|
||||||
"""Register all the extensions."""
|
"""Register all the extensions."""
|
||||||
extensions = OrderedSet()
|
extensions = util.OrderedSet()
|
||||||
extensions.add(('pep8', pep8.__version__))
|
extensions.add(('pep8', pep8.__version__))
|
||||||
parser_hooks = []
|
parser_hooks = []
|
||||||
options_hooks = []
|
options_hooks = []
|
||||||
|
|
@ -123,10 +124,25 @@ def get_style_guide(**kwargs):
|
||||||
for options_hook in options_hooks:
|
for options_hook in options_hooks:
|
||||||
options_hook(options)
|
options_hook(options)
|
||||||
|
|
||||||
|
if util.warn_when_using_jobs(options):
|
||||||
|
if not multiprocessing:
|
||||||
|
warnings.warn("The multiprocessing module is not available. "
|
||||||
|
"Ignoring --jobs arguments.")
|
||||||
|
if util.is_windows():
|
||||||
|
warnings.warn("The --jobs option is not available on Windows. "
|
||||||
|
"Ignoring --jobs arguments.")
|
||||||
|
if util.is_using_stdin(styleguide.paths):
|
||||||
|
warnings.warn("The --jobs option is not compatible with supplying "
|
||||||
|
"input using - . Ignoring --jobs arguments.")
|
||||||
|
if options.diff:
|
||||||
|
warnings.warn("The --diff option was specified with --jobs but "
|
||||||
|
"they are not compatible. Ignoring --jobs arguments."
|
||||||
|
)
|
||||||
|
|
||||||
if options.diff:
|
if options.diff:
|
||||||
options.jobs = None
|
options.jobs = None
|
||||||
|
|
||||||
force_disable_jobs = is_windows() or is_using_stdin(styleguide.paths)
|
force_disable_jobs = util.force_disable_jobs(styleguide)
|
||||||
|
|
||||||
if multiprocessing and options.jobs and not force_disable_jobs:
|
if multiprocessing and options.jobs and not force_disable_jobs:
|
||||||
if options.jobs.isdigit():
|
if options.jobs.isdigit():
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ class TestEngine(unittest.TestCase):
|
||||||
with mock.patch('flake8.engine.get_parser') as get_parser:
|
with mock.patch('flake8.engine.get_parser') as get_parser:
|
||||||
m.ignored_extensions = []
|
m.ignored_extensions = []
|
||||||
StyleGuide.return_value.options.jobs = '42'
|
StyleGuide.return_value.options.jobs = '42'
|
||||||
|
StyleGuide.return_value.options.diff = False
|
||||||
get_parser.return_value = (m, [])
|
get_parser.return_value = (m, [])
|
||||||
engine.get_style_guide(foo='bar')
|
engine.get_style_guide(foo='bar')
|
||||||
get_parser.assert_called_once_with()
|
get_parser.assert_called_once_with()
|
||||||
|
|
@ -85,13 +86,13 @@ class TestEngine(unittest.TestCase):
|
||||||
# ourselves) what system we may be testing on.
|
# ourselves) what system we may be testing on.
|
||||||
|
|
||||||
def test_windows_disables_jobs(self):
|
def test_windows_disables_jobs(self):
|
||||||
with mock.patch('flake8.engine.is_windows') as is_windows:
|
with mock.patch('flake8.util.is_windows') as is_windows:
|
||||||
is_windows.return_value = True
|
is_windows.return_value = True
|
||||||
guide = engine.get_style_guide()
|
guide = engine.get_style_guide()
|
||||||
assert isinstance(guide, reporter.BaseQReport) is False
|
assert isinstance(guide, reporter.BaseQReport) is False
|
||||||
|
|
||||||
def test_stdin_disables_jobs(self):
|
def test_stdin_disables_jobs(self):
|
||||||
with mock.patch('flake8.engine.is_using_stdin') as is_using_stdin:
|
with mock.patch('flake8.util.is_using_stdin') as is_using_stdin:
|
||||||
is_using_stdin.return_value = True
|
is_using_stdin.return_value = True
|
||||||
guide = engine.get_style_guide()
|
guide = engine.get_style_guide()
|
||||||
assert isinstance(guide, reporter.BaseQReport) is False
|
assert isinstance(guide, reporter.BaseQReport) is False
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ except ImportError:
|
||||||
import mock # < PY33
|
import mock # < PY33
|
||||||
|
|
||||||
from flake8 import engine
|
from flake8 import engine
|
||||||
|
from flake8.util import is_windows
|
||||||
|
|
||||||
|
|
||||||
class IntegrationTestCase(unittest.TestCase):
|
class IntegrationTestCase(unittest.TestCase):
|
||||||
|
|
@ -41,8 +42,15 @@ class IntegrationTestCase(unittest.TestCase):
|
||||||
# mock stdout.flush so we can count the number of jobs created
|
# mock stdout.flush so we can count the number of jobs created
|
||||||
with mock.patch('sys.stdout.flush') as mocked:
|
with mock.patch('sys.stdout.flush') as mocked:
|
||||||
guide, report = self.check_files(arglist=['--jobs=%s' % jobs])
|
guide, report = self.check_files(arglist=['--jobs=%s' % jobs])
|
||||||
self.assertEqual(guide.options.jobs, jobs)
|
if is_windows():
|
||||||
self.assertEqual(mocked.call_count, jobs)
|
# The code path where guide.options.jobs gets converted to an
|
||||||
|
# int is not run on windows. So, do the int conversion here.
|
||||||
|
self.assertEqual(int(guide.options.jobs), jobs)
|
||||||
|
# On windows, call count is always zero.
|
||||||
|
self.assertEqual(mocked.call_count, 0)
|
||||||
|
else:
|
||||||
|
self.assertEqual(guide.options.jobs, jobs)
|
||||||
|
self.assertEqual(mocked.call_count, jobs)
|
||||||
|
|
||||||
def test_jobs(self):
|
def test_jobs(self):
|
||||||
self._job_tester(2)
|
self._job_tester(2)
|
||||||
|
|
|
||||||
200
flake8/tests/test_warnings.py
Normal file
200
flake8/tests/test_warnings.py
Normal file
|
|
@ -0,0 +1,200 @@
|
||||||
|
"""
|
||||||
|
_test_warnings.py
|
||||||
|
|
||||||
|
Tests for the warnings that are emitted by flake8.
|
||||||
|
|
||||||
|
This module is named _test_warnings instead of test_warnings so that a
|
||||||
|
normal nosetests run does not collect it. The tests in this module pass
|
||||||
|
when they are run alone, but they fail when they are run along with other
|
||||||
|
tests (nosetests --with-isolation doesn't help).
|
||||||
|
|
||||||
|
In tox.ini, these tests are run separately.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
|
import os
|
||||||
|
import warnings
|
||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from unittest import mock
|
||||||
|
except ImportError:
|
||||||
|
import mock # < PY33
|
||||||
|
|
||||||
|
from flake8 import engine
|
||||||
|
from flake8.util import is_windows
|
||||||
|
|
||||||
|
|
||||||
|
class IntegrationTestCaseWarnings(unittest.TestCase):
|
||||||
|
"""Integration style tests to check that warnings are issued properly for
|
||||||
|
different command line options."""
|
||||||
|
|
||||||
|
windows_warning_text = ("The --jobs option is not available on Windows."
|
||||||
|
" Ignoring --jobs arguments.")
|
||||||
|
stdin_warning_text = ("The --jobs option is not compatible with"
|
||||||
|
" supplying input using - . Ignoring --jobs"
|
||||||
|
" arguments.")
|
||||||
|
|
||||||
|
def this_file(self):
|
||||||
|
"""Return the real path of this file."""
|
||||||
|
this_file = os.path.realpath(__file__)
|
||||||
|
if this_file.endswith("pyc"):
|
||||||
|
this_file = this_file[:-1]
|
||||||
|
return this_file
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_style_guide_with_warnings(engine, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Return a style guide object (obtained by calling
|
||||||
|
engine.get_style_guide) and a list of the warnings that were raised in
|
||||||
|
the process.
|
||||||
|
|
||||||
|
Note: not threadsafe
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Note
|
||||||
|
# https://docs.python.org/2/library/warnings.html
|
||||||
|
#
|
||||||
|
# The catch_warnings manager works by replacing and then later
|
||||||
|
# restoring the module's showwarning() function and internal list of
|
||||||
|
# filter specifications. This means the context manager is modifying
|
||||||
|
# global state and therefore is not thread-safe
|
||||||
|
|
||||||
|
with warnings.catch_warnings(record=True) as collected_warnings:
|
||||||
|
# Cause all warnings to always be triggered.
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
|
||||||
|
# Get the style guide
|
||||||
|
style_guide = engine.get_style_guide(*args, **kwargs)
|
||||||
|
|
||||||
|
# Now that the warnings have been collected, return the style guide and
|
||||||
|
# the
|
||||||
|
# warnings.
|
||||||
|
return (style_guide, collected_warnings)
|
||||||
|
|
||||||
|
def verify_warnings(self, collected_warnings, expected_warnings):
|
||||||
|
"""
|
||||||
|
Verifies that collected_warnings is a sequence that contains user
|
||||||
|
warnings that match the sequence of string values passed in as
|
||||||
|
expected_warnings.
|
||||||
|
"""
|
||||||
|
if expected_warnings is None:
|
||||||
|
expected_warnings = []
|
||||||
|
|
||||||
|
collected_user_warnings = [w for w in collected_warnings
|
||||||
|
if issubclass(w.category, UserWarning)]
|
||||||
|
|
||||||
|
self.assertEqual(len(collected_user_warnings),
|
||||||
|
len(expected_warnings))
|
||||||
|
|
||||||
|
collected_warnings_set = set(str(warning.message)
|
||||||
|
for warning
|
||||||
|
in collected_user_warnings)
|
||||||
|
expected_warnings_set = set(expected_warnings)
|
||||||
|
self.assertEqual(collected_warnings_set, expected_warnings_set)
|
||||||
|
|
||||||
|
def check_files_collect_warnings(self,
|
||||||
|
arglist=[],
|
||||||
|
explicit_stdin=False,
|
||||||
|
count=0,
|
||||||
|
verbose=False):
|
||||||
|
"""Call check_files and collect any warnings that are issued."""
|
||||||
|
if verbose:
|
||||||
|
arglist.append('--verbose')
|
||||||
|
if explicit_stdin:
|
||||||
|
target_file = "-"
|
||||||
|
else:
|
||||||
|
target_file = self.this_file()
|
||||||
|
argv = ['flake8'] + arglist + [target_file]
|
||||||
|
with mock.patch("sys.argv", argv):
|
||||||
|
(style_guide,
|
||||||
|
collected_warnings,
|
||||||
|
) = self.get_style_guide_with_warnings(engine,
|
||||||
|
parse_argv=True)
|
||||||
|
report = style_guide.check_files()
|
||||||
|
self.assertEqual(report.total_errors, count)
|
||||||
|
return style_guide, report, collected_warnings
|
||||||
|
|
||||||
|
def check_files_no_warnings_allowed(self,
|
||||||
|
arglist=[],
|
||||||
|
explicit_stdin=False,
|
||||||
|
count=0,
|
||||||
|
verbose=False):
|
||||||
|
"""Call check_files, and assert that there were no warnings issued."""
|
||||||
|
(style_guide,
|
||||||
|
report,
|
||||||
|
collected_warnings,
|
||||||
|
) = self.check_files_collect_warnings(arglist=arglist,
|
||||||
|
explicit_stdin=explicit_stdin,
|
||||||
|
count=count,
|
||||||
|
verbose=verbose)
|
||||||
|
self.verify_warnings(collected_warnings, expected_warnings=None)
|
||||||
|
return style_guide, report
|
||||||
|
|
||||||
|
def _job_tester(self, jobs, verbose=False):
|
||||||
|
# mock stdout.flush so we can count the number of jobs created
|
||||||
|
with mock.patch('sys.stdout.flush') as mocked:
|
||||||
|
(guide,
|
||||||
|
report,
|
||||||
|
collected_warnings,
|
||||||
|
) = self.check_files_collect_warnings(
|
||||||
|
arglist=['--jobs=%s' % jobs],
|
||||||
|
verbose=verbose)
|
||||||
|
|
||||||
|
if is_windows():
|
||||||
|
# The code path where guide.options.jobs gets converted to an
|
||||||
|
# int is not run on windows. So, do the int conversion here.
|
||||||
|
self.assertEqual(int(guide.options.jobs), jobs)
|
||||||
|
# On windows, call count is always zero.
|
||||||
|
self.assertEqual(mocked.call_count, 0)
|
||||||
|
else:
|
||||||
|
self.assertEqual(guide.options.jobs, jobs)
|
||||||
|
self.assertEqual(mocked.call_count, jobs)
|
||||||
|
|
||||||
|
expected_warings = []
|
||||||
|
if verbose and is_windows():
|
||||||
|
expected_warings.append(self.windows_warning_text)
|
||||||
|
self.verify_warnings(collected_warnings, expected_warings)
|
||||||
|
|
||||||
|
def test_jobs(self, verbose=False):
|
||||||
|
self._job_tester(2, verbose=verbose)
|
||||||
|
self._job_tester(10, verbose=verbose)
|
||||||
|
|
||||||
|
def test_no_args_no_warnings(self, verbose=False):
|
||||||
|
self.check_files_no_warnings_allowed(verbose=verbose)
|
||||||
|
|
||||||
|
def test_stdin_jobs_warning(self, verbose=False):
|
||||||
|
self.count = 0
|
||||||
|
|
||||||
|
def fake_stdin():
|
||||||
|
self.count += 1
|
||||||
|
with open(self.this_file(), "r") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
with mock.patch("pep8.stdin_get_value", fake_stdin):
|
||||||
|
(style_guide,
|
||||||
|
report,
|
||||||
|
collected_warnings,
|
||||||
|
) = self.check_files_collect_warnings(arglist=['--jobs=4'],
|
||||||
|
explicit_stdin=True,
|
||||||
|
verbose=verbose)
|
||||||
|
expected_warings = []
|
||||||
|
if verbose:
|
||||||
|
expected_warings.append(self.stdin_warning_text)
|
||||||
|
if is_windows():
|
||||||
|
expected_warings.append(self.windows_warning_text)
|
||||||
|
self.verify_warnings(collected_warnings, expected_warings)
|
||||||
|
self.assertEqual(self.count, 1)
|
||||||
|
|
||||||
|
def test_jobs_verbose(self):
|
||||||
|
self.test_jobs(verbose=True)
|
||||||
|
|
||||||
|
def test_no_args_no_warnings_verbose(self):
|
||||||
|
self.test_no_args_no_warnings(verbose=True)
|
||||||
|
|
||||||
|
def test_stdin_jobs_warning_verbose(self):
|
||||||
|
self.test_stdin_jobs_warning(verbose=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
@ -54,6 +54,15 @@ def is_using_stdin(paths):
|
||||||
return '-' in paths
|
return '-' in paths
|
||||||
|
|
||||||
|
|
||||||
|
def warn_when_using_jobs(options):
|
||||||
|
return (options.verbose and options.jobs and options.jobs.isdigit() and
|
||||||
|
int(options.jobs) > 1)
|
||||||
|
|
||||||
|
|
||||||
|
def force_disable_jobs(styleguide):
|
||||||
|
return is_windows() or is_using_stdin(styleguide.paths)
|
||||||
|
|
||||||
|
|
||||||
def flag_on(val):
|
def flag_on(val):
|
||||||
"""Return true if flag is on"""
|
"""Return true if flag is on"""
|
||||||
return str(val).upper() in ('1', 'T', 'TRUE', 'ON')
|
return str(val).upper() in ('1', 'T', 'TRUE', 'ON')
|
||||||
|
|
|
||||||
1
tox.ini
1
tox.ini
|
|
@ -6,6 +6,7 @@ envlist =
|
||||||
[testenv]
|
[testenv]
|
||||||
usedevelop = True
|
usedevelop = True
|
||||||
deps =
|
deps =
|
||||||
|
mock
|
||||||
commands =
|
commands =
|
||||||
python setup.py test -q
|
python setup.py test -q
|
||||||
python setup.py flake8
|
python setup.py flake8
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue