]> crepu.dev Git - config.git/blame - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/flake8/formatting/base.py
Configuracion en desarrollo PC pega
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / flake8 / formatting / base.py
CommitLineData
53e6db90
DC
1"""The base class and interface for all formatting plugins."""
2from __future__ import annotations
3
4import argparse
5import os
6import sys
7from typing import IO
8
9from flake8.formatting import _windows_color
10from flake8.statistics import Statistics
11from flake8.violation import Violation
12
13
14class BaseFormatter:
15 """Class defining the formatter interface.
16
17 .. attribute:: options
18
19 The options parsed from both configuration files and the command-line.
20
21 .. attribute:: filename
22
23 If specified by the user, the path to store the results of the run.
24
25 .. attribute:: output_fd
26
27 Initialized when the :meth:`start` is called. This will be a file
28 object opened for writing.
29
30 .. attribute:: newline
31
32 The string to add to the end of a line. This is only used when the
33 output filename has been specified.
34 """
35
36 def __init__(self, options: argparse.Namespace) -> None:
37 """Initialize with the options parsed from config and cli.
38
39 This also calls a hook, :meth:`after_init`, so subclasses do not need
40 to call super to call this method.
41
42 :param options:
43 User specified configuration parsed from both configuration files
44 and the command-line interface.
45 """
46 self.options = options
47 self.filename = options.output_file
48 self.output_fd: IO[str] | None = None
49 self.newline = "\n"
50 self.color = options.color == "always" or (
51 options.color == "auto"
52 and sys.stdout.isatty()
53 and _windows_color.terminal_supports_color
54 )
55 self.after_init()
56
57 def after_init(self) -> None:
58 """Initialize the formatter further."""
59
60 def beginning(self, filename: str) -> None:
61 """Notify the formatter that we're starting to process a file.
62
63 :param filename:
64 The name of the file that Flake8 is beginning to report results
65 from.
66 """
67
68 def finished(self, filename: str) -> None:
69 """Notify the formatter that we've finished processing a file.
70
71 :param filename:
72 The name of the file that Flake8 has finished reporting results
73 from.
74 """
75
76 def start(self) -> None:
77 """Prepare the formatter to receive input.
78
79 This defaults to initializing :attr:`output_fd` if :attr:`filename`
80 """
81 if self.filename:
82 dirname = os.path.dirname(os.path.abspath(self.filename))
83 os.makedirs(dirname, exist_ok=True)
84 self.output_fd = open(self.filename, "a")
85
86 def handle(self, error: Violation) -> None:
87 """Handle an error reported by Flake8.
88
89 This defaults to calling :meth:`format`, :meth:`show_source`, and
90 then :meth:`write`. To extend how errors are handled, override this
91 method.
92
93 :param error:
94 This will be an instance of
95 :class:`~flake8.violation.Violation`.
96 """
97 line = self.format(error)
98 source = self.show_source(error)
99 self.write(line, source)
100
101 def format(self, error: Violation) -> str | None:
102 """Format an error reported by Flake8.
103
104 This method **must** be implemented by subclasses.
105
106 :param error:
107 This will be an instance of
108 :class:`~flake8.violation.Violation`.
109 :returns:
110 The formatted error string.
111 """
112 raise NotImplementedError(
113 "Subclass of BaseFormatter did not implement" " format."
114 )
115
116 def show_statistics(self, statistics: Statistics) -> None:
117 """Format and print the statistics."""
118 for error_code in statistics.error_codes():
119 stats_for_error_code = statistics.statistics_for(error_code)
120 statistic = next(stats_for_error_code)
121 count = statistic.count
122 count += sum(stat.count for stat in stats_for_error_code)
123 self._write(f"{count:<5} {error_code} {statistic.message}")
124
125 def show_benchmarks(self, benchmarks: list[tuple[str, float]]) -> None:
126 """Format and print the benchmarks."""
127 # NOTE(sigmavirus24): The format strings are a little confusing, even
128 # to me, so here's a quick explanation:
129 # We specify the named value first followed by a ':' to indicate we're
130 # formatting the value.
131 # Next we use '<' to indicate we want the value left aligned.
132 # Then '10' is the width of the area.
133 # For floats, finally, we only want only want at most 3 digits after
134 # the decimal point to be displayed. This is the precision and it
135 # can not be specified for integers which is why we need two separate
136 # format strings.
137 float_format = "{value:<10.3} {statistic}".format
138 int_format = "{value:<10} {statistic}".format
139 for statistic, value in benchmarks:
140 if isinstance(value, int):
141 benchmark = int_format(statistic=statistic, value=value)
142 else:
143 benchmark = float_format(statistic=statistic, value=value)
144 self._write(benchmark)
145
146 def show_source(self, error: Violation) -> str | None:
147 """Show the physical line generating the error.
148
149 This also adds an indicator for the particular part of the line that
150 is reported as generating the problem.
151
152 :param error:
153 This will be an instance of
154 :class:`~flake8.violation.Violation`.
155 :returns:
156 The formatted error string if the user wants to show the source.
157 If the user does not want to show the source, this will return
158 ``None``.
159 """
160 if not self.options.show_source or error.physical_line is None:
161 return ""
162
163 # Because column numbers are 1-indexed, we need to remove one to get
164 # the proper number of space characters.
165 indent = "".join(
166 c if c.isspace() else " "
167 for c in error.physical_line[: error.column_number - 1]
168 )
169 # Physical lines have a newline at the end, no need to add an extra
170 # one
171 return f"{error.physical_line}{indent}^"
172
173 def _write(self, output: str) -> None:
174 """Handle logic of whether to use an output file or print()."""
175 if self.output_fd is not None:
176 self.output_fd.write(output + self.newline)
177 if self.output_fd is None or self.options.tee:
178 sys.stdout.buffer.write(output.encode() + self.newline.encode())
179
180 def write(self, line: str | None, source: str | None) -> None:
181 """Write the line either to the output file or stdout.
182
183 This handles deciding whether to write to a file or print to standard
184 out for subclasses. Override this if you want behaviour that differs
185 from the default.
186
187 :param line:
188 The formatted string to print or write.
189 :param source:
190 The source code that has been formatted and associated with the
191 line of output.
192 """
193 if line:
194 self._write(line)
195 if source:
196 self._write(source)
197
198 def stop(self) -> None:
199 """Clean up after reporting is finished."""
200 if self.output_fd is not None:
201 self.output_fd.close()
202 self.output_fd = None