(docstring: str)
| 289 | |
| 290 | |
| 291 | def parse_docstring(docstring: str) -> DocstringData: |
| 292 | # Keep left indentation to recognize the sections. |
| 293 | lines = docstring.split("\n") |
| 294 | result = DocstringData( |
| 295 | name=lines[0].strip(), |
| 296 | description="", |
| 297 | param={}, |
| 298 | filter_glob={}, |
| 299 | output=None, |
| 300 | ) |
| 301 | |
| 302 | current_section = None |
| 303 | last_param = None |
| 304 | |
| 305 | PREFIXES = ("param", "filter_glob") |
| 306 | |
| 307 | for line in lines[1:]: |
| 308 | if line.startswith(":"): |
| 309 | line = line[1:] |
| 310 | if line.startswith(PREFIXES): |
| 311 | prefix = line.split(" ")[0] |
| 312 | current_section = prefix |
| 313 | match_ = re.match(rf"{prefix}\s+(\w+):\s+(.*)", line) |
| 314 | assert match_, f"Invalid line: '{line}'." |
| 315 | param_name, param_desc = match_.groups() |
| 316 | result[prefix][param_name] = param_desc |
| 317 | last_param = param_name |
| 318 | continue |
| 319 | elif line.startswith("return:"): |
| 320 | current_section = "output" |
| 321 | match_ = re.match(r"return:\s+(.*)", line) |
| 322 | assert match_ |
| 323 | result["output"] = match_.groups()[0] |
| 324 | continue |
| 325 | elif line.startswith("type"): |
| 326 | # Ignore types in favor of signature annotations. |
| 327 | continue |
| 328 | elif line.startswith("Example:"): |
| 329 | # Ignore code example at the end of the docstring. |
| 330 | break |
| 331 | |
| 332 | # Multiline sections start with indentation. |
| 333 | if line.startswith(" ") and current_section: |
| 334 | line = line.lstrip() |
| 335 | if current_section == "output": |
| 336 | assert result["output"] |
| 337 | result["output"] += f"\n{line}" |
| 338 | elif current_section in PREFIXES: |
| 339 | assert last_param |
| 340 | result[current_section][last_param] += f"\n{line}" |
| 341 | continue |
| 342 | |
| 343 | line = line.lstrip() |
| 344 | result["description"] += f"\n{line}" |
| 345 | current_section = None |
| 346 | last_param = None |
| 347 | |
| 348 | result["description"] = result["description"].strip() |
no test coverage detected