Skip to content

Commit

Permalink
docparams can identify multiple types in raises sections
Browse files Browse the repository at this point in the history
  • Loading branch information
AWhetter committed Oct 17, 2019
1 parent 6df0b3e commit a24221a
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 8 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ Release date: TBA

Close #3183

* ``docparams`` extension supports multiple types in raises sections.
Multiple types can also be separated by commas in all valid sections.

Closes #2729


What's New in Pylint 2.4.3?
===========================
Expand Down
27 changes: 20 additions & 7 deletions pylint/extensions/_check_docs_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""Utility methods for docstring checking."""

import re
from typing import List

import astroid

Expand Down Expand Up @@ -105,6 +106,11 @@ def _get_raise_target(node):
return None


def _split_multiple_exc_types(target: str) -> List[str]:
delimiters = r'(\s*,(?:\s*or\s)?\s*|\s+or\s+)'
return re.split(delimiters, target)


def possible_exc_types(node):
"""
Gets all of the possible raised exception types for the given raise node.
Expand Down Expand Up @@ -239,6 +245,13 @@ class SphinxDocstring(Docstring):
type=re_type
)

re_multiple_simple_type = r"""
(?:{container_type}|{type})
(?:(?:\s+(?:of|or)\s+|\s*,\s*)(?:{container_type}|{type}))*
""".format(
type=re_type, container_type=re_simple_container_type
)

re_xref = r"""
(?::\w+:)? # optional tag
`{}` # what to reference
Expand Down Expand Up @@ -275,7 +288,7 @@ class SphinxDocstring(Docstring):
\s* # whitespace
: # final colon
""".format(
type=re_type
type=re_multiple_simple_type
)
re_type_in_docstring = re.compile(re_type_raw, re.X | re.S)

Expand All @@ -284,7 +297,7 @@ class SphinxDocstring(Docstring):
\s+ # whitespace
{type} # type declaration
""".format(
type=re_type
type=re_multiple_simple_type
)
re_property_type_in_docstring = re.compile(re_property_type_raw, re.X | re.S)

Expand All @@ -299,7 +312,7 @@ class SphinxDocstring(Docstring):
\s* # whitespace
: # final colon
""".format(
type=re_type
type=re_multiple_simple_type
)
re_raise_in_docstring = re.compile(re_raise_raw, re.X | re.S)

Expand All @@ -323,7 +336,7 @@ def exceptions(self):

for match in re.finditer(self.re_raise_in_docstring, self.doc):
raise_type = match.group(1)
types.add(raise_type)
types.update(_split_multiple_exc_types(raise_type))

return types

Expand Down Expand Up @@ -441,7 +454,7 @@ class GoogleDocstring(Docstring):

re_multiple_type = r"""
(?:{container_type}|{type}|{xref})
(?:\s+(?:of|or)\s+(?:{container_type}|{type}|{xref}))*
(?:(?:\s+(?:of|or)\s+|\s*,\s*)(?:{container_type}|{type}|{xref}))*
""".format(
type=re_type, xref=re_xref, container_type=re_container_type
)
Expand Down Expand Up @@ -484,7 +497,7 @@ class GoogleDocstring(Docstring):
\s* ({type}) \s* : # identifier
\s* (.*) # beginning of optional description
""".format(
type=re_type
type=re_multiple_type
),
re.X | re.S | re.M,
)
Expand Down Expand Up @@ -629,7 +642,7 @@ def exceptions(self):
exc_type = match.group(1)
exc_desc = match.group(2)
if exc_desc:
types.add(exc_type)
types.update(_split_multiple_exc_types(exc_type))

return types

Expand Down
38 changes: 37 additions & 1 deletion tests/extensions/test_check_raise_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ def my_func(self):
)
with self.assertNoMessages():
self.checker.visit_raise(raise_node)
pass

def test_find_google_attr_raises_substr_exc(self):
raise_node = astroid.extract_node(
Expand Down Expand Up @@ -295,6 +294,43 @@ def my_func(self):
with self.assertNoMessages():
self.checker.visit_raise(raise_node)

def test_find_multiple_sphinx_raises(self):
raise_node = astroid.extract_node(
'''
def my_func(self):
"""This is a docstring.
:raises RuntimeError: Always
:raises NameError, OSError, ValueError: Never
"""
raise RuntimeError('hi')
raise NameError('hi') #@
raise OSError(2, 'abort!')
raise ValueError('foo')
'''
)
with self.assertNoMessages():
self.checker.visit_raise(raise_node)

def test_find_multiple_google_raises(self):
raise_node = astroid.extract_node(
'''
def my_func(self):
"""This is a docstring.
Raises:
RuntimeError: Always
NameError, OSError, ValueError: Never
"""
raise RuntimeError('hi')
raise NameError('hi') #@
raise OSError(2, 'abort!')
raise ValueError('foo')
'''
)
with self.assertNoMessages():
self.checker.visit_raise(raise_node)

def test_finds_rethrown_sphinx_raises(self):
raise_node = astroid.extract_node(
'''
Expand Down

0 comments on commit a24221a

Please sign in to comment.