Merge branch 'master' into 'master'

Add --tee option to split report output stream.

The `--tee` option allows the linter report to be written to stdout, even
though it is being redirected to a file with the` --output-file` option.
This is useful if I want to store the report in a separate file for later
analysis but also be able to print the output on screen (e.g when running
in a CI environment).

See merge request !90
This commit is contained in:
Ian Cordasco 2016-10-25 21:34:43 +00:00
commit a9e15afbf5
5 changed files with 43 additions and 4 deletions

View file

@ -125,6 +125,7 @@ And you should see something like:
available to use. (Default: auto) available to use. (Default: auto)
--output-file=OUTPUT_FILE --output-file=OUTPUT_FILE
Redirect report to a file. Redirect report to a file.
--tee Write to stdout and output-file.
--append-config=APPEND_CONFIG --append-config=APPEND_CONFIG
Provide extra config files to parse in addition to the Provide extra config files to parse in addition to the
files found by Flake8 by default. These files are the files found by Flake8 by default. These files are the

View file

@ -563,6 +563,26 @@
output_file = output.txt output_file = output.txt
.. option:: --tee
Also print output to stdout if output-file has been configured.
Command-line example:
.. prompt:: bash
flake8 --tee --output-file=output.txt dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
output-file = output.txt
tee = True
.. option:: --append-config=<config> .. option:: --append-config=<config>
Provide extra config files to parse in after and in addition to the files Provide extra config files to parse in after and in addition to the files

View file

@ -150,7 +150,7 @@ class BaseFormatter(object):
"""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)
else: if self.output_fd is None or self.options.tee:
print(output) print(output)
def write(self, line, source): def write(self, line, source):

View file

@ -27,6 +27,7 @@ def register_default_options(option_manager):
- ``--exit-zero`` - ``--exit-zero``
- ``-j``/``--jobs`` - ``-j``/``--jobs``
- ``--output-file`` - ``--output-file``
- ``--tee``
- ``--append-config`` - ``--append-config``
- ``--config`` - ``--config``
- ``--isolated`` - ``--isolated``
@ -174,6 +175,11 @@ def register_default_options(option_manager):
help='Redirect report to a file.', help='Redirect report to a file.',
) )
add_option(
'--tee', default=False, parse_from_config=True, action='store_true',
help='Write to stdout and output-file.',
)
# Config file options # Config file options
add_option( add_option(

View file

@ -11,6 +11,7 @@ from flake8.formatting import base
def options(**kwargs): def options(**kwargs):
"""Create an optparse.Values instance.""" """Create an optparse.Values instance."""
kwargs.setdefault('output_file', None) kwargs.setdefault('output_file', None)
kwargs.setdefault('tee', False)
return optparse.Values(kwargs) return optparse.Values(kwargs)
@ -76,15 +77,26 @@ def test_show_source_updates_physical_line_appropriately(line, column):
assert pointer.count(' ') == (column - 1) assert pointer.count(' ') == (column - 1)
def test_write_uses_an_output_file(): @pytest.mark.parametrize('tee', [False, True])
def test_write_uses_an_output_file(tee):
"""Verify that we use the output file when it's present.""" """Verify that we use the output file when it's present."""
line = 'Something to write' line = 'Something to write'
source = 'source' source = 'source'
filemock = mock.Mock() filemock = mock.Mock()
formatter = base.BaseFormatter(options()) formatter = base.BaseFormatter(options(tee=tee))
formatter.output_fd = filemock formatter.output_fd = filemock
formatter.write(line, source)
with mock.patch('flake8.formatting.base.print') as print_func:
formatter.write(line, source)
if tee:
assert print_func.called
assert print_func.mock_calls == [
mock.call(line),
mock.call(source),
]
else:
assert not print_func.called
assert filemock.write.called is True assert filemock.write.called is True
assert filemock.write.call_count == 2 assert filemock.write.call_count == 2