Skip to content

Commit fa26911

Browse files
committed
DocumentationAPI: Support for :raises xyz:
Add support for :raises xyz: Add subsequent test cases. Closes #4279
1 parent c79ec5a commit fa26911

File tree

9 files changed

+131
-14
lines changed

9 files changed

+131
-14
lines changed

coalib/bearlib/languages/documentation/DocstyleDefinition.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class DocstyleDefinition:
1616
etc.).
1717
"""
1818
Metadata = namedtuple('Metadata', ('param_start', 'param_end',
19+
'exception_start', 'exception_end',
1920
'return_sep'))
2021

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

181-
metadata_settings = ('param_start', 'param_end', 'return_sep')
182+
metadata_settings = ('param_start', 'param_end',
183+
'exception_start', 'exception_end',
184+
'return_sep')
182185

183186
metadata = cls.Metadata(*(str(docstyle_settings.get(req_setting, ''))
184187
for req_setting in metadata_settings))

coalib/bearlib/languages/documentation/DocumentationComment.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class DocumentationComment:
1212
inside source-code, like position etc.
1313
"""
1414
Parameter = namedtuple('Parameter', 'name, desc')
15+
ExceptionValue = namedtuple('ExceptionValue', 'name, desc')
1516
ReturnValue = namedtuple('ReturnValue', 'desc')
1617
Description = namedtuple('Description', 'desc')
1718

