def test_parse_whole_description(self): """Make sure we can handle descriptions of multiple lines.""" node = parse( condense( lex('Short description\n' '\n' 'Long : (description)\n' '\n' ' <code></code>\n' '\n'))) self.assertTrue(node) self.assertTrue(CykNodeUtils.contains(node, 'short-description')) self.assertTrue(CykNodeUtils.contains(node, 'long-description'))
def test_long_description_with_noqa(self): tokens = condense( lex('\n'.join([ 'A docstring with noqas in it.', '', '# noqa: I203', '', '# noqa', '', ]))) node = parse(tokens) self.assertTrue(CykNodeUtils.contains(node, 'short-description')) self.assertTrue(CykNodeUtils.contains(node, 'long-description'))
def test_parse_args_section_with_newline_after_type(self): tokens = condense( lex('\n'.join([ 'Args:', ' points (:class:`numpy.ndarray`):', ' The points to test.', ]))) node = parse(tokens) self.assertEqual( node.symbol, 'arguments-section', str(node), )
def test_parse_return_keywords_cyk(self): keywords = { 'returns-section': ['returns'], 'return-type': ['rtype'], } for keyword_section in keywords: for keyword in keywords[keyword_section]: docstring = 'Short.\n\n:{}: something'.format(keyword) node = parse(condense(lex(docstring))) self.assertTrue( CykNodeUtils.contains(node, keyword_section), '{}: {}'.format(keyword_section, node), )
def test_no_short_description_checks_for_others(self): program = '\n'.join([ '@abstract.abstractmethod', 'def __init__(self, config: dict):', ' """', '', ' :param config: config dict user defined in config file.', ' """', ]) doc = ast.get_docstring(ast.parse(program).body[0]) tokens = condense(lex(doc)) node = parse(tokens) self.assertTrue(CykNodeUtils.contains(node, 'arguments-section'))
def test_parse_long_description_cyk(self): """Make sure we can parse a long description.""" node = parse( condense( lex('\n'.join([ 'Short descr.', '', 'A long description should be ', 'able to be multiple lines.', ' Code snippets should be allowed.', 'As should noqas # noqa', ])))) self.assertTrue(CykNodeUtils.contains(node, 'long-description'), )
def test_parse_long_description_with_noqa(self): """Make sure noqas can appear in a global scope.""" node = parse( condense( lex('\n'.join([ 'Short description can\'t have a noqa.' '' 'But a long description can.' '' '# noqa: I101 arg1' '\n' ])))) self.assertTrue(CykNodeUtils.contains(node, 'noqa'))
def test_top_parse_separates_by_indent_if_section_starts(self): """Make sure we an ignore indentations if between sections.""" docstring = '\n'.join([ 'A short summary.', ' ', 'Args:', ' x: y.', ' ', 'Returns:', ' Something.', ]) parsed = top_parse(condense(lex(docstring))) self.assertEqual(len(parsed), 3)
def test_parse_arguments(self): docstring = '\n'.join([ 'Estimate the probability of being cool.', '', 'Args:', ' hip: How hip it is.', ' hot: How hot it is.', ' coolness: Modified by this function.', ]) tokens = condense(lex(docstring)) tree = parse(tokens) self.assertTrue(tree is not None) self.assertContains(tree, 'arguments-section') self.assertContains(tree, 'ident')
def test_description_ends_with_sections(self): """Make sure the description section doesn't eat everything.""" node = parse( condense( lex('Short description.\n' '\n' 'Long Description.\n' '\n' 'Returns:\n' ' Nothing!\n' '\n'))) self.assertTrue(CykNodeUtils.contains(node, 'short-description')) self.assertTrue(CykNodeUtils.contains(node, 'long-description')) self.assertTrue(CykNodeUtils.contains(node, 'returns-section'))
def test_parse_noqa_for_global(self): """Make sure global targets are empty lists.""" func = '\n'.join([ 'def my_function():', ' """Ignore missing return.', '', ' # noqa: I201', '', ' """', ' return "This is ignored."', ]) doc = ast.get_docstring(ast.parse(func).body[0]) node = parse(condense(lex(doc))) self.assertTrue(CykNodeUtils.contains(node, 'noqa'))
def test_parse_args_section_with_newline_after_arg_name(self): tokens = condense(lex('\n'.join([ 'Args:', ' x:', ' Description text for x', ' y:', ' Description text for y' ]))) node = parse(tokens) self.assertEqual( node.symbol, 'arguments-section', str(node), )
def test_parse_global_noqa_with_target(self): """Make sure targets are present in the lists.""" func = '\n'.join([ 'def my_function(arg1):', ' """Ignore missing argument.', '', ' # noqa: I101 arg1', '', ' """', ' pass', ]) doc = ast.get_docstring(ast.parse(func).body[0]) node = parse(condense(lex(doc))) self.assertTrue(CykNodeUtils.contains(node, 'noqa'))
def test_top_parse_only_separates_by_indent_if_followed_by_newline(self): docstring = '\n'.join([ 'Short shorts.', '', ' Long Description.', ' ', 'Args:', ' x: y', ]) parsed = top_parse(condense(lex(docstring))) self.assertEqual(len(parsed), 3) self.assertTrue( parsed[1][0].token_type == TokenType.INDENT, 'Expected INDENT but was {}'.format(parsed[1][0].token_type, ))
def test_noqas_in_long_description(self): raw_docstring = '\n'.join([ 'Sore snork stort stort.', '', '# noqa: DAR101', '', ]) tokens = condense(lex(raw_docstring, config=self.config)) docstring = parse(tokens) self.assertIdentified( docstring, NoqaIdentifier, {'DAR101'}, )
def test_header_can_have_variable_length(self): for underline in [ '-' * x for x in range(1, 15) ]: raw_docstring = '\n'.join([ 'Cry aloud.', '', 'Parameters', '{}', '', ]).format(underline) tokens = condense(lex(raw_docstring)) docstring = parse(tokens) self.assertContains(docstring, 'arguments-section')
def test_parse_sole_argument_with_two_lines_indent_error(self): docstring = '\n'.join([ 'Short.', '', 'Args:', ' x: Something something something.', ' Something something.', ' Something, something, something.', '', 'Returns:', ' A value.', ]) tokens = condense(lex(docstring)) node = parse(tokens) self.assertTrue(CykNodeUtils.contains(node, 'arguments-section'))
def test_only_indents_treated_newlines_within_simple_section(self): """Make sure indent-only lines are treated as newlines in simple.""" node = parse( condense( lex('\n'.join([ 'Get the value of pi.', '', 'Returns:', ' A value that is an approximation of pi. This approximation', ' is actually just the quotient,', ' ', 'Raises:', ' Exception: Seemingly at random.', ])))) self.assertTrue(CykNodeUtils.contains(node, 'raises-section'))
def test_yield_type_with_multiple_names(self): raw_docstring = '\n'.join([ 'Yield the number four.', '', 'Yields', '-------', 'number : int', ' A number to use.', 'repr: str', ' The representation of the number.', '', ]) tokens = condense(lex(raw_docstring, config=self.config)) docstring = parse(tokens) self.assertContains(docstring, 'yields-section')
def test_no_blank_line_swallows_sections(self): """Make sure there must be a blank line after the short description.""" node = parse( condense( lex('\n'.join([ 'Should not have a raises section.', 'Args:', ' x: The divisor.', ' y: The dividend.', '', ])))) self.assertFalse( CykNodeUtils.contains(node, 'arguments-section'), 'The arguments section should have been eaten -- that way the ' 'user gets a signal that they should separate the sections.')
def test_long_description_can_come_between_sections(self): """Make sure non-standard parts are treated as descriptions.""" node = parse( condense( lex('\n'.join([ 'Double the number.', '', 'Args:', ' x: The only argument..', '', 'Requires:', ' Some kind of setup.', '', ])))) self.assertTrue(CykNodeUtils.contains(node, 'long-description'))
def test_returns_section_can_be_multiple_indented_lines(self): tokens = condense( lex('\n'.join([ 'Returns the sum of squares.', '', 'Returns:', ' The sum of squares:', '', ' SSx = \\sum(x - xbar)^2', '', ' For all x in X.', ]))) node = parse(tokens) self.assertTrue(node is not None) self.assertContains(node, 'returns-section')
def test_parse_library_exception(self): tokens = condense( lex('\n'.join([ 'Use custom handlers for error conditions.', '', 'Raises:', ' aiohttp.web.HTTPException: Reraises any HTTPExceptions we don\'t have an override for.', '' ]))) node = parse(tokens) self.assertTrue(CykNodeUtils.contains(node, 'raises-section')) exceptions = CykNodeUtils.get_annotated(node, ExceptionIdentifier) self.assertEqual(len(exceptions), 1) exception = list(exceptions)[0] self.assertEqual( ExceptionIdentifier.extract(exception), 'aiohttp.web.HTTPException', )
def test_parse_args_section_with_newline_after_type_in_context(self): tokens = condense(lex('\n'.join([ 'Args:', ' unbroken (int): without breaks.', ' points (:class:`numpy.ndarray`):', ' The points to test.', ' other (:class: `numpy.ndarray`):', ' Something.', ' nonbroken (int): without extra break', ]))) node = parse(tokens) self.assertEqual( node.symbol, 'arguments-section', str(node), )
def test_expected_amount_of_sections(self): docstring = '\n'.join([ 'foobar', '', 'Args:', ' foo: foobar', '', 'Returns:', ' bar', ]) tokens = condense(lex(docstring)) sections = top_parse(tokens) self.assertEqual( len(sections), 3, )
def test_parser_sections_correctly(self): program = '\n'.join([ 'def func(x, l):', ' """Add an item to the head of the list.', ' ', ' :param x: The item to add to the list.', ' :return: The list with the item attached.', ' ', ' """', ' return l.appendleft(x)', ]) doc = ast.get_docstring(ast.parse(program).body[0]) tokens = condense(lex(doc)) node = parse(tokens) self.assertTrue(CykNodeUtils.contains(node, 'returns-section'), ) self.assertTrue(CykNodeUtils.contains(node, 'arguments-section'), )
def test_parse_star_arguments(self): docstring = '\n'.join([ 'Negate a function which returns a boolean.', '', 'Args:', ' *fns (int): Functions which returns a boolean.', '', 'Returns:', ' int: A function which returns fallse when any of the' ' callables return true, and true will all of the ', ' callables return false.', ]) tokens = condense(lex(docstring)) tree = parse(tokens) self.assertTrue(tree is not None) self.assertContains(tree, 'arguments')
def test_crazy_argument_type_signatures(self): possible_types = [ # '(int)', # '(:obj:`str`, optional)', '(:obj:`str`, optional)', '(:obj:`str`,\n optional)', ] for type_ in possible_types: docstring = '\n'.join([ 'A short summary,', '', 'Args:', ' x {}: y.'.format(type_), ]) node = parse(condense(lex(docstring))) self.assertTrue(CykNodeUtils.contains(node, 'type-section-parens'))
def test_multiple_entries_in_raises(self): raw_docstring = '\n'.join([ 'A problematic function.', '', 'Raises', '------', 'InvalidNumberException', ' An exception for if it\'s ' ' invalid.', 'Exception', ' Seemingly at random.', '', ]) tokens = condense(lex(raw_docstring, config=self.config)) docstring = parse(tokens) self.assertContains(docstring, 'raises-section')
def test_noqas_in_parameters_section(self): raw_docstring = '\n'.join([ 'Get the cartesian product of two lists.', '', 'Parameters', '----------', 'x1 : List[Any]', ' The lists to use for the product. # noqa: DAR101', '', ]) tokens = condense(lex(raw_docstring, config=self.config)) docstring = parse(tokens) self.assertIdentified( docstring, NoqaIdentifier, {'DAR101'}, )