|
26 | 26 | import importlib
|
27 | 27 | import doctest
|
28 | 28 | import tempfile
|
| 29 | +import ast |
| 30 | +import textwrap |
29 | 31 |
|
30 | 32 | import flake8.main.application
|
31 | 33 |
|
@@ -490,9 +492,45 @@ def yields(self):
|
490 | 492 | @property
|
491 | 493 | def method_source(self):
|
492 | 494 | try:
|
493 |
| - return inspect.getsource(self.obj) |
| 495 | + source = inspect.getsource(self.obj) |
494 | 496 | except TypeError:
|
495 | 497 | return ''
|
| 498 | + return textwrap.dedent(source) |
| 499 | + |
| 500 | + @property |
| 501 | + def method_returns_something(self): |
| 502 | + ''' |
| 503 | + Check if the docstrings method can return something. |
| 504 | +
|
| 505 | + Bare returns, returns valued None and returns from nested functions are |
| 506 | + disconsidered. |
| 507 | +
|
| 508 | + Returns |
| 509 | + ------- |
| 510 | + bool |
| 511 | + Whether the docstrings method can return something. |
| 512 | + ''' |
| 513 | + |
| 514 | + def get_returns_not_on_nested_functions(node): |
| 515 | + returns = [node] if isinstance(node, ast.Return) else [] |
| 516 | + for child in ast.iter_child_nodes(node): |
| 517 | + # Ignore nested functions and its subtrees. |
| 518 | + if not isinstance(child, ast.FunctionDef): |
| 519 | + child_returns = get_returns_not_on_nested_functions(child) |
| 520 | + returns.extend(child_returns) |
| 521 | + return returns |
| 522 | + |
| 523 | + tree = ast.parse(self.method_source).body |
| 524 | + if tree: |
| 525 | + returns = get_returns_not_on_nested_functions(tree[0]) |
| 526 | + return_values = [r.value for r in returns] |
| 527 | + # Replace NameConstant nodes valued None for None. |
| 528 | + for i, v in enumerate(return_values): |
| 529 | + if isinstance(v, ast.NameConstant) and v.value is None: |
| 530 | + return_values[i] = None |
| 531 | + return any(return_values) |
| 532 | + else: |
| 533 | + return False |
496 | 534 |
|
497 | 535 | @property
|
498 | 536 | def first_line_ends_in_dot(self):
|
@@ -691,7 +729,7 @@ def get_validation_data(doc):
|
691 | 729 |
|
692 | 730 | if doc.is_function_or_method:
|
693 | 731 | if not doc.returns:
|
694 |
| - if 'return' in doc.method_source: |
| 732 | + if doc.method_returns_something: |
695 | 733 | errs.append(error('RT01'))
|
696 | 734 | else:
|
697 | 735 | if len(doc.returns) == 1 and doc.returns[0][1]:
|
|
0 commit comments