]> crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/yapf/yapflib/yapf_api.py
Actualizado el Readme
[config.git] / djavu-asus / elpy / rpc-venv / lib / python3.11 / site-packages / yapf / yapflib / yapf_api.py
1 # Copyright 2015 Google Inc. All Rights Reserved.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 """Entry points for YAPF.
15
16 The main APIs that YAPF exposes to drive the reformatting.
17
18 FormatFile(): reformat a file.
19 FormatCode(): reformat a string of code.
20
21 These APIs have some common arguments:
22
23 style_config: (string) Either a style name or a path to a file that contains
24 formatting style settings. If None is specified, use the default style
25 as set in style.DEFAULT_STYLE_FACTORY
26 lines: (list of tuples of integers) A list of tuples of lines, [start, end],
27 that we want to format. The lines are 1-based indexed. It can be used by
28 third-party code (e.g., IDEs) when reformatting a snippet of code rather
29 than a whole file.
30 print_diff: (bool) Instead of returning the reformatted source, return a
31 diff that turns the formatted source into reformatter source.
32 """
33
34 import codecs
35 import difflib
36 import re
37
38 from yapf.pyparser import pyparser
39 from yapf.pytree import blank_line_calculator
40 from yapf.pytree import comment_splicer
41 from yapf.pytree import continuation_splicer
42 from yapf.pytree import pytree_unwrapper
43 from yapf.pytree import pytree_utils
44 from yapf.pytree import split_penalty
45 from yapf.pytree import subtype_assigner
46 from yapf.yapflib import errors
47 from yapf.yapflib import file_resources
48 from yapf.yapflib import identify_container
49 from yapf.yapflib import reformatter
50 from yapf.yapflib import style
51
52
53 def FormatFile(filename,
54 style_config=None,
55 lines=None,
56 print_diff=False,
57 in_place=False,
58 logger=None):
59 """Format a single Python file and return the formatted code.
60
61 Arguments:
62 filename: (unicode) The file to reformat.
63 style_config: (string) Either a style name or a path to a file that contains
64 formatting style settings. If None is specified, use the default style
65 as set in style.DEFAULT_STYLE_FACTORY
66 lines: (list of tuples of integers) A list of tuples of lines, [start, end],
67 that we want to format. The lines are 1-based indexed. It can be used by
68 third-party code (e.g., IDEs) when reformatting a snippet of code rather
69 than a whole file.
70 print_diff: (bool) Instead of returning the reformatted source, return a
71 diff that turns the formatted source into reformatter source.
72 in_place: (bool) If True, write the reformatted code back to the file.
73 logger: (io streamer) A stream to output logging.
74
75 Returns:
76 Tuple of (reformatted_code, encoding, changed). reformatted_code is None if
77 the file is successfully written to (having used in_place). reformatted_code
78 is a diff if print_diff is True.
79
80 Raises:
81 IOError: raised if there was an error reading the file.
82 ValueError: raised if in_place and print_diff are both specified.
83 """
84 if in_place and print_diff:
85 raise ValueError('Cannot pass both in_place and print_diff.')
86
87 original_source, newline, encoding = ReadFile(filename, logger)
88 reformatted_source, changed = FormatCode(
89 original_source,
90 style_config=style_config,
91 filename=filename,
92 lines=lines,
93 print_diff=print_diff)
94 if newline != '\n':
95 reformatted_source = reformatted_source.replace('\n', newline)
96 if in_place:
97 if changed:
98 file_resources.WriteReformattedCode(filename, reformatted_source,
99 encoding, in_place)
100 return None, encoding, changed
101
102 return reformatted_source, encoding, changed
103
104
105 def FormatTree(tree, style_config=None, lines=None):
106 """Format a parsed lib2to3 pytree.
107
108 This provides an alternative entry point to YAPF.
109
110 Arguments:
111 tree: (pytree.Node) The root of the pytree to format.
112 style_config: (string) Either a style name or a path to a file that contains
113 formatting style settings. If None is specified, use the default style
114 as set in style.DEFAULT_STYLE_FACTORY
115 lines: (list of tuples of integers) A list of tuples of lines, [start, end],
116 that we want to format. The lines are 1-based indexed. It can be used by
117 third-party code (e.g., IDEs) when reformatting a snippet of code rather
118 than a whole file.
119
120 Returns:
121 The source formatted according to the given formatting style.
122 """
123 style.SetGlobalStyle(style.CreateStyleFromConfig(style_config))
124
125 # Run passes on the tree, modifying it in place.
126 comment_splicer.SpliceComments(tree)
127 continuation_splicer.SpliceContinuations(tree)
128 subtype_assigner.AssignSubtypes(tree)
129 identify_container.IdentifyContainers(tree)
130 split_penalty.ComputeSplitPenalties(tree)
131 blank_line_calculator.CalculateBlankLines(tree)
132
133 llines = pytree_unwrapper.UnwrapPyTree(tree)
134 for lline in llines:
135 lline.CalculateFormattingInformation()
136
137 lines = _LineRangesToSet(lines)
138 _MarkLinesToFormat(llines, lines)
139 return reformatter.Reformat(_SplitSemicolons(llines), lines)
140
141
142 def FormatAST(ast, style_config=None, lines=None):
143 """Format a parsed lib2to3 pytree.
144
145 This provides an alternative entry point to YAPF.
146
147 Arguments:
148 unformatted_source: (unicode) The code to format.
149 style_config: (string) Either a style name or a path to a file that contains
150 formatting style settings. If None is specified, use the default style
151 as set in style.DEFAULT_STYLE_FACTORY
152 lines: (list of tuples of integers) A list of tuples of lines, [start, end],
153 that we want to format. The lines are 1-based indexed. It can be used by
154 third-party code (e.g., IDEs) when reformatting a snippet of code rather
155 than a whole file.
156
157 Returns:
158 The source formatted according to the given formatting style.
159 """
160 style.SetGlobalStyle(style.CreateStyleFromConfig(style_config))
161
162 llines = pyparser.ParseCode(ast)
163 for lline in llines:
164 lline.CalculateFormattingInformation()
165
166 lines = _LineRangesToSet(lines)
167 _MarkLinesToFormat(llines, lines)
168 return reformatter.Reformat(_SplitSemicolons(llines), lines)
169
170
171 def FormatCode(unformatted_source,
172 filename='<unknown>',
173 style_config=None,
174 lines=None,
175 print_diff=False):
176 """Format a string of Python code.
177
178 This provides an alternative entry point to YAPF.
179
180 Arguments:
181 unformatted_source: (unicode) The code to format.
182 filename: (unicode) The name of the file being reformatted.
183 style_config: (string) Either a style name or a path to a file that contains
184 formatting style settings. If None is specified, use the default style
185 as set in style.DEFAULT_STYLE_FACTORY
186 lines: (list of tuples of integers) A list of tuples of lines, [start, end],
187 that we want to format. The lines are 1-based indexed. It can be used by
188 third-party code (e.g., IDEs) when reformatting a snippet of code rather
189 than a whole file.
190 print_diff: (bool) Instead of returning the reformatted source, return a
191 diff that turns the formatted source into reformatter source.
192
193 Returns:
194 Tuple of (reformatted_source, changed). reformatted_source conforms to the
195 desired formatting style. changed is True if the source changed.
196 """
197 try:
198 tree = pytree_utils.ParseCodeToTree(unformatted_source)
199 except Exception as e:
200 e.filename = filename
201 raise errors.YapfError(errors.FormatErrorMsg(e))
202
203 reformatted_source = FormatTree(tree, style_config=style_config, lines=lines)
204
205 if unformatted_source == reformatted_source:
206 return '' if print_diff else reformatted_source, False
207
208 if print_diff:
209 code_diff = _GetUnifiedDiff(
210 unformatted_source, reformatted_source, filename=filename)
211 return code_diff, code_diff.strip() != '' # pylint: disable=g-explicit-bool-comparison # noqa
212
213 return reformatted_source, True
214
215
216 def ReadFile(filename, logger=None):
217 """Read the contents of the file.
218
219 An optional logger can be specified to emit messages to your favorite logging
220 stream. If specified, then no exception is raised. This is external so that it
221 can be used by third-party applications.
222
223 Arguments:
224 filename: (unicode) The name of the file.
225 logger: (function) A function or lambda that takes a string and emits it.
226
227 Returns:
228 The contents of filename.
229
230 Raises:
231 IOError: raised if there was an error reading the file.
232 """
233 try:
234 encoding = file_resources.FileEncoding(filename)
235
236 # Preserves line endings.
237 with codecs.open(filename, mode='r', encoding=encoding) as fd:
238 lines = fd.readlines()
239
240 line_ending = file_resources.LineEnding(lines)
241 source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n'
242 return source, line_ending, encoding
243 except IOError as e: # pragma: no cover
244 if logger:
245 logger(e)
246 e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3]))
247 raise
248 except UnicodeDecodeError as e: # pragma: no cover
249 if logger:
250 logger('Could not parse %s! Consider excluding this file with --exclude.',
251 filename)
252 logger(e)
253 e.args = (e.args[0], (filename, e.args[1][1], e.args[1][2], e.args[1][3]))
254 raise
255
256
257 def _SplitSemicolons(lines):
258 res = []
259 for line in lines:
260 res.extend(line.Split())
261 return res
262
263
264 DISABLE_PATTERN = r'^#.*\b(?:yapf:\s*disable|fmt: ?off)\b'
265 ENABLE_PATTERN = r'^#.*\b(?:yapf:\s*enable|fmt: ?on)\b'
266
267
268 def _LineRangesToSet(line_ranges):
269 """Return a set of lines in the range."""
270
271 if line_ranges is None:
272 return None
273
274 line_set = set()
275 for low, high in sorted(line_ranges):
276 line_set.update(range(low, high + 1))
277
278 return line_set
279
280
281 def _MarkLinesToFormat(llines, lines):
282 """Skip sections of code that we shouldn't reformat."""
283 if lines:
284 for uwline in llines:
285 uwline.disable = not lines.intersection(
286 range(uwline.lineno, uwline.last.lineno + 1))
287
288 # Now go through the lines and disable any lines explicitly marked as
289 # disabled.
290 index = 0
291 while index < len(llines):
292 uwline = llines[index]
293 if uwline.is_comment:
294 if _DisableYAPF(uwline.first.value.strip()):
295 index += 1
296 while index < len(llines):
297 uwline = llines[index]
298 line = uwline.first.value.strip()
299 if uwline.is_comment and _EnableYAPF(line):
300 if not _DisableYAPF(line):
301 break
302 uwline.disable = True
303 index += 1
304 elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE):
305 uwline.disable = True
306 index += 1
307
308
309 def _DisableYAPF(line):
310 return (re.search(DISABLE_PATTERN,
311 line.split('\n')[0].strip(), re.IGNORECASE) or
312 re.search(DISABLE_PATTERN,
313 line.split('\n')[-1].strip(), re.IGNORECASE))
314
315
316 def _EnableYAPF(line):
317 return (re.search(ENABLE_PATTERN,
318 line.split('\n')[0].strip(), re.IGNORECASE) or
319 re.search(ENABLE_PATTERN,
320 line.split('\n')[-1].strip(), re.IGNORECASE))
321
322
323 def _GetUnifiedDiff(before, after, filename='code'):
324 """Get a unified diff of the changes.
325
326 Arguments:
327 before: (unicode) The original source code.
328 after: (unicode) The reformatted source code.
329 filename: (unicode) The code's filename.
330
331 Returns:
332 The unified diff text.
333 """
334 before = before.splitlines()
335 after = after.splitlines()
336 return '\n'.join(
337 difflib.unified_diff(
338 before,
339 after,
340 filename,
341 filename,
342 '(original)',
343 '(reformatted)',
344 lineterm='')) + '\n'