@@ -69,13 +70,13 @@ def parse(self):
6970
"""
7071
if self.language == 'python' and self.docstyle == 'default':
7172
return self._parse_documentation_with_symbols(
72-
(':param ', ':'), ':return:')
73+
(':param ', ':'), (':raises ', ':'), ':return:')
7374
elif self.language == 'python' and self.docstyle == 'doxygen':
7475
return self._parse_documentation_with_symbols(
75-
('@param ', ' '), '@return ')
76+
('@param ', ' '), ('@raises ', ' '), '@return ')
7677
elif self.language == 'java' and self.docstyle == 'default':
7778
return self._parse_documentation_with_symbols(
78-
('@param ', ' '), '@return ')
79+
('@param ', ' '), ('@raises ', ' '), '@return ')
7980
elif self.language == 'golang' and self.docstyle == 'golang':
8081
# golang does not have param, return markers
8182
return self.documentation.splitlines(keepends=True)
@@ -84,19 +85,23 @@ def parse(self):
8485
'Documentation parsing for {0.language!r} in {0.docstyle!r}'
8586
' has not been implemented yet'.format(self))
8687

87-
def _parse_documentation_with_symbols(self, param_identifiers,
88+
def _parse_documentation_with_symbols(self,
89+
param_identifiers,
90+
exception_identifiers,
8891
return_identifiers):
8992
"""
90-
Parses documentation based on parameter and return symbols.
93+
Parses documentation based on parameter, exception and return symbols.
9194
9295
:param param_identifiers:
9396
A tuple of two strings with which a parameter starts and ends.
97+
:param exception_identifiers:
98+
A tuple of two strings with which an exception starts and ends.
9499
:param return_identifiers:
95100
The string with which a return description starts.
96101
:return:
97102
The list of all the parsed sections of the documentation. Every
98-
section is a namedtuple of either ``Description`` or ``Parameter``
99-
or ``ReturnValue``.
103+
section is a named tuple of either ``Description``, ``Parameter``,
104+
``ExceptionValue`` or ``ReturnValue``.
100105
"""
101106
lines = self.documentation.splitlines(keepends=True)
102107

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

129+
elif stripped_line.startswith(exception_identifiers[0]):
130+
parse_mode = self.ExceptionValue
131+
exception_offset = line.find(
132+
exception_identifiers[0]) + len(exception_identifiers[0])
133+
splitted = line[exception_offset:].split(
134+
exception_identifiers[1], 1)
135+
cur_exception = splitted[0].strip()
136+
137+
exception_desc = splitted[1]
138+
parsed.append(self.ExceptionValue(
139+
name=cur_exception, desc=exception_desc))
140+
124141
elif stripped_line.startswith(return_identifiers):
125142
parse_mode = self.ReturnValue
126143
return_offset = line.find(
@@ -133,6 +150,12 @@ def _parse_documentation_with_symbols(self, param_identifiers,
133150
parsed.pop()
134151
parsed.append(self.ReturnValue(desc=retval_desc))
135152

153+
elif parse_mode == self.ExceptionValue:
154+
exception_desc += line
155+
parsed.pop()
156+
parsed.append(self.ExceptionValue(
157+
name=cur_exception, desc=exception_desc))
158+
136159
elif parse_mode == self.Parameter:
137160
param_desc += line
138161
parsed.pop()
@@ -198,6 +221,11 @@ def from_metadata(cls, doccomment, docstyle_definition,
198221
section.name +
199222
docstyle_definition.metadata.param_end)
200223

224+
elif isinstance(section, cls.ExceptionValue):
225+
assembled_doc += (docstyle_definition.metadata.exception_start
226+
+ section.name
227+
+ docstyle_definition.metadata.exception_end)
228+
201229
elif isinstance(section, cls.ReturnValue):
202230
assembled_doc += docstyle_definition.metadata.return_sep
203231

coalib/bearlib/languages/documentation/default.coalang

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,23 @@
22
doc-marker = """, , """
33
param_start = :param\ # here's a space
44
param_end = :
5+
exception_start = :raises\ # here's a space
6+
exception_end = :
57
return_sep = :return:
68

79
[PYTHON3]
810
doc-marker = """, , """
911
param_start = :param\ # here's a space
1012
param_end = :
13+
exception_start = :raises\ # here's a space
14+
exception_end = :
1115
return_sep = :return:
1216

1317
[JAVA]
1418
doc-marker1 = /**, \ *, \ */
1519
doc-marker2 = /**, , \ */
1620
param_start = @param\ \ # here's a space
1721
param_end = \ # here's a space
22+
exception_start = @raises\ \ # here's a space
23+
exception_end = \ # here's a space
1824
return_sep = @return\ # here's a space

coalib/bearlib/languages/documentation/doxygen.coalang

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@ doc-marker1 = """, , """
3636
doc-marker2 = \#\#, \#, \#
3737
param_start = @param\ # here's a space
3838
param_end = \ # here's a space
39+
exception_start = @raises\ # here's a space
40+
exception_end = \ # here's a space
3941
return_sep = @return\ # here's a space
4042

4143
[PYTHON3]
4244
doc-marker1 = """, , """
4345
doc-marker2 = \#\#, \#, \#
4446
param_start = @param\ # here's a space
4547
param_end = \ # here's a space
48+
exception_start = @raises\ # here's a space
49+
exception_end = \ # here's a space
4650
return_sep = @return\ # here's a space
4751

4852
[TCL]

tests/bearlib/languages/documentation/DocstyleDefinitionTest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class DocstyleDefinitionTest(unittest.TestCase):
99

1010
Metadata = DocstyleDefinition.Metadata
11-
dummy_metadata = Metadata(':param ', ':', ':return:')
11+
dummy_metadata = Metadata(':param ', ':', ':raises ', ':', ':return:')
1212

1313
def test_fail_instantation(self):
1414
with self.assertRaises(ValueError):

tests/bearlib/languages/documentation/DocumentationCommentTest.py

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class DocumentationCommentTest(unittest.TestCase):
1414

1515
Description = DocumentationComment.Description
1616
Parameter = DocumentationComment.Parameter
17+
ExceptionValue = DocumentationComment.ExceptionValue
1718
ReturnValue = DocumentationComment.ReturnValue
1819

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

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

42-
python_doxygen_metadata = self.Metadata('@param ', ' ', '@return ')
43+
python_doxygen_metadata = self.Metadata('@param ', ' ',
44+
'@raises ', ' ',
45+
'@return ')
4346

4447
uut = DocumentationComment('qwertzuiop',
4548
python_doxygen,
@@ -58,7 +61,7 @@ def test_fields(self):
5861

5962
def test_not_implemented(self):
6063
raw_docstyle = DocstyleDefinition('nolang', 'nostyle', ('', '', ''),
61-
self.Metadata('', '', ''))
64+
self.Metadata('', '', '', '', ''))
6265
not_implemented = DocumentationComment(
6366
'some docs', raw_docstyle, None, None, None)
6467
with self.assertRaises(NotImplementedError):
@@ -114,6 +117,15 @@ def test_params_default(self):
114117
self.Parameter(name='test', desc=' test description2 \n')]
115118
self.check_docstring(doc, expected)
116119

120+
def test_exception_default(self):
121+
doc = (' :raises test: test description1\n'
122+
' :raises test: test description2\n')
123+
expected = [self.ExceptionValue(name='test',
124+
desc=' test description1\n'),
125+
self.ExceptionValue(name='test',
126+
desc=' test description2\n')]
127+
self.check_docstring(doc, expected)
128+
117129
def test_return_values_default(self):
118130
doc = (' :return: something1 \n'
119131
' :return: something2 ')
@@ -147,7 +159,26 @@ def test_python_default(self):
147159
desc='\n Short Param description.\n\n'),
148160
self.ReturnValue(desc=' Long Return Description That Makes No '
149161
'Sense And Will\n Cut to the Next'
150-
' Line.\n')]]
162+
' Line.\n')],
163+
[self.Description(desc='\nThis is dummy docstring find '
164+
'function.\n\n'),
165+
self.Parameter(name='filename',
166+
desc='\n contains filename\n'),
167+
self.ExceptionValue(name='FileNotFoundError',
168+
desc='\n raised when the given '
169+
'file name was not found\n\n'),
170+
self.ReturnValue(desc=' returns all possible docstrings'
171+
' in a file\n')],
172+
[self.Description(desc='\nThis returns perimeter '
173+
'of a triangle. \n\n'),
174+
self.Parameter(name='side_A',
175+
desc='\n length of side_A \n'),
176+
self.Parameter(name='side_B',
177+
desc='\n length of side_B \n'),
178+
self.Parameter(name='side_C',
179+
desc='\n length of side_C \n\n'),
180+
self.ReturnValue(desc=' returns perimeter\n')],
181+
]
151182

152183
self.assertEqual(parsed_docs, expected)
153184

@@ -170,7 +201,14 @@ def test_python_doxygen(self):
170201
[self.Description(desc=' This is the best docstring ever!\n\n'),
171202
self.Parameter(name='param1', desc='Parameter 1\n'),
172203
self.Parameter(name='param2', desc='Parameter 2\n'),
173-
self.ReturnValue(desc='Nothing\n')]]
204+
self.ReturnValue(desc='Nothing\n')],
205+
[self.Description(desc=' This is dummy docstring find '
206+
'function.\n\n'),
207+
self.Parameter(name='filename', desc='contains filename\n'),
208+
self.ExceptionValue(name='FileNotFoundError',
209+
desc='raises when filename is not found\n'),
210+
self.ReturnValue(desc='nothing\n')],
211+
]
174212

175213
self.assertEqual(parsed_docs, expected)
176214

@@ -188,6 +226,8 @@ def test_java_default(self):
188226
' argument.\n\n'),
189227
self.Parameter(name='name',
190228
desc='the name to which to say hello\n'),
229+
self.ExceptionValue(name='IOException',
230+
desc='throws IOException\n'),
191231
self.ReturnValue(
192232
desc=' the concatenated string\n')]]
193233

tests/bearlib/languages/documentation/documentation_extraction_testdata/default.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ class HelloWorld {
44
* Returns an String that says Hello with the name argument.
55
*
66
* @param name the name to which to say hello
7+
* @raises IOException throws IOException
78
* @return the concatenated string
89
*/
9-
public String sayHello(String name) {
10+
public String sayHello(String name) throws IOException {
1011
return "Hello, " + name;
1112
}
1213
}

tests/bearlib/languages/documentation/documentation_extraction_testdata/default.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,30 @@ def best_docstring(param1, param2):
3737
Cut to the Next Line.
3838
"""
3939
return None
40+
41+
def docstring_find(filename):
42+
"""
43+
This is dummy docstring find function.
44+
45+
:param filename:
46+
contains filename
47+
:raises FileNotFoundError:
48+
raised when the given file name was not found
49+
50+
:return: returns all possible docstrings in a file
51+
"""
52+
53+
def foobar_triangle(side_A, side_B, side_C):
54+
"""
55+
This returns perimeter of a triangle.
56+
57+
:param side_A:
58+
length of side_A
59+
:param side_B:
60+
length of side_B
61+
:param side_C:
62+
length of side_C
63+
64+
:return: returns perimeter
65+
"""
66+
return side_A + side_B + side_C

tests/bearlib/languages/documentation/documentation_extraction_testdata/doxygen.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ def best_docstring(param1, param2):
3232
# @param param2 Parameter 2
3333
# @return Nothing
3434
return None
35+
36+
def docstring_find(filename):
37+
## This is dummy docstring find function.
38+
#
39+
# @param filename contains filename
40+
# @raises FileNotFoundError raises when filename is not found
41+
# @return nothing
42+
return None

0 commit comments

Comments
 (0)