Skip to content

Commit

Permalink
Fix part of #6550: Write tests for docstrings_checker and pylint_exte…
Browse files Browse the repository at this point in the history
…nsions (#7153)

* Write tests for docstrings_checker and pylint_extensions

* write more tests

* add more tests

* fix lint

* fix imports

* revert some changes

* Fix tests

* address comments

* remove space

* fix

* fix lint

* fix lint

* fix isort on travis

* address comments

* write tests

* add last test
  • Loading branch information
Rishav Chakraborty authored and kevinlee12 committed Aug 3, 2019
1 parent a6d988e commit 6b7cb9d
Show file tree
Hide file tree
Showing 3 changed files with 574 additions and 43 deletions.
97 changes: 96 additions & 1 deletion scripts/docstrings_checker_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@

"""Unit tests for scripts/docstrings_checker."""

import ast
import contextlib
import unittest
import docstrings_checker # pylint: disable=relative-import

# pylint: disable=wrong-import-position
import astroid
import docstrings_checker # pylint: disable=relative-import

from pylint.checkers import utils # isort:skip
# pylint: enable=wrong-import-position


class ASTDocstringsCheckerTest(unittest.TestCase):
Expand Down Expand Up @@ -165,3 +173,90 @@ def test_compare_arg_order_multi_line_descriptions_success(self):
expected_result = []
result = docstring_checker.compare_arg_order(func_args, docstring_args)
self.assertEqual(result, expected_result)

def test_space_indentation(self):
sample_string = ' This is a sample string.'
self.assertEqual(docstrings_checker.space_indentation(sample_string), 5)

def test_check_docstrings_arg_order(self):
docstring_checker = docstrings_checker.ASTDocStringChecker()

ast_file = ast.walk(ast.parse(
"""
def func(test_var_one, test_var_two): #@
\"\"\"Function to test docstring parameters.
Args:
test_var_one: int. First test variable.
test_var_two: str. Second test variable.
Returns:
int. The test result.
\"\"\"
result = test_var_one + test_var_two
return result"""))

func_defs = [n for n in ast_file if isinstance(n, ast.FunctionDef)]
self.assertEqual(len(func_defs), 1)

func_result = docstring_checker.check_docstrings_arg_order(func_defs[0])
self.assertEqual(func_result, [])

def test_possible_exc_types_with_inference_error(self):

@contextlib.contextmanager
def swap(obj, attr, newvalue):
"""Swap an object's attribute value within the context of a
'with' statement. The object can be anything that supports
getattr and setattr, such as class instances, modules, etc.
"""
original = getattr(obj, attr)
setattr(obj, attr, newvalue)
try:
yield
finally:
setattr(obj, attr, original)

raise_node = astroid.extract_node("""
def func():
raise Exception('An exception.') #@
""")
node_ignores_exception_swap = swap(
utils, 'node_ignores_exception',
lambda _, __: (_ for _ in ()).throw(astroid.InferenceError()))

with node_ignores_exception_swap:
exceptions = docstrings_checker.possible_exc_types(raise_node)
self.assertEqual(exceptions, set([]))

def test_possible_exc_types_with_exception_message(self):
raise_node = astroid.extract_node("""
def func():
\"\"\"Function to test raising exceptions.\"\"\"
raise Exception('An exception.') #@
""")

exceptions = docstrings_checker.possible_exc_types(raise_node)
self.assertEqual(exceptions, set(['Exception']))

def test_possible_exc_types_with_no_exception(self):
raise_node = astroid.extract_node("""
def func():
\"\"\"Function to test raising exceptions.\"\"\"
raise #@
""")

exceptions = docstrings_checker.possible_exc_types(raise_node)
self.assertEqual(exceptions, set([]))

def test_possible_exc_types_with_exception_inside_function(self):
raise_node = astroid.extract_node("""
def func():
try:
raise Exception('An exception.')
except Exception:
raise #@
""")

exceptions = docstrings_checker.possible_exc_types(raise_node)
self.assertEqual(exceptions, set(['Exception']))
29 changes: 5 additions & 24 deletions scripts/pylint_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"""

import re

import astroid
import docstrings_checker # pylint: disable=relative-import

Expand Down Expand Up @@ -69,9 +70,6 @@ def visit_call(self, node):

# Build the set of keyword arguments and count the positional arguments.
call_site = astroid.arguments.CallSite.from_call(node)
if call_site.has_invalid_arguments() or (
call_site.has_invalid_keywords()):
return

num_positional_args = len(call_site.positional_arguments)
keyword_args = list(call_site.keyword_arguments.keys())
Expand Down Expand Up @@ -107,10 +105,7 @@ def visit_call(self, node):
# been called explicitly.
for [(name, defval), _] in parameters:
if defval:
if name is None:
display_name = '<tuple>'
else:
display_name = repr(name)
display_name = repr(name)

if name not in keyword_args and (
num_positional_args_unused > (
Expand All @@ -122,10 +117,7 @@ def visit_call(self, node):
try:
func_name = node.func.attrname
except AttributeError:
try:
func_name = node.func.name
except AttributeError:
func_name = node.func
func_name = node.func.name

self.add_message(
'non-explicit-keyword-args', node=node,
Expand Down Expand Up @@ -443,8 +435,6 @@ def visit_return(self, node):
return

func_node = node.frame()
if not isinstance(func_node, astroid.FunctionDef):
return

doc = docstrings_checker.docstringify(func_node.doc)
if not doc.is_valid() and self.config.accept_no_return_doc:
Expand Down Expand Up @@ -475,19 +465,13 @@ def visit_yield(self, node):
method definition in the AST.
"""
func_node = node.frame()
if not isinstance(func_node, astroid.FunctionDef):
return

doc = docstrings_checker.docstringify(func_node.doc)
if not doc.is_valid() and self.config.accept_no_yields_doc:
return

if doc.supports_yields:
doc_has_yields = doc.has_yields()
doc_has_yields_type = doc.has_yields_type()
else:
doc_has_yields = doc.has_returns()
doc_has_yields_type = doc.has_rtype()
doc_has_yields = doc.has_yields()
doc_has_yields_type = doc.has_yields_type()

if not doc_has_yields:
self.add_message(
Expand Down Expand Up @@ -648,7 +632,6 @@ def check_single_constructor_params(self, class_doc, init_doc, class_node):
def _handle_no_raise_doc(self, excs, node):
"""Checks whether the raised exception in a function has been
documented, add a message otherwise.
Args:
excs: list(str). A list of exception types.
node: astroid.scoped_nodes.Function. Node to access module content.
Expand Down Expand Up @@ -722,8 +705,6 @@ def visit_importfrom(self, node):
node=node,
args=(name, modname),
)
except astroid.AstroidBuildingException:
pass


class BackslashContinuationChecker(checkers.BaseChecker):
Expand Down
Loading

0 comments on commit 6b7cb9d

Please sign in to comment.