|
30 | 30 | import textwrap |
31 | 31 | from typing import Iterable, List, Tuple, Union |
32 | 32 |
|
33 | | -SPHINX_REGEX = r":[a-zA-Z0-9_\- ]*:" |
34 | | -"""Regular expression to use for finding Sphinx-style field lists.""" |
| 33 | +BULLET_REGEX = r"\s*[*\-+] [\S ]+" |
| 34 | +"""Regular expression to use for finding bullet lists.""" |
| 35 | + |
| 36 | +ENUM_REGEX = r"\s*\d\." |
| 37 | +"""Regular expression to use for finding enumerated lists.""" |
| 38 | + |
| 39 | +EPYTEXT_REGEX = r"@[a-zA-Z0-9_\-\s]+:" |
| 40 | +"""Regular expression to use for finding Epytext-style field lists.""" |
| 41 | + |
| 42 | +GOOGLE_REGEX = r"^ *[a-zA-Z0-9_\- ]*:$" |
| 43 | +"""Regular expression to use for finding Google-style field lists.""" |
| 44 | + |
| 45 | +LITERAL_REGEX = r"[\S ]*::" |
| 46 | +"""Regular expression to use for finding literal blocks.""" |
| 47 | + |
| 48 | +NUMPY_REGEX = r"^\s[a-zA-Z0-9_\- ]+ ?: [\S ]+" |
| 49 | +"""Regular expression to use for finding Numpy-style field lists.""" |
| 50 | + |
| 51 | +OPTION_REGEX = r"^-{1,2}[\S ]+ {2}\S+" |
| 52 | +"""Regular expression to use for finding option lists.""" |
35 | 53 |
|
36 | 54 | REST_REGEX = r"(\.{2}|``) ?[\w-]+(:{1,2}|``)?" |
37 | 55 | """Regular expression to use for finding reST directives.""" |
38 | 56 |
|
| 57 | +SPHINX_REGEX = r":[a-zA-Z0-9_\- ]*:" |
| 58 | +"""Regular expression to use for finding Sphinx-style field lists.""" |
| 59 | + |
39 | 60 | URL_PATTERNS = ( |
40 | 61 | "afp|" |
41 | 62 | "apt|" |
@@ -238,22 +259,36 @@ def do_find_directives(text: str) -> bool: |
238 | 259 | return bool([(_rest.start(0), _rest.end(0)) for _rest in _rest_iter]) |
239 | 260 |
|
240 | 261 |
|
241 | | -def do_find_sphinx_field_lists(text: str) -> List[Tuple[int, int]]: |
| 262 | +def do_find_field_lists(text: str, style: str): |
242 | 263 | r"""Determine if docstring contains any field lists. |
243 | 264 |
|
244 | 265 | Parameters |
245 | 266 | ---------- |
246 | 267 | text : str |
247 | 268 | The docstring description to check for field list patterns. |
| 269 | + style : str |
| 270 | + The field list style used. |
248 | 271 |
|
249 | 272 | Returns |
250 | 273 | ------- |
251 | | - field_index : list |
| 274 | + _field_idx, _wrap_parameters : tuple |
252 | 275 | A list of tuples with each tuple containing the starting and ending |
253 | 276 | position of each field list found in the passed description. |
| 277 | + A boolean indicating whether long field list lines should be wrapped. |
254 | 278 | """ |
255 | | - _field_iter = re.finditer(SPHINX_REGEX, text) |
256 | | - return [(_field.start(0), _field.end(0)) for _field in _field_iter] |
| 279 | + _field_idx = [] |
| 280 | + _wrap_parameters = False |
| 281 | + |
| 282 | + if style == "epytext": |
| 283 | + _field_iter = re.finditer(EPYTEXT_REGEX, text) |
| 284 | + _field_idx = [(_field.start(0), _field.end(0)) for _field in _field_iter] |
| 285 | + _wrap_parameters = True |
| 286 | + elif style == "sphinx": |
| 287 | + _field_iter = re.finditer(SPHINX_REGEX, text) |
| 288 | + _field_idx = [(_field.start(0), _field.end(0)) for _field in _field_iter] |
| 289 | + _wrap_parameters = True |
| 290 | + |
| 291 | + return _field_idx, _wrap_parameters |
257 | 292 |
|
258 | 293 |
|
259 | 294 | def do_find_links(text: str) -> List[Tuple[int, int]]: |
@@ -333,12 +368,9 @@ def do_split_description( |
333 | 368 |
|
334 | 369 | # Check if the description contains any URLs. |
335 | 370 | _url_idx = do_find_links(text) |
336 | | - if style == "sphinx": |
337 | | - _parameter_idx = do_find_sphinx_field_lists(text) |
338 | | - _wrap_parameters = True |
339 | | - else: |
340 | | - _parameter_idx = [] |
341 | | - _wrap_parameters = False |
| 371 | + |
| 372 | + # Check if the description contains any field lists. |
| 373 | + _parameter_idx, _wrap_parameters = do_find_field_lists(text, style) |
342 | 374 |
|
343 | 375 | if not _url_idx and not (_parameter_idx and _wrap_parameters): |
344 | 376 | return description_to_list( |
@@ -511,6 +543,47 @@ def do_wrap_urls( |
511 | 543 | return _lines, text_idx |
512 | 544 |
|
513 | 545 |
|
| 546 | +def is_some_sort_of_field_list( |
| 547 | + text: str, |
| 548 | + style: str, |
| 549 | +) -> bool: |
| 550 | + """Determine if docstring contains field lists. |
| 551 | +
|
| 552 | + Parameters |
| 553 | + ---------- |
| 554 | + text : str |
| 555 | + The docstring text. |
| 556 | + style : str |
| 557 | + The field list style to use. |
| 558 | +
|
| 559 | + Returns |
| 560 | + ------- |
| 561 | + is_field_list : bool |
| 562 | + Whether the field list pattern for style was found in the docstring. |
| 563 | + """ |
| 564 | + split_lines = text.rstrip().splitlines() |
| 565 | + |
| 566 | + if style == "epytext": |
| 567 | + return any( |
| 568 | + ( |
| 569 | + # "@param x:" <-- Epytext style |
| 570 | + # "@type x:" <-- Epytext style |
| 571 | + re.match(EPYTEXT_REGEX, line) |
| 572 | + ) |
| 573 | + for line in split_lines |
| 574 | + ) |
| 575 | + elif style == "sphinx": |
| 576 | + return any( |
| 577 | + ( |
| 578 | + # ":parameter: description" <-- Sphinx style |
| 579 | + re.match(SPHINX_REGEX, line) |
| 580 | + ) |
| 581 | + for line in split_lines |
| 582 | + ) |
| 583 | + |
| 584 | + return False |
| 585 | + |
| 586 | + |
514 | 587 | # pylint: disable=line-too-long |
515 | 588 | def is_some_sort_of_list( |
516 | 589 | text: str, |
@@ -545,81 +618,55 @@ def is_some_sort_of_list( |
545 | 618 | ) and not strict: |
546 | 619 | return True |
547 | 620 |
|
548 | | - if style == "sphinx": |
549 | | - return any( |
550 | | - ( |
551 | | - # "* parameter" <-- Bullet list |
552 | | - # "- parameter" <-- Bullet list |
553 | | - # "+ parameter" <-- Bullet list |
554 | | - re.match(r"\s*[*\-+] [\S ]+", line) |
555 | | - or |
556 | | - # "1. item" <-- Enumerated list |
557 | | - re.match(r"\s*\d\.", line) |
558 | | - or |
559 | | - # "-a description" <-- Option list |
560 | | - # "--long description" <-- Option list |
561 | | - re.match(r"^-{1,2}[\S ]+ {2}\S+", line) |
562 | | - or |
563 | | - # "@parameter" <-- Epydoc style |
564 | | - re.match(r"\s*@\S*", line) |
565 | | - or |
566 | | - # "parameter : description" <-- Numpy style |
567 | | - # "parameter: description" <-- Numpy style |
568 | | - re.match(r"^\s*(?!:)\S+ ?: \S+", line) |
569 | | - or |
570 | | - # "word\n----" <-- Numpy headings |
571 | | - re.match(r"^\s*-+", line) |
572 | | - or |
573 | | - # "parameter - description" |
574 | | - re.match(r"[\S ]+ - \S+", line) |
575 | | - or |
576 | | - # "parameter -- description" |
577 | | - re.match(r"\s*\S+\s+--\s+", line) |
578 | | - or |
579 | | - # Literal block |
580 | | - re.match(r"[\S ]*::", line) |
581 | | - ) |
582 | | - for line in split_lines |
583 | | - ) |
584 | | - else: |
585 | | - return any( |
586 | | - ( |
587 | | - # "* parameter" <-- Bullet list |
588 | | - # "- parameter" <-- Bullet list |
589 | | - # "+ parameter" <-- Bullet list |
590 | | - re.match(r"\s*[*\-+] [\S ]+", line) |
591 | | - or |
592 | | - # "1. item" <-- Enumerated list |
593 | | - re.match(r"\s*\d\.", line) |
594 | | - or |
595 | | - # "-a description" <-- Option list |
596 | | - # "--long description" <-- Option list |
597 | | - re.match(r"^-{1,2}[\S ]+ {2}\S+", line) |
598 | | - or |
599 | | - # "@parameter" <-- Epydoc style |
600 | | - re.match(r"\s*@\S*", line) |
601 | | - or |
602 | | - # ":parameter: description" <-- Sphinx style |
603 | | - re.match(SPHINX_REGEX, line) |
604 | | - or |
605 | | - # "parameter : description" <-- Numpy style |
606 | | - # "parameter: description" <-- Numpy style |
607 | | - re.match(r"^\s[\S ]+ ?: [\S ]+", line) |
608 | | - or |
609 | | - # "word\n----" <-- Numpy headings |
610 | | - re.match(r"^\s*-+", line) |
611 | | - or |
612 | | - # "parameter - description" |
613 | | - re.match(r"[\S ]+ - \S+", line) |
614 | | - or |
615 | | - # "parameter -- description" |
616 | | - re.match(r"\s*\S+\s+--\s+", line) |
617 | | - or |
618 | | - # Literal block |
619 | | - re.match(r"[\S ]*::", line) |
620 | | - ) |
621 | | - for line in split_lines |
| 621 | + if is_some_sort_of_field_list(text, style): |
| 622 | + return False |
| 623 | + |
| 624 | + return any( |
| 625 | + ( |
| 626 | + # "* parameter" <-- Bullet list |
| 627 | + # "- parameter" <-- Bullet list |
| 628 | + # "+ parameter" <-- Bullet list |
| 629 | + re.match(BULLET_REGEX, line) |
| 630 | + or |
| 631 | + # "1. item" <-- Enumerated list |
| 632 | + re.match(ENUM_REGEX, line) |
| 633 | + or |
| 634 | + # "-a description" <-- Option list |
| 635 | + # "--long description" <-- Option list |
| 636 | + re.match(OPTION_REGEX, line) |
| 637 | + or |
| 638 | + # "@param x:" <-- Epytext style |
| 639 | + # "@type x:" <-- Epytext style |
| 640 | + re.match(EPYTEXT_REGEX, line) |
| 641 | + or |
| 642 | + # ":parameter: description" <-- Sphinx style |
| 643 | + re.match(SPHINX_REGEX, line) |
| 644 | + or |
| 645 | + # "parameter : description" <-- Numpy style |
| 646 | + # "parameter: description" <-- Numpy style |
| 647 | + re.match(NUMPY_REGEX, line) |
| 648 | + or |
| 649 | + # "word\n----" <-- Numpy headings |
| 650 | + re.match(r"^\s*-+", line) |
| 651 | + or |
| 652 | + # "Args:" <-- Google style |
| 653 | + # "parameter:" <-- Google style |
| 654 | + re.match(GOOGLE_REGEX, line) |
| 655 | + or |
| 656 | + # "parameter - description" |
| 657 | + re.match(r"[\S ]+ - \S+", line) |
| 658 | + or |
| 659 | + # "parameter -- description" |
| 660 | + re.match(r"\s*\S+\s+--\s+", line) |
| 661 | + or |
| 662 | + # Literal block |
| 663 | + re.match(LITERAL_REGEX, line) |
| 664 | + or |
| 665 | + # "@parameter" |
| 666 | + re.match(r"^ *@[a-zA-Z0-9_\- ]*(?:(?!:).)*$", line) |
622 | 667 | ) |
| 668 | + for line in split_lines |
| 669 | + ) |
623 | 670 |
|
624 | 671 |
|
625 | 672 | def is_some_sort_of_code(text: str) -> bool: |
|
0 commit comments