Coverage for tests/test_docstrings/test_sphinx.py: 100.00%
352 statements
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-12 01:34 +0200
« prev ^ index » next coverage.py v7.6.2, created at 2024-10-12 01:34 +0200
1"""Tests for the [Sphinx-style parser][griffe.docstrings.sphinx]."""
3from __future__ import annotations
5import inspect
6from typing import TYPE_CHECKING, Any
8import pytest
10from griffe import (
11 Attribute,
12 Class,
13 DocstringAttribute,
14 DocstringParameter,
15 DocstringRaise,
16 DocstringReturn,
17 DocstringSectionKind,
18 Function,
19 Module,
20 Parameter,
21 Parameters,
22)
24if TYPE_CHECKING:
25 from tests.test_docstrings.helpers import ParserType
27SOME_NAME = "foo"
28SOME_TEXT = "descriptive test text"
29SOME_EXTRA_TEXT = "more test text"
30SOME_EXCEPTION_NAME = "SomeException"
31SOME_OTHER_EXCEPTION_NAME = "SomeOtherException"
34@pytest.mark.parametrize(
35 "docstring",
36 [
37 "One line docstring description",
38 """
39 Multiple line docstring description.
41 With more text.
42 """,
43 ],
44)
45def test_parse__description_only_docstring__single_markdown_section(parse_sphinx: ParserType, docstring: str) -> None:
46 """Parse a single or multiline docstring.
48 Parameters:
49 parse_sphinx: Fixture parser.
50 docstring: A parametrized docstring.
51 """
52 sections, warnings = parse_sphinx(docstring)
54 assert len(sections) == 1
55 assert sections[0].kind is DocstringSectionKind.text
56 assert sections[0].value == inspect.cleandoc(docstring)
57 assert not warnings
60def test_parse__no_description__single_markdown_section(parse_sphinx: ParserType) -> None:
61 """Parse an empty docstring.
63 Parameters:
64 parse_sphinx: Fixture parser.
65 """
66 sections, warnings = parse_sphinx("")
68 assert len(sections) == 1
69 assert sections[0].kind is DocstringSectionKind.text
70 assert sections[0].value == ""
71 assert not warnings
74def test_parse__multiple_blank_lines_before_description__single_markdown_section(parse_sphinx: ParserType) -> None:
75 """Parse a docstring with initial blank lines.
77 Parameters:
78 parse_sphinx: Fixture parser.
79 """
80 sections, warnings = parse_sphinx(
81 """
84 Now text""",
85 )
87 assert len(sections) == 1
88 assert sections[0].kind is DocstringSectionKind.text
89 assert sections[0].value == "Now text"
90 assert not warnings
93def test_parse__param_field__param_section(parse_sphinx: ParserType) -> None:
94 """Parse a parameter section.
96 Parameters:
97 parse_sphinx: Fixture parser.
98 """
99 sections, _ = parse_sphinx(
100 f"""
101 Docstring with one line param.
103 :param {SOME_NAME}: {SOME_TEXT}
104 """,
105 )
106 assert len(sections) == 2
107 assert sections[1].kind is DocstringSectionKind.parameters
108 actual = sections[1].value[0]
109 expected = DocstringParameter(SOME_NAME, description=SOME_TEXT)
110 assert isinstance(actual, type(expected))
111 assert actual.as_dict() == expected.as_dict()
114def test_parse__only_param_field__empty_markdown(parse_sphinx: ParserType) -> None:
115 """Parse only a parameter section.
117 Parameters:
118 parse_sphinx: Fixture parser.
119 """
120 sections, _ = parse_sphinx(":param foo: text")
121 assert len(sections) == 2
122 assert sections[0].kind is DocstringSectionKind.text
123 assert sections[0].value == ""
126@pytest.mark.parametrize(
127 "param_directive_name",
128 [
129 "param",
130 "parameter",
131 "arg",
132 "arguments",
133 "key",
134 "keyword",
135 ],
136)
137def test_parse__all_param_names__param_section(parse_sphinx: ParserType, param_directive_name: str) -> None:
138 """Parse all parameters directives.
140 Parameters:
141 parse_sphinx: Fixture parser.
142 param_directive_name: A parametrized directive name.
143 """
144 sections, _ = parse_sphinx(
145 f"""
146 Docstring with one line param.
148 :{param_directive_name} {SOME_NAME}: {SOME_TEXT}
149 """,
150 )
151 assert len(sections) == 2
152 assert sections[1].kind is DocstringSectionKind.parameters
153 actual = sections[1].value[0]
154 expected = DocstringParameter(SOME_NAME, description=SOME_TEXT)
155 assert isinstance(actual, type(expected))
156 assert actual.as_dict() == expected.as_dict()
159@pytest.mark.parametrize(
160 "docstring",
161 [
162 f"""
163 Docstring with param with continuation, no indent.
165 :param {SOME_NAME}: {SOME_TEXT}
166 {SOME_EXTRA_TEXT}
167 """,
168 f"""
169 Docstring with param with continuation, with indent.
171 :param {SOME_NAME}: {SOME_TEXT}
172 {SOME_EXTRA_TEXT}
173 """,
174 ],
175)
176def test_parse__param_field_multi_line__param_section(parse_sphinx: ParserType, docstring: str) -> None:
177 """Parse multiline directives.
179 Parameters:
180 parse_sphinx: Fixture parser.
181 docstring: A parametrized docstring.
182 """
183 sections, _ = parse_sphinx(docstring)
184 assert len(sections) == 2
185 assert sections[1].kind is DocstringSectionKind.parameters
186 actual = sections[1].value[0]
187 expected = DocstringParameter(SOME_NAME, description=f"{SOME_TEXT} {SOME_EXTRA_TEXT}")
188 assert isinstance(actual, type(expected))
189 assert actual.as_dict() == expected.as_dict()
192def test_parse__param_field_for_function__param_section_with_kind(parse_sphinx: ParserType) -> None:
193 """Parse parameters.
195 Parameters:
196 parse_sphinx: Fixture parser.
197 """
198 docstring = f"""
199 Docstring with line continuation.
201 :param foo: {SOME_TEXT}
202 """
204 sections, _ = parse_sphinx(docstring)
205 assert len(sections) == 2
206 assert sections[1].kind is DocstringSectionKind.parameters
207 actual = sections[1].value[0]
208 expected = DocstringParameter(SOME_NAME, description=SOME_TEXT)
209 assert isinstance(actual, type(expected))
210 assert actual.as_dict() == expected.as_dict()
213def test_parse__param_field_docs_type__param_section_with_type(parse_sphinx: ParserType) -> None:
214 """Parse parameters with types.
216 Parameters:
217 parse_sphinx: Fixture parser.
218 """
219 docstring = f"""
220 Docstring with line continuation.
222 :param str foo: {SOME_TEXT}
223 """
225 sections, _ = parse_sphinx(docstring)
226 assert len(sections) == 2
227 assert sections[1].kind is DocstringSectionKind.parameters
228 actual = sections[1].value[0]
229 expected = DocstringParameter(SOME_NAME, annotation="str", description=SOME_TEXT)
230 assert isinstance(actual, type(expected))
231 assert actual.as_dict() == expected.as_dict()
234def test_parse__param_field_type_field__param_section_with_type(parse_sphinx: ParserType) -> None:
235 """Parse parameters with separated types.
237 Parameters:
238 parse_sphinx: Fixture parser.
239 """
240 docstring = f"""
241 Docstring with line continuation.
243 :param foo: {SOME_TEXT}
244 :type foo: str
245 """
247 sections, _ = parse_sphinx(docstring)
248 assert len(sections) == 2
249 assert sections[1].kind is DocstringSectionKind.parameters
250 actual = sections[1].value[0]
251 expected = DocstringParameter(SOME_NAME, annotation="str", description=SOME_TEXT)
252 assert isinstance(actual, type(expected))
253 assert actual.as_dict() == expected.as_dict()
256def test_parse__param_field_type_field_first__param_section_with_type(parse_sphinx: ParserType) -> None:
257 """Parse parameters with separated types first.
259 Parameters:
260 parse_sphinx: Fixture parser.
261 """
262 docstring = f"""
263 Docstring with line continuation.
265 :type foo: str
266 :param foo: {SOME_TEXT}
267 """
269 sections, _ = parse_sphinx(docstring)
270 assert len(sections) == 2
271 assert sections[1].kind is DocstringSectionKind.parameters
272 actual = sections[1].value[0]
273 expected = DocstringParameter(SOME_NAME, annotation="str", description=SOME_TEXT)
274 assert isinstance(actual, type(expected))
275 assert actual.as_dict() == expected.as_dict()
278@pytest.mark.parametrize("union", ["str or None", "None or str", "str or int", "str or int or float"])
279def test_parse__param_field_type_field_or_none__param_section_with_optional(
280 parse_sphinx: ParserType,
281 union: str,
282) -> None:
283 """Parse parameters with separated union types.
285 Parameters:
286 parse_sphinx: Fixture parser.
287 union: A parametrized union type.
288 """
289 docstring = f"""
290 Docstring with line continuation.
292 :param foo: {SOME_TEXT}
293 :type foo: {union}
294 """
296 sections, _ = parse_sphinx(docstring)
297 assert len(sections) == 2
298 assert sections[1].kind is DocstringSectionKind.parameters
299 actual = sections[1].value[0]
300 expected = DocstringParameter(SOME_NAME, annotation=union.replace(" or ", " | "), description=SOME_TEXT)
301 assert isinstance(actual, type(expected))
302 assert actual.as_dict() == expected.as_dict()
305def test_parse__param_field_annotate_type__param_section_with_type(parse_sphinx: ParserType) -> None:
306 """Parse a simple docstring.
308 Parameters:
309 parse_sphinx: Fixture parser.
310 """
311 docstring = f"""
312 Docstring with line continuation.
314 :param foo: {SOME_TEXT}
315 """
317 sections, warnings = parse_sphinx(
318 docstring,
319 parent=Function("func", parameters=Parameters(Parameter("foo", annotation="str", kind=None))),
320 )
321 assert len(sections) == 2
322 assert sections[1].kind is DocstringSectionKind.parameters
323 actual = sections[1].value[0]
324 expected = DocstringParameter(SOME_NAME, annotation="str", description=SOME_TEXT)
325 assert isinstance(actual, type(expected))
326 assert actual.as_dict() == expected.as_dict()
327 assert not warnings
330def test_parse__param_field_no_matching_param__result_from_docstring(parse_sphinx: ParserType) -> None:
331 """Parse a simple docstring.
333 Parameters:
334 parse_sphinx: Fixture parser.
335 """
336 docstring = f"""
337 Docstring with line continuation.
339 :param other: {SOME_TEXT}
340 """
342 sections, _ = parse_sphinx(docstring)
343 assert len(sections) == 2
344 assert sections[1].kind is DocstringSectionKind.parameters
345 actual = sections[1].value[0]
346 expected = DocstringParameter("other", description=SOME_TEXT)
347 assert isinstance(actual, type(expected))
348 assert actual.as_dict() == expected.as_dict()
351def test_parse__param_field_with_default__result_from_docstring(parse_sphinx: ParserType) -> None:
352 """Parse a simple docstring.
354 Parameters:
355 parse_sphinx: Fixture parser.
356 """
357 docstring = f"""
358 Docstring with line continuation.
360 :param foo: {SOME_TEXT}
361 """
363 sections, warnings = parse_sphinx(
364 docstring,
365 parent=Function("func", parameters=Parameters(Parameter("foo", kind=None, default=repr("")))),
366 )
367 assert len(sections) == 2
368 assert sections[1].kind is DocstringSectionKind.parameters
369 actual = sections[1].value[0]
370 expected = DocstringParameter("foo", description=SOME_TEXT, value=repr(""))
371 assert isinstance(actual, type(expected))
372 assert actual.as_dict() == expected.as_dict()
373 assert not warnings
376def test_parse__param_field_no_matching_param__error_message(parse_sphinx: ParserType) -> None:
377 """Parse a simple docstring.
379 Parameters:
380 parse_sphinx: Fixture parser.
381 """
382 docstring = f"""
383 Docstring with line continuation.
385 :param other: {SOME_TEXT}
386 """
388 _, warnings = parse_sphinx(docstring)
389 assert "No matching parameter for 'other'" in warnings[0]
392def test_parse__invalid_param_field_only_initial_marker__error_message(parse_sphinx: ParserType) -> None:
393 """Parse a simple docstring.
395 Parameters:
396 parse_sphinx: Fixture parser.
397 """
398 docstring = f"""
399 Docstring with line continuation.
401 :param foo {SOME_TEXT}
402 """
404 _, warnings = parse_sphinx(docstring)
405 assert "Failed to get ':directive: value' pair" in warnings[0]
408def test_parse__invalid_param_field_wrong_part_count__error_message(parse_sphinx: ParserType) -> None:
409 """Parse a simple docstring.
411 Parameters:
412 parse_sphinx: Fixture parser.
413 """
414 docstring = f"""
415 Docstring with line continuation.
417 :param: {SOME_TEXT}
418 """
420 _, warnings = parse_sphinx(docstring)
421 assert "Failed to parse field directive" in warnings[0]
424def test_parse__param_twice__error_message(parse_sphinx: ParserType) -> None:
425 """Parse a simple docstring.
427 Parameters:
428 parse_sphinx: Fixture parser.
429 """
430 docstring = f"""
431 Docstring with line continuation.
433 :param foo: {SOME_TEXT}
434 :param foo: {SOME_TEXT} again
435 """
437 _, warnings = parse_sphinx(
438 docstring,
439 parent=Function("func", parameters=Parameters(Parameter("foo", kind=None))),
440 )
441 assert "Duplicate parameter entry for 'foo'" in warnings[0]
444def test_parse__param_type_twice_doc__error_message(parse_sphinx: ParserType) -> None:
445 """Parse a simple docstring.
447 Parameters:
448 parse_sphinx: Fixture parser.
449 """
450 docstring = f"""
451 Docstring with line continuation.
453 :param str foo: {SOME_TEXT}
454 :type foo: str
455 """
457 _, warnings = parse_sphinx(
458 docstring,
459 parent=Function("func", parameters=Parameters(Parameter("foo", kind=None))),
460 )
461 assert "Duplicate parameter information for 'foo'" in warnings[0]
464def test_parse__param_type_twice_type_directive_first__error_message(parse_sphinx: ParserType) -> None:
465 """Parse a simple docstring.
467 Parameters:
468 parse_sphinx: Fixture parser.
469 """
470 docstring = f"""
471 Docstring with line continuation.
473 :type foo: str
474 :param str foo: {SOME_TEXT}
475 """
477 _, warnings = parse_sphinx(
478 docstring,
479 parent=Function("func", parameters=Parameters(Parameter("foo", kind=None))),
480 )
481 assert "Duplicate parameter information for 'foo'" in warnings[0]
484def test_parse__param_type_twice_annotated__error_message(parse_sphinx: ParserType) -> None:
485 """Parse a simple docstring.
487 Parameters:
488 parse_sphinx: Fixture parser.
489 """
490 docstring = f"""
491 Docstring with line continuation.
493 :param str foo: {SOME_TEXT}
494 :type foo: str
495 """
497 _, warnings = parse_sphinx(
498 docstring,
499 parent=Function("func", parameters=Parameters(Parameter("foo", annotation="str", kind=None))),
500 )
501 assert "Duplicate parameter information for 'foo'" in warnings[0]
504def test_warn_about_unknown_parameters(parse_sphinx: ParserType) -> None:
505 """Warn about unknown parameters in "Parameters" sections.
507 Parameters:
508 parse_sphinx: Fixture parser.
509 """
510 docstring = """
512 :param str a: {SOME_TEXT}
513 """
515 _, warnings = parse_sphinx(
516 docstring,
517 parent=Function(
518 "func",
519 parameters=Parameters(
520 Parameter("b"),
521 ),
522 ),
523 )
524 assert len(warnings) == 1
525 assert "Parameter 'a' does not appear in the function signature" in warnings[0]
528def test_parse__param_type_no_type__error_message(parse_sphinx: ParserType) -> None:
529 """Parse a simple docstring.
531 Parameters:
532 parse_sphinx: Fixture parser.
533 """
534 docstring = f"""
535 Docstring with line continuation.
537 :param str foo: {SOME_TEXT}
538 :type str
539 """
541 _, warnings = parse_sphinx(
542 docstring,
543 parent=Function("func", parameters=Parameters(Parameter("foo", annotation="str", kind=None))),
544 )
545 assert "Failed to get ':directive: value' pair from" in warnings[0]
548def test_parse__param_type_no_name__error_message(parse_sphinx: ParserType) -> None:
549 """Parse a simple docstring.
551 Parameters:
552 parse_sphinx: Fixture parser.
553 """
554 docstring = f"""
555 Docstring with line continuation.
557 :param str foo: {SOME_TEXT}
558 :type: str
559 """
561 _, warnings = parse_sphinx(
562 docstring,
563 parent=Function("func", parameters=Parameters(Parameter("foo", annotation="str", kind=None))),
564 )
565 assert "Failed to get parameter name from" in warnings[0]
568@pytest.mark.parametrize(
569 "docstring",
570 [
571 f"""
572 Docstring with param with continuation, no indent.
574 :var {SOME_NAME}: {SOME_TEXT}
575 {SOME_EXTRA_TEXT}
576 """,
577 f"""
578 Docstring with param with continuation, with indent.
580 :var {SOME_NAME}: {SOME_TEXT}
581 {SOME_EXTRA_TEXT}
582 """,
583 ],
584)
585def test_parse__attribute_field_multi_line__param_section(parse_sphinx: ParserType, docstring: str) -> None:
586 """Parse multiline attributes.
588 Parameters:
589 parse_sphinx: Fixture parser.
590 docstring: A parametrized docstring.
591 """
592 sections, warnings = parse_sphinx(docstring)
593 assert len(sections) == 2
594 assert sections[1].kind is DocstringSectionKind.attributes
595 actual = sections[1].value[0]
596 expected = DocstringAttribute(SOME_NAME, description=f"{SOME_TEXT} {SOME_EXTRA_TEXT}")
597 assert isinstance(actual, type(expected))
598 assert actual.as_dict() == expected.as_dict()
599 assert not warnings
602@pytest.mark.parametrize(
603 "attribute_directive_name",
604 [
605 "var",
606 "ivar",
607 "cvar",
608 ],
609)
610def test_parse__all_attribute_names__param_section(parse_sphinx: ParserType, attribute_directive_name: str) -> None:
611 """Parse all attributes directives.
613 Parameters:
614 parse_sphinx: Fixture parser.
615 attribute_directive_name: A parametrized directive name.
616 """
617 sections, warnings = parse_sphinx(
618 f"""
619 Docstring with one line attribute.
621 :{attribute_directive_name} {SOME_NAME}: {SOME_TEXT}
622 """,
623 )
624 assert len(sections) == 2
625 assert sections[1].kind is DocstringSectionKind.attributes
626 actual = sections[1].value[0]
627 expected = DocstringAttribute(SOME_NAME, description=SOME_TEXT)
628 assert isinstance(actual, type(expected))
629 assert actual.as_dict() == expected.as_dict()
630 assert not warnings
633def test_parse__class_attributes__attributes_section(parse_sphinx: ParserType) -> None:
634 """Parse class attributes.
636 Parameters:
637 parse_sphinx: Fixture parser.
638 """
639 docstring = f"""
640 Class docstring with attributes
642 :var foo: {SOME_TEXT}
643 """
645 sections, _ = parse_sphinx(docstring, parent=Class("klass"))
646 assert len(sections) == 2
647 assert sections[1].kind is DocstringSectionKind.attributes
648 actual = sections[1].value[0]
649 expected = DocstringAttribute(SOME_NAME, description=SOME_TEXT)
650 assert isinstance(actual, type(expected))
651 assert actual.as_dict() == expected.as_dict()
654def test_parse__class_attributes_with_type__annotation_in_attributes_section(parse_sphinx: ParserType) -> None:
655 """Parse typed class attributes.
657 Parameters:
658 parse_sphinx: Fixture parser.
659 """
660 docstring = f"""
661 Class docstring with attributes
663 :vartype foo: str
664 :var foo: {SOME_TEXT}
665 """
667 sections, _ = parse_sphinx(docstring, parent=Class("klass"))
668 assert len(sections) == 2
669 assert sections[1].kind is DocstringSectionKind.attributes
670 actual = sections[1].value[0]
671 expected = DocstringAttribute(SOME_NAME, annotation="str", description=SOME_TEXT)
672 assert isinstance(actual, type(expected))
673 assert actual.as_dict() == expected.as_dict()
676def test_parse__attribute_invalid_directive___error(parse_sphinx: ParserType) -> None:
677 """Warn on invalid attribute directive.
679 Parameters:
680 parse_sphinx: Fixture parser.
681 """
682 docstring = f"""
683 Class docstring with attributes
685 :var {SOME_TEXT}
686 """
688 _, warnings = parse_sphinx(docstring)
689 assert "Failed to get ':directive: value' pair from" in warnings[0]
692def test_parse__attribute_no_name__error(parse_sphinx: ParserType) -> None:
693 """Warn on invalid attribute directive.
695 Parameters:
696 parse_sphinx: Fixture parser.
697 """
698 docstring = f"""
699 Class docstring with attributes
701 :var: {SOME_TEXT}
702 """
704 _, warnings = parse_sphinx(docstring)
705 assert "Failed to parse field directive from" in warnings[0]
708def test_parse__attribute_duplicate__error(parse_sphinx: ParserType) -> None:
709 """Warn on duplicate attribute directive.
711 Parameters:
712 parse_sphinx: Fixture parser.
713 """
714 docstring = f"""
715 Class docstring with attributes
717 :var foo: {SOME_TEXT}
718 :var foo: {SOME_TEXT}
719 """
721 _, warnings = parse_sphinx(docstring)
722 assert "Duplicate attribute entry for 'foo'" in warnings[0]
725def test_parse__class_attributes_type_invalid__error(parse_sphinx: ParserType) -> None:
726 """Warn on invalid attribute type directive.
728 Parameters:
729 parse_sphinx: Fixture parser.
730 """
731 docstring = f"""
732 Class docstring with attributes
734 :vartype str
735 :var foo: {SOME_TEXT}
736 """
738 _, warnings = parse_sphinx(docstring)
739 assert "Failed to get ':directive: value' pair from " in warnings[0]
742def test_parse__class_attributes_type_no_name__error(parse_sphinx: ParserType) -> None:
743 """Warn on invalid attribute directive.
745 Parameters:
746 parse_sphinx: Fixture parser.
747 """
748 docstring = f"""
749 Class docstring with attributes
751 :vartype: str
752 :var foo: {SOME_TEXT}
753 """
755 _, warnings = parse_sphinx(docstring)
756 assert "Failed to get attribute name from" in warnings[0]
759def test_parse__return_directive__return_section_no_type(parse_sphinx: ParserType) -> None:
760 """Parse return directives.
762 Parameters:
763 parse_sphinx: Fixture parser.
764 """
765 docstring = f"""
766 Function with only return directive
768 :return: {SOME_TEXT}
769 """
771 sections, _ = parse_sphinx(docstring)
772 assert len(sections) == 2
773 assert sections[1].kind is DocstringSectionKind.returns
774 actual = sections[1].value[0]
775 expected = DocstringReturn(name="", annotation=None, description=SOME_TEXT)
776 assert isinstance(actual, type(expected))
777 assert actual.as_dict() == expected.as_dict()
780def test_parse__return_directive_rtype__return_section_with_type(parse_sphinx: ParserType) -> None:
781 """Parse typed return directives.
783 Parameters:
784 parse_sphinx: Fixture parser.
785 """
786 docstring = f"""
787 Function with only return & rtype directive
789 :return: {SOME_TEXT}
790 :rtype: str
791 """
793 sections, _ = parse_sphinx(docstring)
794 assert len(sections) == 2
795 assert sections[1].kind is DocstringSectionKind.returns
796 actual = sections[1].value[0]
797 expected = DocstringReturn(name="", annotation="str", description=SOME_TEXT)
798 assert isinstance(actual, type(expected))
799 assert actual.as_dict() == expected.as_dict()
802def test_parse__return_directive_rtype_first__return_section_with_type(parse_sphinx: ParserType) -> None:
803 """Parse typed-first return directives.
805 Parameters:
806 parse_sphinx: Fixture parser.
807 """
808 docstring = f"""
809 Function with only return & rtype directive
811 :rtype: str
812 :return: {SOME_TEXT}
813 """
815 sections, _ = parse_sphinx(docstring)
816 assert len(sections) == 2
817 assert sections[1].kind is DocstringSectionKind.returns
818 actual = sections[1].value[0]
819 expected = DocstringReturn(name="", annotation="str", description=SOME_TEXT)
820 assert isinstance(actual, type(expected))
821 assert actual.as_dict() == expected.as_dict()
824def test_parse__return_directive_annotation__return_section_with_type(parse_sphinx: ParserType) -> None:
825 """Parse return directives with return annotation.
827 Parameters:
828 parse_sphinx: Fixture parser.
829 """
830 docstring = f"""
831 Function with return directive, rtype directive, & annotation
833 :return: {SOME_TEXT}
834 """
836 sections, _ = parse_sphinx(docstring, parent=Function("func", returns="str"))
837 assert len(sections) == 2
838 assert sections[1].kind is DocstringSectionKind.returns
839 actual = sections[1].value[0]
840 expected = DocstringReturn(name="", annotation="str", description=SOME_TEXT)
841 assert isinstance(actual, type(expected))
842 assert actual.as_dict() == expected.as_dict()
845def test_parse__return_directive_annotation__prefer_return_directive(parse_sphinx: ParserType) -> None:
846 """Prefer docstring type over return annotation.
848 Parameters:
849 parse_sphinx: Fixture parser.
850 """
851 docstring = f"""
852 Function with return directive, rtype directive, & annotation
854 :return: {SOME_TEXT}
855 :rtype: str
856 """
858 sections, _ = parse_sphinx(docstring, parent=Function("func", returns="int"))
859 assert len(sections) == 2
860 assert sections[1].kind is DocstringSectionKind.returns
861 actual = sections[1].value[0]
862 expected = DocstringReturn(name="", annotation="str", description=SOME_TEXT)
863 assert isinstance(actual, type(expected))
864 assert actual.as_dict() == expected.as_dict()
867def test_parse__return_invalid__error(parse_sphinx: ParserType) -> None:
868 """Warn on invalid return directive.
870 Parameters:
871 parse_sphinx: Fixture parser.
872 """
873 docstring = f"""
874 Function with only return directive
876 :return {SOME_TEXT}
877 """
879 _, warnings = parse_sphinx(docstring)
880 assert "Failed to get ':directive: value' pair from " in warnings[0]
883def test_parse__rtype_invalid__error(parse_sphinx: ParserType) -> None:
884 """Warn on invalid typed return directive.
886 Parameters:
887 parse_sphinx: Fixture parser.
888 """
889 docstring = """
890 Function with only return directive
892 :rtype str
893 """
895 _, warnings = parse_sphinx(docstring)
896 assert "Failed to get ':directive: value' pair from " in warnings[0]
899def test_parse__raises_directive__exception_section(parse_sphinx: ParserType) -> None:
900 """Parse raise directives.
902 Parameters:
903 parse_sphinx: Fixture parser.
904 """
905 docstring = f"""
906 Function with only return directive
908 :raise SomeException: {SOME_TEXT}
909 """
911 sections, _ = parse_sphinx(docstring)
912 assert len(sections) == 2
913 assert sections[1].kind is DocstringSectionKind.raises
914 actual = sections[1].value[0]
915 expected = DocstringRaise(annotation=SOME_EXCEPTION_NAME, description=SOME_TEXT)
916 assert isinstance(actual, type(expected))
917 assert actual.as_dict() == expected.as_dict()
920def test_parse__multiple_raises_directive__exception_section_with_two(parse_sphinx: ParserType) -> None:
921 """Parse multiple raise directives.
923 Parameters:
924 parse_sphinx: Fixture parser.
925 """
926 docstring = f"""
927 Function with only return directive
929 :raise SomeException: {SOME_TEXT}
930 :raise SomeOtherException: {SOME_TEXT}
931 """
933 sections, _ = parse_sphinx(docstring)
934 assert len(sections) == 2
935 assert sections[1].kind is DocstringSectionKind.raises
936 actual = sections[1].value[0]
937 expected = DocstringRaise(annotation=SOME_EXCEPTION_NAME, description=SOME_TEXT)
938 assert isinstance(actual, type(expected))
939 assert actual.as_dict() == expected.as_dict()
940 actual = sections[1].value[1]
941 expected = DocstringRaise(annotation=SOME_OTHER_EXCEPTION_NAME, description=SOME_TEXT)
942 assert isinstance(actual, type(expected))
943 assert actual.as_dict() == expected.as_dict()
946@pytest.mark.parametrize(
947 "raise_directive_name",
948 [
949 "raises",
950 "raise",
951 "except",
952 "exception",
953 ],
954)
955def test_parse__all_exception_names__param_section(parse_sphinx: ParserType, raise_directive_name: str) -> None:
956 """Parse all raise directives.
958 Parameters:
959 parse_sphinx: Fixture parser.
960 raise_directive_name: A parametrized directive name.
961 """
962 sections, _ = parse_sphinx(
963 f"""
964 Docstring with one line attribute.
966 :{raise_directive_name} {SOME_EXCEPTION_NAME}: {SOME_TEXT}
967 """,
968 )
969 assert len(sections) == 2
970 assert sections[1].kind is DocstringSectionKind.raises
971 actual = sections[1].value[0]
972 expected = DocstringRaise(annotation=SOME_EXCEPTION_NAME, description=SOME_TEXT)
973 assert isinstance(actual, type(expected))
974 assert actual.as_dict() == expected.as_dict()
977def test_parse__raise_invalid__error(parse_sphinx: ParserType) -> None:
978 """Warn on invalid raise directives.
980 Parameters:
981 parse_sphinx: Fixture parser.
982 """
983 docstring = f"""
984 Function with only return directive
986 :raise {SOME_TEXT}
987 """
989 _, warnings = parse_sphinx(docstring)
990 assert "Failed to get ':directive: value' pair from " in warnings[0]
993def test_parse__raise_no_name__error(parse_sphinx: ParserType) -> None:
994 """Warn on invalid raise directives.
996 Parameters:
997 parse_sphinx: Fixture parser.
998 """
999 docstring = f"""
1000 Function with only return directive
1002 :raise: {SOME_TEXT}
1003 """
1005 _, warnings = parse_sphinx(docstring)
1006 assert "Failed to parse exception directive from" in warnings[0]
1009def test_parse__module_attributes_section__expected_attributes_section(parse_sphinx: ParserType) -> None:
1010 """Parse attributes section in modules.
1012 Parameters:
1013 parse_sphinx: Fixture parser.
1014 """
1015 docstring = """
1016 Let's describe some attributes.
1018 :var A: Alpha.
1019 :vartype B: bytes
1020 :var B: Beta.
1021 :var C: Gamma.
1022 :var D: Delta.
1023 :var E: Epsilon.
1024 :vartype E: float
1025 """
1027 module = Module("mod", filepath=None)
1028 module["A"] = Attribute("A", annotation="int", value="0")
1029 module["B"] = Attribute("B", annotation="str", value=repr("ŧ"))
1030 module["C"] = Attribute("C", annotation="bool", value="True")
1031 module["D"] = Attribute("D", annotation=None, value="3.0")
1032 module["E"] = Attribute("E", annotation=None, value="None")
1033 sections, warnings = parse_sphinx(docstring, parent=module)
1035 attr_section = sections[1]
1036 assert attr_section.kind is DocstringSectionKind.attributes
1037 assert len(attr_section.value) == 5
1038 expected_data: list[dict[str, Any]] = [
1039 {"name": "A", "annotation": "int", "description": "Alpha."},
1040 {"name": "B", "annotation": "bytes", "description": "Beta."},
1041 {"name": "C", "annotation": "bool", "description": "Gamma."},
1042 {"name": "D", "annotation": None, "description": "Delta."},
1043 {"name": "E", "annotation": "float", "description": "Epsilon."},
1044 ]
1045 for index, expected_kwargs in enumerate(expected_data):
1046 actual = attr_section.value[index]
1047 expected = DocstringAttribute(**expected_kwargs)
1048 assert isinstance(actual, type(expected))
1049 assert actual.name == expected.name
1050 assert actual.as_dict() == expected.as_dict()
1051 assert not warnings
1054def test_parse__properties_return_type(parse_sphinx: ParserType) -> None:
1055 """Parse attributes section in modules.
1057 Parameters:
1058 parse_sphinx: Fixture parser.
1059 """
1060 docstring = """
1061 Property that returns True for explaining the issue.
1063 :return: True
1064 """
1065 prop = Attribute("example", annotation="bool")
1066 sections, warnings = parse_sphinx(docstring, parent=prop)
1067 assert not warnings
1068 assert sections[1].value[0].annotation == "bool"