Source code for flake8.formatting.base
"""The base class and interface for all formatting plugins."""
from __future__ import print_function
[docs]class BaseFormatter(object):
"""Class defining the formatter interface.
.. attribute:: options
The options parsed from both configuration files and the command-line.
.. attribute:: filename
If specified by the user, the path to store the results of the run.
.. attribute:: output_fd
Initialized when the :meth:`start` is called. This will be a file
object opened for writing.
.. attribute:: newline
The string to add to the end of a line. This is only used when the
output filename has been specified.
"""
def __init__(self, options):
"""Initialize with the options parsed from config and cli.
This also calls a hook, :meth:`after_init`, so subclasses do not need
to call super to call this method.
:param optparse.Values options:
User specified configuration parsed from both configuration files
and the command-line interface.
"""
self.options = options
self.filename = options.output_file
self.output_fd = None
self.newline = '\n'
self.after_init()
[docs] def start(self):
"""Prepare the formatter to receive input.
This defaults to initializing :attr:`output_fd` if :attr:`filename`
"""
if self.filename:
self.output_fd = open(self.filename, 'w')
[docs] def handle(self, error):
"""Handle an error reported by Flake8.
This defaults to calling :meth:`format`, :meth:`show_source`, and
then :meth:`write`. To extend how errors are handled, override this
method.
:param error:
This will be an instance of :class:`~flake8.style_guide.Error`.
:type error:
flake8.style_guide.Error
"""
line = self.format(error)
source = self.show_source(error)
self.write(line, source)
[docs] def format(self, error):
"""Format an error reported by Flake8.
This method **must** be implemented by subclasses.
:param error:
This will be an instance of :class:`~flake8.style_guide.Error`.
:type error:
flake8.style_guide.Error
:returns:
The formatted error string.
:rtype:
str
"""
raise NotImplementedError('Subclass of BaseFormatter did not implement'
' format.')
[docs] def show_benchmarks(self, benchmarks):
"""Format and print the benchmarks."""
# NOTE(sigmavirus24): The format strings are a little confusing, even
# to me, so here's a quick explanation:
# We specify the named value first followed by a ':' to indicate we're
# formatting the value.
# Next we use '<' to indicate we want the value left aligned.
# Then '10' is the width of the area.
# For floats, finally, we only want only want at most 3 digits after
# the decimal point to be displayed. This is the precision and it
# can not be specified for integers which is why we need two separate
# format strings.
float_format = '{value:<10.3} {statistic}'.format
int_format = '{value:<10} {statistic}'.format
for statistic, value in benchmarks:
if isinstance(value, int):
benchmark = int_format(statistic=statistic, value=value)
else:
benchmark = float_format(statistic=statistic, value=value)
self._write(benchmark)
[docs] def show_source(self, error):
"""Show the physical line generating the error.
This also adds an indicator for the particular part of the line that
is reported as generating the problem.
:param error:
This will be an instance of :class:`~flake8.style_guide.Error`.
:type error:
flake8.style_guide.Error
:returns:
The formatted error string if the user wants to show the source.
If the user does not want to show the source, this will return
``None``.
:rtype:
str
"""
if not self.options.show_source or error.physical_line is None:
return ''
pointer = (' ' * error.column_number) + '^'
# Physical lines have a newline at the end, no need to add an extra
# one
return error.physical_line + pointer
def _write(self, output):
"""Handle logic of whether to use an output file or print()."""
if self.output_fd is not None:
self.output_fd.write(output + self.newline)
else:
print(output)
[docs] def write(self, line, source):
"""Write the line either to the output file or stdout.
This handles deciding whether to write to a file or print to standard
out for subclasses. Override this if you want behaviour that differs
from the default.
:param str line:
The formatted string to print or write.
:param str source:
The source code that has been formatted and associated with the
line of output.
"""
self._write(line)
if source:
self._write(source)
[docs] def stop(self):
"""Clean up after reporting is finished."""
if self.output_fd is not None:
self.output_fd.close()
self.output_fd = None