OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """A 2to3 fixer that reformats docstrings. | 5 """A 2to3 fixer that reformats docstrings. |
6 | 6 |
7 This should transform docstrings to be closer to the conventions in pep-0257; | 7 This should transform docstrings to be closer to the conventions in pep-0257; |
8 see https://www.python.org/dev/peps/pep-0257/. | 8 see https://www.python.org/dev/peps/pep-0257/. |
9 """ | 9 """ |
10 | 10 |
11 import re | 11 import re |
12 | 12 |
13 from lib2to3.fixer_base import BaseFix | 13 from lib2to3.fixer_base import BaseFix |
14 from lib2to3.pgen2 import token | 14 from lib2to3.pgen2 import token |
| 15 from lib2to3.pygram import python_symbols |
15 | 16 |
16 | 17 |
17 class FixDocstrings(BaseFix): | 18 class FixDocstrings(BaseFix): |
18 | 19 |
19 explicit = True | 20 explicit = True |
20 _accept_type = token.STRING | 21 _accept_type = token.STRING |
21 | 22 |
22 def match(self, node): | 23 def match(self, node): |
23 return node.value.startswith('"""') and node.prev_sibling is None | 24 """Returns True if the given node appears to be a docstring. |
| 25 |
| 26 Docstrings should always have no previous siblings, and should be |
| 27 direct children of simple_stmt. |
| 28 |
| 29 Note: This may also match for some edge cases where there are |
| 30 simple_stmt strings that aren't the first thing in a module, class |
| 31 or function, and thus aren't considered docstrings; but changing these |
| 32 strings should not change behavior. |
| 33 """ |
| 34 # Pylint incorrectly warns that there's no member simple_stmt on python_
symbols |
| 35 # because the attribute is set dynamically. pylint: disable=no-member |
| 36 return (node.value.startswith('"""') and |
| 37 node.prev_sibling is None and |
| 38 node.parent.type == python_symbols.simple_stmt) |
24 | 39 |
25 def transform(self, node, results): | 40 def transform(self, node, results): |
26 # First, strip whitespace at the beginning and end. | 41 # First, strip whitespace at the beginning and end. |
27 node.value = re.sub(r'^"""\s+', '"""', node.value) | 42 node.value = re.sub(r'^"""\s+', '"""', node.value) |
28 node.value = re.sub(r'\s+"""$', '"""', node.value) | 43 node.value = re.sub(r'\s+"""$', '"""', node.value) |
29 | 44 |
30 # For multi-line docstrings, the closing quotes should go on their own l
ine. | 45 # For multi-line docstrings, the closing quotes should go on their own l
ine. |
31 if '\n' in node.value: | 46 if '\n' in node.value: |
32 indent = re.search(r'\n( *)\S', node.value).group(1) | 47 indent = self._find_indent(node) |
33 node.value = re.sub(r'"""$', '\n' + indent + '"""', node.value) | 48 node.value = re.sub(r'"""$', '\n' + indent + '"""', node.value) |
34 | 49 |
35 node.changed() | 50 node.changed() |
| 51 |
| 52 def _find_indent(self, node): |
| 53 """Returns the indentation level of the docstring.""" |
| 54 # The parent is assumed to be a simple_stmt (the docstring statement) |
| 55 # either preceded by an indentation, or nothing. |
| 56 if not node.parent.prev_sibling or node.parent.prev_sibling.type != toke
n.INDENT: |
| 57 return '' |
| 58 return node.parent.prev_sibling.value |
OLD | NEW |