# Copyright (C) 2018 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for fire docstrings module.""" from __future__ import absolute_import from __future__ import division from __future__ import print_function from fire import docstrings from fire import testutils # pylint: disable=invalid-name DocstringInfo = docstrings.DocstringInfo ArgInfo = docstrings.ArgInfo KwargInfo = docstrings.KwargInfo # pylint: enable=invalid-name class DocstringsTest(testutils.BaseTestCase): def test_one_line_simple(self): docstring = """A simple one line docstring.""" docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='A simple one line docstring.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_one_line_simple_whitespace(self): docstring = """ A simple one line docstring. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='A simple one line docstring.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_one_line_too_long(self): # pylint: disable=line-too-long docstring = """A one line docstring thats both a little too verbose and a little too long so it keeps going well beyond a reasonable length for a one-liner. """ # pylint: enable=line-too-long docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='A one line docstring thats both a little too verbose and ' 'a little too long so it keeps going well beyond a reasonable length ' 'for a one-liner.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_one_line_runs_over(self): # pylint: disable=line-too-long docstring = """A one line docstring thats both a little too verbose and a little too long so it runs onto a second line. """ # pylint: enable=line-too-long docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='A one line docstring thats both a little too verbose and ' 'a little too long so it runs onto a second line.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_one_line_runs_over_whitespace(self): docstring = """ A one line docstring thats both a little too verbose and a little too long so it runs onto a second line. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='A one line docstring thats both a little too verbose and ' 'a little too long so it runs onto a second line.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_google_format_args_only(self): docstring = """One line description. Args: arg1: arg1_description arg2: arg2_description """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='One line description.', args=[ ArgInfo(name='arg1', description='arg1_description'), ArgInfo(name='arg2', description='arg2_description'), ] ) self.assertEqual(expected_docstring_info, docstring_info) def test_google_format_arg_named_args(self): docstring = """ Args: args: arg_description """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( args=[ ArgInfo(name='args', description='arg_description'), ] ) self.assertEqual(expected_docstring_info, docstring_info) def test_google_format_typed_args_and_returns(self): docstring = """Docstring summary. This is a longer description of the docstring. It spans multiple lines, as is allowed. Args: param1 (int): The first parameter. param2 (str): The second parameter. Returns: bool: The return value. True for success, False otherwise. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is a longer description of the docstring. It spans ' 'multiple lines, as\nis allowed.', args=[ ArgInfo(name='param1', type='int', description='The first parameter.'), ArgInfo(name='param2', type='str', description='The second parameter.'), ], returns='bool: The return value. True for success, False otherwise.' ) self.assertEqual(expected_docstring_info, docstring_info) def test_google_format_multiline_arg_description(self): docstring = """Docstring summary. This is a longer description of the docstring. It spans multiple lines, as is allowed. Args: param1 (int): The first parameter. param2 (str): The second parameter. This has a lot of text, enough to cover two lines. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is a longer description of the docstring. It spans ' 'multiple lines, as\nis allowed.', args=[ ArgInfo(name='param1', type='int', description='The first parameter.'), ArgInfo(name='param2', type='str', description='The second parameter. This has a lot of text, ' 'enough to cover two lines.'), ], ) self.assertEqual(expected_docstring_info, docstring_info) def test_rst_format_typed_args_and_returns(self): docstring = """Docstring summary. This is a longer description of the docstring. It spans across multiple lines. :param arg1: Description of arg1. :type arg1: str. :param arg2: Description of arg2. :type arg2: bool. :returns: int -- description of the return value. :raises: AttributeError, KeyError """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is a longer description of the docstring. It spans ' 'across multiple\nlines.', args=[ ArgInfo(name='arg1', type='str', description='Description of arg1.'), ArgInfo(name='arg2', type='bool', description='Description of arg2.'), ], returns='int -- description of the return value.', raises='AttributeError, KeyError', ) self.assertEqual(expected_docstring_info, docstring_info) def test_numpy_format_typed_args_and_returns(self): docstring = """Docstring summary. This is a longer description of the docstring. It spans across multiple lines. Parameters ---------- param1 : int The first parameter. param2 : str The second parameter. Returns ------- bool True if successful, False otherwise. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is a longer description of the docstring. It spans ' 'across multiple\nlines.', args=[ ArgInfo(name='param1', type='int', description='The first parameter.'), ArgInfo(name='param2', type='str', description='The second parameter.'), ], # TODO(dbieber): Support return type. returns='bool True if successful, False otherwise.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_numpy_format_multiline_arg_description(self): docstring = """Docstring summary. This is a longer description of the docstring. It spans across multiple lines. Parameters ---------- param1 : int The first parameter. param2 : str The second parameter. This has a lot of text, enough to cover two lines. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is a longer description of the docstring. It spans ' 'across multiple\nlines.', args=[ ArgInfo(name='param1', type='int', description='The first parameter.'), ArgInfo(name='param2', type='str', description='The second parameter. This has a lot of text, ' 'enough to cover two lines.'), ], ) self.assertEqual(expected_docstring_info, docstring_info) def test_multisection_docstring(self): docstring = """Docstring summary. This is the first section of a docstring description. This is the second section of a docstring description. This docstring description has just two sections. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', description='This is the first section of a docstring description.' '\n\n' 'This is the second section of a docstring description. This docstring' '\n' 'description has just two sections.', ) self.assertEqual(expected_docstring_info, docstring_info) def test_google_section_with_blank_first_line(self): docstring = """Inspired by requests HTTPAdapter docstring. :param x: Simple param. Usage: >>> import requests """ docstring_info = docstrings.parse(docstring) self.assertEqual('Inspired by requests HTTPAdapter docstring.', docstring_info.summary) def test_ill_formed_docstring(self): docstring = """Docstring summary. args: raises :: : pathological docstrings should not fail, and ideally should behave reasonably. """ docstrings.parse(docstring) def test_strip_blank_lines(self): lines = [' ', ' foo ', ' '] expected_output = [' foo '] self.assertEqual(expected_output, docstrings._strip_blank_lines(lines)) # pylint: disable=protected-access def test_numpy_colon_in_description(self): docstring = """ Greets name. Arguments --------- name : str name, default : World arg2 : int arg2, default:None arg3 : bool """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Greets name.', description=None, args=[ ArgInfo(name='name', type='str', description='name, default : World'), ArgInfo(name='arg2', type='int', description='arg2, default:None'), ArgInfo(name='arg3', type='bool', description=None), ] ) self.assertEqual(expected_docstring_info, docstring_info) def test_rst_format_typed_args_and_kwargs(self): docstring = """Docstring summary. :param arg1: Description of arg1. :type arg1: str. :key arg2: Description of arg2. :type arg2: bool. :key arg3: Description of arg3. :type arg3: str. """ docstring_info = docstrings.parse(docstring) expected_docstring_info = DocstringInfo( summary='Docstring summary.', args=[ ArgInfo(name='arg1', type='str', description='Description of arg1.'), KwargInfo(name='arg2', type='bool', description='Description of arg2.'), KwargInfo(name='arg3', type='str', description='Description of arg3.'), ], ) self.assertEqual(expected_docstring_info, docstring_info) if __name__ == '__main__': testutils.main()