| # Copyright 2016 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """A 2to3 fixer that reformats docstrings. |
| |
| This should transform docstrings to be closer to the conventions in pep-0257; |
| see https://www.python.org/dev/peps/pep-0257/. |
| """ |
| |
| import re |
| |
| from lib2to3.fixer_base import BaseFix |
| from lib2to3.pgen2 import token |
| from lib2to3.pygram import python_symbols |
| |
| |
| class FixDocstrings(BaseFix): |
| |
| explicit = True |
| _accept_type = token.STRING |
| |
| def match(self, node): |
| """Returns True if the given node appears to be a docstring. |
| |
| Docstrings should always have no previous siblings, and should be |
| direct children of simple_stmt. |
| |
| Note: This may also match for some edge cases where there are |
| simple_stmt strings that aren't the first thing in a module, class |
| or function, and thus aren't considered docstrings; but changing these |
| strings should not change behavior. |
| """ |
| # Pylint incorrectly warns that there's no member simple_stmt on python_symbols |
| # because the attribute is set dynamically. pylint: disable=no-member |
| return (node.value.startswith('"""') and |
| node.prev_sibling is None and |
| node.parent.type == python_symbols.simple_stmt) |
| |
| def transform(self, node, results): |
| # First, strip whitespace at the beginning and end. |
| node.value = re.sub(r'^"""\s+', '"""', node.value) |
| node.value = re.sub(r'\s+"""$', '"""', node.value) |
| |
| # For multi-line docstrings, the closing quotes should go on their own line. |
| if '\n' in node.value: |
| indent = self._find_indent(node) |
| node.value = re.sub(r'"""$', '\n' + indent + '"""', node.value) |
| |
| node.changed() |
| |
| def _find_indent(self, node): |
| """Returns the indentation level of the docstring.""" |
| # The parent is assumed to be a simple_stmt (the docstring statement) |
| # either preceded by an indentation, or nothing. |
| if not node.parent.prev_sibling or node.parent.prev_sibling.type != token.INDENT: |
| return '' |
| return node.parent.prev_sibling.value |