Add warnings when --jobs is invalid

Some platforms and options are not compatible with the --jobs option. For
example, it is not valid on Windows. Nor is it compatible with the --diff
option. This adds warnings when the --jobs option is supplied but is not
allowed.
This commit is contained in:
Christian Long 2015-02-23 17:08:04 -06:00
parent a9f375aa93
commit c3f5d144bc
3 changed files with 203 additions and 0 deletions

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import re
import platform
import warnings
import pep8
@ -123,6 +124,21 @@ def get_style_guide(**kwargs):
for options_hook in options_hooks:
options_hook(options)
if options.jobs and options.jobs.isdigit() and int(options.jobs) > 1:
if not multiprocessing:
warnings.warn("The multiprocessing module is not available. "
"Ignoring --jobs arguments.")
if is_windows():
warnings.warn("The --jobs option is not available on Windows. "
"Ignoring --jobs arguments.")
if 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:
options.jobs = None

View file

@ -0,0 +1,184 @@
"""
toast_warnings.py
Tests for the warnings that are emitted by flake8.
This module is named toast_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."""
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=None):
"""
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):
"""Call check_files and collect any warnings that are issued."""
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):
"""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)
self.verify_warnings(collected_warnings)
return style_guide, report
def test_no_args_no_warnings(self):
# assert there are no reported errors or warnings
self.check_files_no_warnings_allowed()
def _job_tester(self, jobs):
# 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])
expected_warings = []
if is_windows():
expected_warings.append("The --jobs option is not "
"available on Windows. Ignoring "
"--jobs arguments.")
# 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)
self.verify_warnings(collected_warnings, expected_warings)
def test_jobs(self):
self._job_tester(2)
self._job_tester(10)
def test_stdin_jobs_warning(self):
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)
expected_warings = ["The --jobs option is not compatible with "
"supplying input using - . Ignoring --jobs "
"arguments."]
if is_windows():
expected_warings.append("The --jobs option is not "
"available on Windows. Ignoring "
"--jobs arguments.")
self.verify_warnings(collected_warnings, expected_warings)
self.assertEqual(self.count, 1)
if __name__ == '__main__':
unittest.main()

View file

@ -6,9 +6,12 @@ envlist =
[testenv]
usedevelop = True
deps =
nose
mock
commands =
python setup.py test -q
python setup.py flake8
nosetests flake8.tests.toast_warnings
[testenv:py27-flake8]
basepython = python2.7