]>
crepu.dev Git - config.git/blob - djavu-asus/elpy/rpc-venv/lib/python3.11/site-packages/yapf/yapflib/yapf_api.py
1 # Copyright 2015 Google Inc. All Rights Reserved.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
16 The main APIs that YAPF exposes to drive the reformatting.
18 FormatFile(): reformat a file.
19 FormatCode(): reformat a string of code.
21 These APIs have some common arguments:
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
30 print_diff: (bool) Instead of returning the reformatted source, return a
31 diff that turns the formatted source into reformatter source.
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
53 def FormatFile(filename
,
59 """Format a single Python file and return the formatted code.
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
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.
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.
81 IOError: raised if there was an error reading the file.
82 ValueError: raised if in_place and print_diff are both specified.
84 if in_place
and print_diff
:
85 raise ValueError('Cannot pass both in_place and print_diff.')
87 original_source
, newline
, encoding
= ReadFile(filename
, logger
)
88 reformatted_source
, changed
= FormatCode(
90 style_config
=style_config
,
93 print_diff
=print_diff
)
95 reformatted_source
= reformatted_source
.replace('\n', newline
)
98 file_resources
.WriteReformattedCode(filename
, reformatted_source
,
100 return None, encoding
, changed
102 return reformatted_source
, encoding
, changed
105 def FormatTree(tree
, style_config
=None, lines
=None):
106 """Format a parsed lib2to3 pytree.
108 This provides an alternative entry point to YAPF.
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
121 The source formatted according to the given formatting style.
123 style
.SetGlobalStyle(style
.CreateStyleFromConfig(style_config
))
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
)
133 llines
= pytree_unwrapper
.UnwrapPyTree(tree
)
135 lline
.CalculateFormattingInformation()
137 lines
= _LineRangesToSet(lines
)
138 _MarkLinesToFormat(llines
, lines
)
139 return reformatter
.Reformat(_SplitSemicolons(llines
), lines
)
142 def FormatAST(ast
, style_config
=None, lines
=None):
143 """Format a parsed lib2to3 pytree.
145 This provides an alternative entry point to YAPF.
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
158 The source formatted according to the given formatting style.
160 style
.SetGlobalStyle(style
.CreateStyleFromConfig(style_config
))
162 llines
= pyparser
.ParseCode(ast
)
164 lline
.CalculateFormattingInformation()
166 lines
= _LineRangesToSet(lines
)
167 _MarkLinesToFormat(llines
, lines
)
168 return reformatter
.Reformat(_SplitSemicolons(llines
), lines
)
171 def FormatCode(unformatted_source
,
172 filename
='<unknown>',
176 """Format a string of Python code.
178 This provides an alternative entry point to YAPF.
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
190 print_diff: (bool) Instead of returning the reformatted source, return a
191 diff that turns the formatted source into reformatter source.
194 Tuple of (reformatted_source, changed). reformatted_source conforms to the
195 desired formatting style. changed is True if the source changed.
198 tree
= pytree_utils
.ParseCodeToTree(unformatted_source
)
199 except Exception as e
:
200 e
.filename
= filename
201 raise errors
.YapfError(errors
.FormatErrorMsg(e
))
203 reformatted_source
= FormatTree(tree
, style_config
=style_config
, lines
=lines
)
205 if unformatted_source
== reformatted_source
:
206 return '' if print_diff
else reformatted_source
, False
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
213 return reformatted_source
, True
216 def ReadFile(filename
, logger
=None):
217 """Read the contents of the file.
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.
224 filename: (unicode) The name of the file.
225 logger: (function) A function or lambda that takes a string and emits it.
228 The contents of filename.
231 IOError: raised if there was an error reading the file.
234 encoding
= file_resources
.FileEncoding(filename
)
236 # Preserves line endings.
237 with codecs
.open(filename
, mode
='r', encoding
=encoding
) as fd
:
238 lines
= fd
.readlines()
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
246 e
.args
= (e
.args
[0], (filename
, e
.args
[1][1], e
.args
[1][2], e
.args
[1][3]))
248 except UnicodeDecodeError as e
: # pragma: no cover
250 logger('Could not parse %s! Consider excluding this file with --exclude.',
253 e
.args
= (e
.args
[0], (filename
, e
.args
[1][1], e
.args
[1][2], e
.args
[1][3]))
257 def _SplitSemicolons(lines
):
260 res
.extend(line
.Split())
264 DISABLE_PATTERN
= r
'^#.*\b(?:yapf:\s*disable|fmt: ?off)\b'
265 ENABLE_PATTERN
= r
'^#.*\b(?:yapf:\s*enable|fmt: ?on)\b'
268 def _LineRangesToSet(line_ranges
):
269 """Return a set of lines in the range."""
271 if line_ranges
is None:
275 for low
, high
in sorted(line_ranges
):
276 line_set
.update(range(low
, high
+ 1))
281 def _MarkLinesToFormat(llines
, lines
):
282 """Skip sections of code that we shouldn't reformat."""
284 for uwline
in llines
:
285 uwline
.disable
= not lines
.intersection(
286 range(uwline
.lineno
, uwline
.last
.lineno
+ 1))
288 # Now go through the lines and disable any lines explicitly marked as
291 while index
< len(llines
):
292 uwline
= llines
[index
]
293 if uwline
.is_comment
:
294 if _DisableYAPF(uwline
.first
.value
.strip()):
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
):
302 uwline
.disable
= True
304 elif re
.search(DISABLE_PATTERN
, uwline
.last
.value
.strip(), re
.IGNORECASE
):
305 uwline
.disable
= True
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
))
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
))
323 def _GetUnifiedDiff(before
, after
, filename
='code'):
324 """Get a unified diff of the changes.
327 before: (unicode) The original source code.
328 after: (unicode) The reformatted source code.
329 filename: (unicode) The code's filename.
332 The unified diff text.
334 before
= before
.splitlines()
335 after
= after
.splitlines()
337 difflib
.unified_diff(