Skip to content

Commit

Permalink
DocumentationAPI: Support for :raises xyz:
Browse files Browse the repository at this point in the history
Add support for :raises xyz:
Add subsequent test cases.
Closes #4279
  • Loading branch information
damngamerz committed Jun 9, 2017
1 parent c79ec5a commit fa26911
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 14 deletions.
5 changes: 4 additions & 1 deletion coalib/bearlib/languages/documentation/DocstyleDefinition.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class DocstyleDefinition:
etc.).
"""
Metadata = namedtuple('Metadata', ('param_start', 'param_end',
'exception_start', 'exception_end',
'return_sep'))

@enforce_signature
Expand Down Expand Up @@ -178,7 +179,9 @@ def load(cls, language: str, docstyle: str, coalang_dir=None):
raise KeyError('Language {!r} is not defined for docstyle {!r}.'
.format(language, docstyle))

metadata_settings = ('param_start', 'param_end', 'return_sep')
metadata_settings = ('param_start', 'param_end',
'exception_start', 'exception_end',
'return_sep')

metadata = cls.Metadata(*(str(docstyle_settings.get(req_setting, ''))
for req_setting in metadata_settings))
Expand Down
42 changes: 35 additions & 7 deletions coalib/bearlib/languages/documentation/DocumentationComment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class DocumentationComment:
inside source-code, like position etc.
"""
Parameter = namedtuple('Parameter', 'name, desc')
ExceptionValue = namedtuple('ExceptionValue', 'name, desc')
ReturnValue = namedtuple('ReturnValue', 'desc')
Description = namedtuple('Description', 'desc')

