|
9 | 9 | from datetime import datetime
|
10 | 10 |
|
11 | 11 | from sphinx.ext.autodoc import FunctionDocumenter
|
| 12 | +from sphinx.ext.napoleon import NumpyDocstring, docstring |
12 | 13 |
|
13 | 14 | from dpnp.dpnp_algo.dpnp_elementwise_common import DPNPBinaryFunc, DPNPUnaryFunc
|
14 | 15 |
|
@@ -231,3 +232,59 @@ def _can_document_member(member, *args, **kwargs):
|
231 | 232 | napoleon_use_ivar = True
|
232 | 233 | napoleon_include_special_with_doc = True
|
233 | 234 | napoleon_custom_sections = ["limitations"]
|
| 235 | + |
| 236 | + |
| 237 | +# Napoleon extension can't properly render "Returns" section in case of |
| 238 | +# namedtuple as a return type. That patch proposes to extend the parse logic |
| 239 | +# which allows text in a header of "Returns" section. |
| 240 | +def _parse_returns_section_patched(self, section: str) -> list[str]: |
| 241 | + fields = self._consume_returns_section() |
| 242 | + multi = len(fields) > 1 |
| 243 | + use_rtype = False if multi else self._config.napoleon_use_rtype |
| 244 | + lines: list[str] = [] |
| 245 | + header: list[str] = [] |
| 246 | + is_logged_header = False |
| 247 | + |
| 248 | + for _name, _type, _desc in fields: |
| 249 | + # self._consume_returns_section() stores the header block |
| 250 | + # into `_type` argument, while `_name` has to be empty string and |
| 251 | + # `_desc` has to be empty list of strings |
| 252 | + if _name == "" and (not _desc or len(_desc) == 1 and _desc[0] == ""): |
| 253 | + if not is_logged_header: |
| 254 | + docstring.logger.info( |
| 255 | + "parse a header block of 'Returns' section", |
| 256 | + location=self._get_location(), |
| 257 | + ) |
| 258 | + is_logged_header = True |
| 259 | + |
| 260 | + # build a list with lines of the header block |
| 261 | + header.extend([_type]) |
| 262 | + continue |
| 263 | + |
| 264 | + if use_rtype: |
| 265 | + field = self._format_field(_name, "", _desc) |
| 266 | + else: |
| 267 | + field = self._format_field(_name, _type, _desc) |
| 268 | + |
| 269 | + if multi: |
| 270 | + if lines: |
| 271 | + lines.extend(self._format_block(" * ", field)) |
| 272 | + else: |
| 273 | + if header: |
| 274 | + # add the header block + the 1st parameter stored in `field` |
| 275 | + lines.extend([":returns:", ""]) |
| 276 | + lines.extend(self._format_block(" " * 4, header)) |
| 277 | + lines.extend(self._format_block(" * ", field)) |
| 278 | + else: |
| 279 | + lines.extend(self._format_block(":returns: * ", field)) |
| 280 | + else: |
| 281 | + if any(field): # only add :returns: if there's something to say |
| 282 | + lines.extend(self._format_block(":returns: ", field)) |
| 283 | + if _type and use_rtype: |
| 284 | + lines.extend([f":rtype: {_type}", ""]) |
| 285 | + if lines and lines[-1]: |
| 286 | + lines.append("") |
| 287 | + return lines |
| 288 | + |
| 289 | + |
| 290 | +NumpyDocstring._parse_returns_section = _parse_returns_section_patched |
0 commit comments