Expand Down Expand Up @@ -69,13 +70,13 @@ def parse(self):
"""
if self.language == 'python' and self.docstyle == 'default':
return self._parse_documentation_with_symbols(
(':param ', ':'), ':return:')
(':param ', ':'), (':raises ', ':'), ':return:')
elif self.language == 'python' and self.docstyle == 'doxygen':
return self._parse_documentation_with_symbols(
('@param ', ' '), '@return ')
('@param ', ' '), ('@raises ', ' '), '@return ')
elif self.language == 'java' and self.docstyle == 'default':
return self._parse_documentation_with_symbols(
('@param ', ' '), '@return ')
('@param ', ' '), ('@raises ', ' '), '@return ')
elif self.language == 'golang' and self.docstyle == 'golang':
# golang does not have param, return markers
return self.documentation.splitlines(keepends=True)
Expand All @@ -84,19 +85,23 @@ def parse(self):
'Documentation parsing for {0.language!r} in {0.docstyle!r}'
' has not been implemented yet'.format(self))

def _parse_documentation_with_symbols(self, param_identifiers,
def _parse_documentation_with_symbols(self,
param_identifiers,
exception_identifiers,
return_identifiers):
"""
Parses documentation based on parameter and return symbols.
Parses documentation based on parameter, exception and return symbols.
:param param_identifiers:
A tuple of two strings with which a parameter starts and ends.
:param exception_identifiers:
A tuple of two strings with which an exception starts and ends.
:param return_identifiers:
The string with which a return description starts.
:return:
The list of all the parsed sections of the documentation. Every
section is a namedtuple of either ``Description`` or ``Parameter``
or ``ReturnValue``.
section is a named tuple of either ``Description``, ``Parameter``,
``ExceptionValue`` or ``ReturnValue``.
"""
lines = self.documentation.splitlines(keepends=True)

Expand All @@ -121,6 +126,18 @@ def _parse_documentation_with_symbols(self, param_identifiers,
param_desc = splitted[1]
parsed.append(self.Parameter(name=cur_param, desc=param_desc))

elif stripped_line.startswith(exception_identifiers[0]):
parse_mode = self.ExceptionValue
exception_offset = line.find(
exception_identifiers[0]) + len(exception_identifiers[0])
splitted = line[exception_offset:].split(
exception_identifiers[1], 1)
cur_exception = splitted[0].strip()

exception_desc = splitted[1]
parsed.append(self.ExceptionValue(
name=cur_exception, desc=exception_desc))

elif stripped_line.startswith(return_identifiers):
parse_mode = self.ReturnValue
return_offset = line.find(
Expand All @@ -133,6 +150,12 @@ def _parse_documentation_with_symbols(self, param_identifiers,
parsed.pop()
parsed.append(self.ReturnValue(desc=retval_desc))

elif parse_mode == self.ExceptionValue:
exception_desc += line
parsed.pop()
parsed.append(self.ExceptionValue(
name=cur_exception, desc=exception_desc))

elif parse_mode == self.Parameter:
param_desc += line
parsed.pop()
Expand Down Expand Up @@ -198,6 +221,11 @@ def from_metadata(cls, doccomment, docstyle_definition,
section.name +
docstyle_definition.metadata.param_end)

elif isinstance(section, cls.ExceptionValue):
assembled_doc += (docstyle_definition.metadata.exception_start
+ section.name
+ docstyle_definition.metadata.exception_end)

elif isinstance(section, cls.ReturnValue):
assembled_doc += docstyle_definition.metadata.return_sep

Expand Down
6 changes: 6 additions & 0 deletions coalib/bearlib/languages/documentation/default.coalang
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@
doc-marker = """, , """
param_start = :param\ # here's a space
param_end = :
exception_start = :raises\ # here's a space
exception_end = :
return_sep = :return:

[PYTHON3]
doc-marker = """, , """
param_start = :param\ # here's a space
param_end = :
exception_start = :raises\ # here's a space
exception_end = :
return_sep = :return:

[JAVA]
doc-marker1 = /**, \ *, \ */
doc-marker2 = /**, , \ */
param_start = @param\ \ # here's a space
param_end = \ # here's a space
exception_start = @raises\ \ # here's a space
exception_end = \ # here's a space
return_sep = @return\ # here's a space
4 changes: 4 additions & 0 deletions coalib/bearlib/languages/documentation/doxygen.coalang
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ doc-marker1 = """, , """
doc-marker2 = \#\#, \#, \#
param_start = @param\ # here's a space
param_end = \ # here's a space
exception_start = @raises\ # here's a space
exception_end = \ # here's a space
return_sep = @return\ # here's a space

[PYTHON3]
doc-marker1 = """, , """
doc-marker2 = \#\#, \#, \#
param_start = @param\ # here's a space
param_end = \ # here's a space
exception_start = @raises\ # here's a space
exception_end = \ # here's a space
return_sep = @return\ # here's a space

[TCL]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class DocstyleDefinitionTest(unittest.TestCase):

Metadata = DocstyleDefinition.Metadata
dummy_metadata = Metadata(':param ', ':', ':return:')
dummy_metadata = Metadata(':param ', ':', ':raises ', ':', ':return:')

def test_fail_instantation(self):
with self.assertRaises(ValueError):
Expand Down
48 changes: 44 additions & 4 deletions tests/bearlib/languages/documentation/DocumentationCommentTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class DocumentationCommentTest(unittest.TestCase):

Description = DocumentationComment.Description
Parameter = DocumentationComment.Parameter
ExceptionValue = DocumentationComment.ExceptionValue
ReturnValue = DocumentationComment.ReturnValue

Metadata = DocstyleDefinition.Metadata
Expand All @@ -39,7 +40,9 @@ def test_fields(self):

python_doxygen = DocstyleDefinition.load('python', 'doxygen')

python_doxygen_metadata = self.Metadata('@param ', ' ', '@return ')
python_doxygen_metadata = self.Metadata('@param ', ' ',
'@raises ', ' ',
'@return ')

uut = DocumentationComment('qwertzuiop',
python_doxygen,
Expand All @@ -58,7 +61,7 @@ def test_fields(self):

def test_not_implemented(self):
raw_docstyle = DocstyleDefinition('nolang', 'nostyle', ('', '', ''),
self.Metadata('', '', ''))
self.Metadata('', '', '', '', ''))
not_implemented = DocumentationComment(
'some docs', raw_docstyle, None, None, None)
with self.assertRaises(NotImplementedError):
Expand Down Expand Up @@ -114,6 +117,15 @@ def test_params_default(self):
self.Parameter(name='test', desc=' test description2 \n')]
self.check_docstring(doc, expected)

def test_exception_default(self):
doc = (' :raises test: test description1\n'
' :raises test: test description2\n')
expected = [self.ExceptionValue(name='test',
desc=' test description1\n'),
self.ExceptionValue(name='test',
desc=' test description2\n')]
self.check_docstring(doc, expected)

def test_return_values_default(self):
doc = (' :return: something1 \n'
' :return: something2 ')
Expand Down Expand Up @@ -147,7 +159,26 @@ def test_python_default(self):
desc='\n Short Param description.\n\n'),
self.ReturnValue(desc=' Long Return Description That Makes No '
'Sense And Will\n Cut to the Next'
' Line.\n')]]
' Line.\n')],
[self.Description(desc='\nThis is dummy docstring find '
'function.\n\n'),
self.Parameter(name='filename',
desc='\n contains filename\n'),
self.ExceptionValue(name='FileNotFoundError',
desc='\n raised when the given '
'file name was not found\n\n'),
self.ReturnValue(desc=' returns all possible docstrings'
' in a file\n')],
[self.Description(desc='\nThis returns perimeter '
'of a triangle. \n\n'),
self.Parameter(name='side_A',
desc='\n length of side_A \n'),
self.Parameter(name='side_B',
desc='\n length of side_B \n'),
self.Parameter(name='side_C',
desc='\n length of side_C \n\n'),
self.ReturnValue(desc=' returns perimeter\n')],
]

self.assertEqual(parsed_docs, expected)

Expand All @@ -170,7 +201,14 @@ def test_python_doxygen(self):
[self.Description(desc=' This is the best docstring ever!\n\n'),
self.Parameter(name='param1', desc='Parameter 1\n'),
self.Parameter(name='param2', desc='Parameter 2\n'),
self.ReturnValue(desc='Nothing\n')]]
self.ReturnValue(desc='Nothing\n')],
[self.Description(desc=' This is dummy docstring find '
'function.\n\n'),
self.Parameter(name='filename', desc='contains filename\n'),
self.ExceptionValue(name='FileNotFoundError',
desc='raises when filename is not found\n'),
self.ReturnValue(desc='nothing\n')],
]

self.assertEqual(parsed_docs, expected)

Expand All @@ -188,6 +226,8 @@ def test_java_default(self):
' argument.\n\n'),
self.Parameter(name='name',
desc='the name to which to say hello\n'),
self.ExceptionValue(name='IOException',
desc='throws IOException\n'),
self.ReturnValue(
desc=' the concatenated string\n')]]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ class HelloWorld {
* Returns an String that says Hello with the name argument.
*
* @param name the name to which to say hello
* @raises IOException throws IOException
* @return the concatenated string
*/
public String sayHello(String name) {
public String sayHello(String name) throws IOException {
return "Hello, " + name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,30 @@ def best_docstring(param1, param2):
Cut to the Next Line.
"""
return None

def docstring_find(filename):
"""
This is dummy docstring find function.
:param filename:
contains filename
:raises FileNotFoundError:
raised when the given file name was not found
:return: returns all possible docstrings in a file
"""

def foobar_triangle(side_A, side_B, side_C):
"""
This returns perimeter of a triangle.
:param side_A:
length of side_A
:param side_B:
length of side_B
:param side_C:
length of side_C
:return: returns perimeter
"""
return side_A + side_B + side_C
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ def best_docstring(param1, param2):
# @param param2 Parameter 2
# @return Nothing
return None

def docstring_find(filename):
## This is dummy docstring find function.
#
# @param filename contains filename
# @raises FileNotFoundError raises when filename is not found
# @return nothing
return None

0 comments on commit fa26911

Please sign in to comment.