Coverage for tests / test_docstrings / test_google.py: 100.00%

584 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-11 11:48 +0100

1"""Tests for the [Google-style parser][griffe.docstrings.google].""" 

2 

3from __future__ import annotations 

4 

5import inspect 

6from typing import TYPE_CHECKING 

7 

8import pytest 

9 

10from griffe import ( 

11 Attribute, 

12 Class, 

13 Docstring, 

14 DocstringReceive, 

15 DocstringReturn, 

16 DocstringSectionKind, 

17 DocstringYield, 

18 ExprName, 

19 Function, 

20 Module, 

21 Parameter, 

22 Parameters, 

23 TypeParameter, 

24 TypeParameterKind, 

25 TypeParameters, 

26 parse_docstring_annotation, 

27) 

28 

29if TYPE_CHECKING: 

30 from tests.test_docstrings.helpers import ParserType 

31 

32 

33# ============================================================================================= 

34# Markup flow (multilines, indentation, etc.) 

35def test_simple_docstring(parse_google: ParserType) -> None: 

36 """Parse a simple docstring. 

37 

38 Parameters: 

39 parse_google: Fixture parser. 

40 """ 

41 sections, warnings = parse_google("A simple docstring.") 

42 assert len(sections) == 1 

43 assert not warnings 

44 

45 

46def test_multiline_docstring(parse_google: ParserType) -> None: 

47 """Parse a multi-line docstring. 

48 

49 Parameters: 

50 parse_google: Fixture parser. 

51 """ 

52 sections, warnings = parse_google( 

53 """ 

54 A somewhat longer docstring. 

55 

56 Blablablabla. 

57 """, 

58 ) 

59 assert len(sections) == 1 

60 assert not warnings 

61 

62 

63def test_parse_partially_indented_lines(parse_google: ParserType) -> None: 

64 """Properly handle partially indented lines. 

65 

66 Parameters: 

67 parse_google: Fixture parser. 

68 """ 

69 docstring = """ 

70 The available formats are: 

71 - JSON 

72 

73 The unavailable formats are: 

74 - YAML 

75 """ 

76 sections, warnings = parse_google(docstring) 

77 assert len(sections) == 2 

78 assert sections[0].kind is DocstringSectionKind.admonition 

79 assert sections[1].kind is DocstringSectionKind.admonition 

80 assert not warnings 

81 

82 

83def test_multiple_lines_in_sections_items(parse_google: ParserType) -> None: 

84 """Parse multi-line item description. 

85 

86 Parameters: 

87 parse_google: Fixture parser. 

88 """ 

89 docstring = """ 

90 Parameters: 

91 p (int): This parameter 

92 has a description 

93 spawning on multiple lines. 

94 

95 It even has blank lines in it. 

96 Some of these lines 

97 are indented for no reason. 

98 q (int): 

99 What if the first line is blank? 

100 """ 

101 

102 sections, warnings = parse_google(docstring) 

103 assert len(sections) == 1 

104 assert len(sections[0].value) == 2 

105 assert warnings 

106 for warning in warnings: 

107 assert "should be 4 * 2 = 8 spaces, not" in warning 

108 

109 

110def test_code_blocks(parse_google: ParserType) -> None: 

111 """Parse code blocks. 

112 

113 Parameters: 

114 parse_google: Fixture parser. 

115 """ 

116 docstring = """ 

117 This docstring contains a code block! 

118 

119 ```python 

120 print("hello") 

121 ``` 

122 """ 

123 

124 sections, warnings = parse_google(docstring) 

125 assert len(sections) == 1 

126 assert not warnings 

127 

128 

129def test_indented_code_block(parse_google: ParserType) -> None: 

130 """Parse indented code blocks. 

131 

132 Parameters: 

133 parse_google: Fixture parser. 

134 """ 

135 docstring = """ 

136 This docstring contains a docstring in a code block o_O! 

137 

138 \"\"\" 

139 This docstring is contained in another docstring O_o! 

140 

141 Parameters: 

142 s: A string. 

143 \"\"\" 

144 """ 

145 

146 sections, warnings = parse_google(docstring) 

147 assert len(sections) == 1 

148 assert not warnings 

149 

150 

151def test_different_indentation(parse_google: ParserType) -> None: 

152 """Parse different indentations, warn on confusing indentation. 

153 

154 Parameters: 

155 parse_google: Fixture parser. 

156 """ 

157 docstring = """ 

158 Raises: 

159 StartAt5: this section's items starts with 5 spaces of indentation. 

160 Well indented continuation line. 

161 Badly indented continuation line (will trigger a warning). 

162 

163 Empty lines are preserved, as well as extra-indentation (this line is a code block). 

164 AnyOtherLine: ...starting with exactly 5 spaces is a new item. 

165 AnyLine: ...indented with less than 5 spaces signifies the end of the section. 

166 """ 

167 

168 sections, warnings = parse_google(docstring) 

169 assert len(sections) == 2 

170 assert len(sections[0].value) == 2 

171 assert sections[0].value[0].description == ( 

172 "this section's items starts with 5 spaces of indentation.\n" 

173 "Well indented continuation line.\n" 

174 "Badly indented continuation line (will trigger a warning).\n" 

175 "\n" 

176 " Empty lines are preserved, as well as extra-indentation (this line is a code block)." 

177 ) 

178 assert sections[1].value == " AnyLine: ...indented with less than 5 spaces signifies the end of the section." 

179 assert len(warnings) == 1 

180 assert "should be 5 * 2 = 10 spaces, not 6" in warnings[0] 

181 

182 

183def test_empty_indented_lines_in_section_with_items(parse_google: ParserType) -> None: 

184 """In sections with items, don't treat lines with just indentation as items. 

185 

186 Parameters: 

187 parse_google: Fixture parser. 

188 """ 

189 docstring = "Returns:\n only_item: Description.\n \n \n\nSomething." 

190 sections, _ = parse_google(docstring) 

191 assert len(sections) == 2 

192 assert len(sections[0].value) == 1 

193 

194 

195@pytest.mark.parametrize( 

196 "section", 

197 [ 

198 "Attributes", 

199 "Other Parameters", 

200 "Parameters", 

201 "Type Parameters", 

202 "Raises", 

203 "Receives", 

204 "Returns", 

205 "Warns", 

206 "Type aliases", 

207 "Yields", 

208 ], 

209) 

210def test_starting_item_description_on_new_line(parse_google: ParserType, section: str) -> None: 

211 """In sections with items, allow starting item descriptions on a new (indented) line. 

212 

213 Parameters: 

214 parse_google: Fixture parser. 

215 section: A parametrized section name. 

216 """ 

217 docstring = f"\n{section}:\n only_item:\n Description." 

218 sections, _ = parse_google(docstring) 

219 assert len(sections) == 1 

220 assert len(sections[0].value) == 1 

221 assert sections[0].value[0].description.strip() == "Description." 

222 

223 

224# ============================================================================================= 

225# Annotations 

226def test_parse_without_parent(parse_google: ParserType) -> None: 

227 """Parse a docstring without a parent function. 

228 

229 Parameters: 

230 parse_google: Fixture parser. 

231 """ 

232 sections, warnings = parse_google( 

233 """ 

234 Parameters: 

235 void: SEGFAULT. 

236 niet: SEGFAULT. 

237 nada: SEGFAULT. 

238 rien: SEGFAULT. 

239 

240 Keyword Args: 

241 keywd: SEGFAULT. 

242 

243 Exceptions: 

244 GlobalError: when nothing works as expected. 

245 

246 Returns: 

247 Itself. 

248 """, 

249 ) 

250 

251 assert len(sections) == 4 

252 assert len(warnings) == 6 # Missing annotations for parameters and return. 

253 for warning in warnings[:-1]: 

254 assert "parameter" in warning 

255 assert "return" in warnings[-1] 

256 

257 

258def test_parse_without_annotations(parse_google: ParserType) -> None: 

259 """Parse a function docstring without signature annotations. 

260 

261 Parameters: 

262 parse_google: Fixture parser. 

263 """ 

264 docstring = """ 

265 Parameters: 

266 x: X value. 

267 

268 Keyword Args: 

269 y: Y value. 

270 

271 Returns: 

272 Sum X + Y + Z. 

273 """ 

274 

275 sections, warnings = parse_google( 

276 docstring, 

277 parent=Function( 

278 "func", 

279 parameters=Parameters( 

280 Parameter("x"), 

281 Parameter("y"), 

282 ), 

283 ), 

284 ) 

285 assert len(sections) == 3 

286 assert len(warnings) == 3 

287 for warning in warnings[:-1]: 

288 assert "parameter" in warning 

289 assert "return" in warnings[-1] 

290 

291 

292def test_parse_with_annotations(parse_google: ParserType) -> None: 

293 """Parse a function docstring with signature annotations. 

294 

295 Parameters: 

296 parse_google: Fixture parser. 

297 """ 

298 docstring = """ 

299 Parameters: 

300 x: X value. 

301 

302 Keyword Parameters: 

303 y: Y value. 

304 

305 Returns: 

306 Sum X + Y. 

307 """ 

308 

309 sections, warnings = parse_google( 

310 docstring, 

311 parent=Function( 

312 "func", 

313 parameters=Parameters( 

314 Parameter("x", annotation="int"), 

315 Parameter("y", annotation="int"), 

316 ), 

317 returns="int", 

318 ), 

319 ) 

320 assert len(sections) == 3 

321 assert not warnings 

322 

323 

324# ============================================================================================= 

325# Sections 

326def test_parse_attributes_section(parse_google: ParserType) -> None: 

327 """Parse Attributes sections. 

328 

329 Parameters: 

330 parse_google: Fixture parser. 

331 """ 

332 docstring = """ 

333 Attributes: 

334 hey: Hey. 

335 ho: Ho. 

336 """ 

337 

338 sections, warnings = parse_google(docstring) 

339 assert len(sections) == 1 

340 assert not warnings 

341 

342 

343def test_parse_functions_section(parse_google: ParserType) -> None: 

344 """Parse Functions/Methods sections. 

345 

346 Parameters: 

347 parse_google: Fixture parser. 

348 """ 

349 docstring = """ 

350 Functions: 

351 f(a, b=2): Hello. 

352 g: Hi. 

353 

354 Methods: 

355 f(a, b=2): Hello. 

356 g: Hi. 

357 """ 

358 

359 sections, warnings = parse_google(docstring) 

360 assert len(sections) == 2 

361 for section in sections: 

362 assert section.kind is DocstringSectionKind.functions 

363 func_f = section.value[0] 

364 assert func_f.name == "f" 

365 assert func_f.signature == "f(a, b=2)" 

366 assert func_f.description == "Hello." 

367 func_g = section.value[1] 

368 assert func_g.name == "g" 

369 assert func_g.signature is None 

370 assert func_g.description == "Hi." 

371 assert not warnings 

372 

373 

374def test_parse_classes_section(parse_google: ParserType) -> None: 

375 """Parse Classes sections. 

376 

377 Parameters: 

378 parse_google: Fixture parser. 

379 """ 

380 docstring = """ 

381 Classes: 

382 C(a, b=2): Hello. 

383 D: Hi. 

384 """ 

385 

386 sections, warnings = parse_google(docstring) 

387 assert len(sections) == 1 

388 assert sections[0].kind is DocstringSectionKind.classes 

389 class_c = sections[0].value[0] 

390 assert class_c.name == "C" 

391 assert class_c.signature == "C(a, b=2)" 

392 assert class_c.description == "Hello." 

393 class_d = sections[0].value[1] 

394 assert class_d.name == "D" 

395 assert class_d.signature is None 

396 assert class_d.description == "Hi." 

397 assert not warnings 

398 

399 

400def test_parse_type_aliases_section(parse_google: ParserType) -> None: 

401 """Parse Type Aliases sections. 

402 

403 Parameters: 

404 parse_google: Fixture parser. 

405 """ 

406 docstring = """ 

407 Type Aliases: 

408 TC: Hello. 

409 TD: Hi. 

410 """ 

411 

412 sections, warnings = parse_google(docstring) 

413 assert len(sections) == 1 

414 assert sections[0].kind is DocstringSectionKind.type_aliases 

415 type_alias_c = sections[0].value[0] 

416 assert type_alias_c.name == "TC" 

417 assert type_alias_c.description == "Hello." 

418 type_alias_d = sections[0].value[1] 

419 assert type_alias_d.name == "TD" 

420 assert type_alias_d.description == "Hi." 

421 assert not warnings 

422 

423 

424def test_parse_modules_section(parse_google: ParserType) -> None: 

425 """Parse Modules sections. 

426 

427 Parameters: 

428 parse_google: Fixture parser. 

429 """ 

430 docstring = """ 

431 Modules: 

432 m: Hello. 

433 n: Hi. 

434 """ 

435 

436 sections, warnings = parse_google(docstring) 

437 assert len(sections) == 1 

438 assert sections[0].kind is DocstringSectionKind.modules 

439 module_m = sections[0].value[0] 

440 assert module_m.name == "m" 

441 assert module_m.description == "Hello." 

442 module_n = sections[0].value[1] 

443 assert module_n.name == "n" 

444 assert module_n.description == "Hi." 

445 assert not warnings 

446 

447 

448def test_parse_examples_sections(parse_google: ParserType) -> None: 

449 """Parse a function docstring with examples. 

450 

451 Parameters: 

452 parse_google: Fixture parser. 

453 """ 

454 docstring = """ 

455 Examples: 

456 Some examples that will create a unified code block: 

457 

458 >>> 2 + 2 == 5 

459 False 

460 >>> print("examples") 

461 "examples" 

462 

463 This is just a random comment in the examples section. 

464 

465 These examples will generate two different code blocks. Note the blank line. 

466 

467 >>> print("I'm in the first code block!") 

468 "I'm in the first code block!" 

469 

470 >>> print("I'm in other code block!") 

471 "I'm in other code block!" 

472 

473 We also can write multiline examples: 

474 

475 >>> x = 3 + 2 # doctest: +SKIP 

476 >>> y = x + 10 

477 >>> y 

478 15 

479 

480 This is just a typical Python code block: 

481 

482 ```python 

483 print("examples") 

484 return 2 + 2 

485 ``` 

486 

487 Even if it contains doctests, the following block is still considered a normal code-block. 

488 

489 ```pycon 

490 >>> print("examples") 

491 "examples" 

492 >>> 2 + 2 

493 4 

494 ``` 

495 

496 The blank line before an example is optional. 

497 >>> x = 3 

498 >>> y = "apple" 

499 >>> z = False 

500 >>> l = [x, y, z] 

501 >>> my_print_list_function(l) 

502 3 

503 "apple" 

504 False 

505 """ 

506 

507 sections, warnings = parse_google( 

508 docstring, 

509 parent=Function( 

510 "func", 

511 parameters=Parameters( 

512 Parameter("x", annotation="int"), 

513 Parameter("y", annotation="int"), 

514 ), 

515 returns="int", 

516 ), 

517 trim_doctest_flags=False, 

518 ) 

519 assert len(sections) == 1 

520 examples = sections[0] 

521 assert len(examples.value) == 9 

522 assert examples.value[6][1].startswith(">>> x = 3 + 2 # doctest: +SKIP") 

523 assert not warnings 

524 

525 

526def test_parse_yields_section(parse_google: ParserType) -> None: 

527 """Parse Yields section. 

528 

529 Parameters: 

530 parse_google: Fixture parser. 

531 """ 

532 docstring = """ 

533 Yields: 

534 x: Floats. 

535 (int): Integers. 

536 y (int): Same. 

537 """ 

538 

539 sections, warnings = parse_google(docstring) 

540 assert len(sections) == 1 

541 annotated = sections[0].value[0] 

542 assert annotated.name == "x" 

543 assert annotated.annotation is None 

544 assert annotated.description == "Floats." 

545 annotated = sections[0].value[1] 

546 assert annotated.name == "" 

547 assert annotated.annotation == "int" 

548 assert annotated.description == "Integers." 

549 annotated = sections[0].value[2] 

550 assert annotated.name == "y" 

551 assert annotated.annotation == "int" 

552 assert annotated.description == "Same." 

553 assert len(warnings) == 1 

554 assert "'x'" in warnings[0] 

555 

556 

557def test_invalid_sections(parse_google: ParserType) -> None: 

558 """Warn on invalid sections. 

559 

560 Parameters: 

561 parse_google: Fixture parser. 

562 """ 

563 docstring = """ 

564 Parameters: 

565 Exceptions: 

566 Exceptions: 

567 

568 Returns: 

569 Note: 

570 

571 Important: 

572 """ 

573 

574 sections, warnings = parse_google(docstring) 

575 assert len(sections) == 1 

576 assert not warnings 

577 

578 

579def test_no_empty_text_section(parse_google: ParserType) -> None: 

580 """Don't create a single empty text section for an empty docstring. 

581 

582 Parameters: 

583 parse_google: Fixture parser. 

584 """ 

585 sections, warnings = parse_google("") 

586 assert not sections 

587 assert not warnings 

588 

589 

590# ============================================================================================= 

591# Parameters sections 

592def test_parse_args_and_kwargs(parse_google: ParserType) -> None: 

593 """Parse args and kwargs. 

594 

595 Parameters: 

596 parse_google: Fixture parser. 

597 """ 

598 docstring = """ 

599 Parameters: 

600 a (str): a parameter. 

601 *args (str): args parameters. 

602 **kwargs (str): kwargs parameters. 

603 """ 

604 

605 sections, warnings = parse_google(docstring) 

606 assert len(sections) == 1 

607 expected_parameters = {"a": "a parameter.", "*args": "args parameters.", "**kwargs": "kwargs parameters."} 

608 for parameter in sections[0].value: 

609 assert parameter.name in expected_parameters 

610 assert expected_parameters[parameter.name] == parameter.description 

611 assert not warnings 

612 

613 

614def test_parse_args_kwargs_keyword_only(parse_google: ParserType) -> None: 

615 """Parse args and kwargs. 

616 

617 Parameters: 

618 parse_google: Fixture parser. 

619 """ 

620 docstring = """ 

621 Parameters: 

622 a (str): a parameter. 

623 *args (str): args parameters. 

624 

625 Keyword Args: 

626 **kwargs (str): kwargs parameters. 

627 """ 

628 

629 sections, warnings = parse_google(docstring) 

630 assert len(sections) == 2 

631 expected_parameters = {"a": "a parameter.", "*args": "args parameters."} 

632 for parameter in sections[0].value: 

633 assert parameter.name in expected_parameters 

634 assert expected_parameters[parameter.name] == parameter.description 

635 

636 expected_parameters = {"**kwargs": "kwargs parameters."} 

637 for kwarg in sections[1].value: 

638 assert kwarg.name in expected_parameters 

639 assert expected_parameters[kwarg.name] == kwarg.description 

640 

641 assert not warnings 

642 

643 

644def test_parse_types_in_docstring(parse_google: ParserType) -> None: 

645 """Parse types in docstring. 

646 

647 Parameters: 

648 parse_google: Fixture parser. 

649 """ 

650 docstring = """ 

651 Parameters: 

652 x (int): X value. 

653 

654 Keyword Args: 

655 y (int): Y value. 

656 

657 Returns: 

658 s (int): Sum X + Y + Z. 

659 """ 

660 

661 sections, warnings = parse_google( 

662 docstring, 

663 parent=Function( 

664 "func", 

665 parameters=Parameters( 

666 Parameter("x"), 

667 Parameter("y"), 

668 ), 

669 ), 

670 ) 

671 assert len(sections) == 3 

672 assert not warnings 

673 

674 assert sections[0].kind is DocstringSectionKind.parameters 

675 assert sections[1].kind is DocstringSectionKind.other_parameters 

676 assert sections[2].kind is DocstringSectionKind.returns 

677 

678 (argx,) = sections[0].value 

679 (argy,) = sections[1].value 

680 (returns,) = sections[2].value 

681 

682 assert argx.name == "x" 

683 assert argx.annotation.name == "int" 

684 assert argx.annotation.canonical_path == "int" 

685 assert argx.description == "X value." 

686 assert argx.value is None 

687 

688 assert argy.name == "y" 

689 assert argy.annotation.name == "int" 

690 assert argy.annotation.canonical_path == "int" 

691 assert argy.description == "Y value." 

692 assert argy.value is None 

693 

694 assert returns.annotation.name == "int" 

695 assert returns.annotation.canonical_path == "int" 

696 assert returns.description == "Sum X + Y + Z." 

697 

698 

699def test_parse_optional_type_in_docstring(parse_google: ParserType) -> None: 

700 """Parse optional types in docstring. 

701 

702 Parameters: 

703 parse_google: Fixture parser. 

704 """ 

705 docstring = """ 

706 Parameters: 

707 x (int): X value. 

708 y (int, optional): Y value. 

709 

710 Keyword Args: 

711 z (int, optional): Z value. 

712 """ 

713 

714 sections, warnings = parse_google( 

715 docstring, 

716 parent=Function( 

717 "func", 

718 parameters=Parameters( 

719 Parameter("x", default="1"), 

720 Parameter("y", default="None"), 

721 Parameter("z", default="None"), 

722 ), 

723 ), 

724 ) 

725 assert len(sections) == 2 

726 assert not warnings 

727 

728 assert sections[0].kind is DocstringSectionKind.parameters 

729 assert sections[1].kind is DocstringSectionKind.other_parameters 

730 

731 argx, argy = sections[0].value 

732 (argz,) = sections[1].value 

733 

734 assert argx.name == "x" 

735 assert argx.annotation.name == "int" 

736 assert argx.annotation.canonical_path == "int" 

737 assert argx.description == "X value." 

738 assert argx.value == "1" 

739 

740 assert argy.name == "y" 

741 assert argy.annotation.name == "int" 

742 assert argy.annotation.canonical_path == "int" 

743 assert argy.description == "Y value." 

744 assert argy.value == "None" 

745 

746 assert argz.name == "z" 

747 assert argz.annotation.name == "int" 

748 assert argz.annotation.canonical_path == "int" 

749 assert argz.description == "Z value." 

750 assert argz.value == "None" 

751 

752 

753def test_prefer_docstring_types_over_annotations(parse_google: ParserType) -> None: 

754 """Prefer the docstring type over the annotation. 

755 

756 Parameters: 

757 parse_google: Fixture parser. 

758 """ 

759 docstring = """ 

760 Parameters: 

761 x (str): X value. 

762 

763 Keyword Args: 

764 y (str): Y value. 

765 

766 Returns: 

767 (str): Sum X + Y + Z. 

768 """ 

769 

770 sections, warnings = parse_google( 

771 docstring, 

772 parent=Function( 

773 "func", 

774 parameters=Parameters( 

775 Parameter("x", annotation="int"), 

776 Parameter("y", annotation="int"), 

777 ), 

778 returns="int", 

779 ), 

780 ) 

781 assert len(sections) == 3 

782 assert not warnings 

783 

784 assert sections[0].kind is DocstringSectionKind.parameters 

785 assert sections[1].kind is DocstringSectionKind.other_parameters 

786 assert sections[2].kind is DocstringSectionKind.returns 

787 

788 (argx,) = sections[0].value 

789 (argy,) = sections[1].value 

790 (returns,) = sections[2].value 

791 

792 assert argx.name == "x" 

793 assert argx.annotation.name == "str" 

794 assert argx.annotation.canonical_path == "str" 

795 assert argx.description == "X value." 

796 

797 assert argy.name == "y" 

798 assert argy.annotation.name == "str" 

799 assert argy.annotation.canonical_path == "str" 

800 assert argy.description == "Y value." 

801 

802 assert returns.annotation.name == "str" 

803 assert returns.annotation.canonical_path == "str" 

804 assert returns.description == "Sum X + Y + Z." 

805 

806 

807def test_parameter_line_without_colon(parse_google: ParserType) -> None: 

808 """Warn when missing colon. 

809 

810 Parameters: 

811 parse_google: Fixture parser. 

812 """ 

813 docstring = """ 

814 Parameters: 

815 x is an integer. 

816 """ 

817 

818 sections, warnings = parse_google(docstring) 

819 assert len(sections) == 0 # Empty sections are discarded. 

820 assert len(warnings) == 1 

821 assert "pair" in warnings[0] 

822 

823 

824def test_parameter_line_without_colon_keyword_only(parse_google: ParserType) -> None: 

825 """Warn when missing colon. 

826 

827 Parameters: 

828 parse_google: Fixture parser. 

829 """ 

830 docstring = """ 

831 Keyword Args: 

832 x is an integer. 

833 """ 

834 

835 sections, warnings = parse_google(docstring) 

836 assert len(sections) == 0 # Empty sections are discarded. 

837 assert len(warnings) == 1 

838 assert "pair" in warnings[0] 

839 

840 

841def test_warn_about_unknown_parameters(parse_google: ParserType) -> None: 

842 """Warn about unknown parameters in "Parameters" sections. 

843 

844 Parameters: 

845 parse_google: Fixture parser. 

846 """ 

847 docstring = """ 

848 Parameters: 

849 x (int): Integer. 

850 y (int): Integer. 

851 """ 

852 

853 _, warnings = parse_google( 

854 docstring, 

855 parent=Function( 

856 "func", 

857 parameters=Parameters( 

858 Parameter("a"), 

859 Parameter("y"), 

860 ), 

861 ), 

862 ) 

863 assert len(warnings) == 1 

864 assert "'x' does not appear in the function signature" in warnings[0] 

865 

866 

867def test_never_warn_about_unknown_other_parameters(parse_google: ParserType) -> None: 

868 """Never warn about unknown parameters in "Other parameters" sections. 

869 

870 Parameters: 

871 parse_google: Fixture parser. 

872 """ 

873 docstring = """ 

874 Other Parameters: 

875 x (int): Integer. 

876 z (int): Integer. 

877 """ 

878 

879 _, warnings = parse_google( 

880 docstring, 

881 parent=Function( 

882 "func", 

883 parameters=Parameters( 

884 Parameter("a"), 

885 Parameter("y"), 

886 ), 

887 ), 

888 ) 

889 assert not warnings 

890 

891 

892def test_unknown_params_scan_doesnt_crash_without_parameters(parse_google: ParserType) -> None: 

893 """Assert we don't crash when parsing parameters sections and parent object does not have parameters. 

894 

895 Parameters: 

896 parse_google: Fixture parser. 

897 """ 

898 docstring = """ 

899 Parameters: 

900 this (str): This. 

901 that (str): That. 

902 """ 

903 

904 _, warnings = parse_google(docstring, parent=Module("mod")) 

905 assert not warnings 

906 

907 

908def test_class_uses_init_parameters(parse_google: ParserType) -> None: 

909 """Assert we use the `__init__` parameters when parsing classes' parameters sections. 

910 

911 Parameters: 

912 parse_google: Fixture parser. 

913 """ 

914 docstring = """ 

915 Parameters: 

916 x: X value. 

917 """ 

918 parent = Class("c") 

919 parent["__init__"] = Function("__init__", parameters=Parameters(Parameter("x", annotation="int"))) 

920 sections, warnings = parse_google(docstring, parent=parent) 

921 assert not warnings 

922 argx = sections[0].value[0] 

923 assert argx.name == "x" 

924 assert argx.annotation == "int" 

925 assert argx.description == "X value." 

926 

927 

928def test_parse_parameters_and_type_without_space(parse_google: ParserType) -> None: 

929 """Parse parameter name and type without space. 

930 

931 Parameters: 

932 parse_google: Fixture parser. 

933 """ 

934 docstring = """ 

935 Parameters: 

936 x(int): X value. 

937 """ 

938 

939 sections, warnings = parse_google(docstring) 

940 assert len(sections) == 1 

941 assert not warnings 

942 argx = sections[0].value[0] 

943 assert argx.name == "x" 

944 assert argx.annotation == "int" 

945 assert argx.description == "X value." 

946 

947 

948# TODO: possible feature 

949# def test_missing_parameter(parse_google: ParserType) -> None: 

950# """Warn on missing parameter in docstring. 

951# 

952# Parameters: 

953# parse_google: Fixture parser. 

954# """ 

955# docstring = """ 

956# Parameters: 

957# x: Integer. 

958# """ 

959# assert not warnings 

960 

961 

962# ============================================================================================= 

963# Type parameters sections 

964def test_parse_type_var_tuples_and_param_specs(parse_google: ParserType) -> None: 

965 """Parse type variable tuples and parameter specifications. 

966 

967 Parameters: 

968 parse_google: Fixture parser. 

969 """ 

970 docstring = """ 

971 Type Parameters: 

972 T: A type parameter. 

973 C (str, (int, float)): A constrained type parameter. 

974 D complex: A bounded type parameter. 

975 """ 

976 

977 sections, warnings = parse_google(docstring) 

978 assert len(sections) == 1 

979 expected_type_parameters = { 

980 "T": ("A type parameter.", None), 

981 "C": ("A constrained type parameter.", "str, (int, float)"), 

982 "D": ("A bounded type parameter.", "complex"), 

983 } 

984 for type_parameter in sections[0].value: 

985 assert type_parameter.name in expected_type_parameters 

986 assert expected_type_parameters[type_parameter.name][0] == type_parameter.description 

987 assert expected_type_parameters[type_parameter.name][1] == type_parameter.annotation 

988 assert not warnings 

989 

990 

991def test_prefer_docstring_bounds_over_annotations(parse_google: ParserType) -> None: 

992 """Prefer the docstring bound over the annotation. 

993 

994 Parameters: 

995 parse_google: Fixture parser. 

996 """ 

997 docstring = """ 

998 Type Parameters: 

999 X (str): X type. 

1000 Y str, int: Y type. 

1001 """ 

1002 

1003 sections, warnings = parse_google( 

1004 docstring, 

1005 parent=Function( 

1006 "func", 

1007 type_parameters=TypeParameters( 

1008 TypeParameter("X", kind=TypeParameterKind.type_var, constraints=["complex"]), 

1009 TypeParameter("Y", kind=TypeParameterKind.type_var, bound="int"), 

1010 ), 

1011 ), 

1012 ) 

1013 assert len(sections) == 1 

1014 assert not warnings 

1015 

1016 assert sections[0].kind is DocstringSectionKind.type_parameters 

1017 

1018 (x, y) = sections[0].value 

1019 

1020 assert x.name == "X" 

1021 assert str(x.bound) == "str" 

1022 assert x.constraints is None 

1023 

1024 assert y.name == "Y" 

1025 assert y.bound is None 

1026 assert [str(constraint) for constraint in y.constraints] == ["str", "int"] 

1027 

1028 

1029def test_type_parameter_line_without_colon(parse_google: ParserType) -> None: 

1030 """Warn when missing colon. 

1031 

1032 Parameters: 

1033 parse_google: Fixture parser. 

1034 """ 

1035 docstring = """ 

1036 Type Parameters: 

1037 X is an integer type. 

1038 """ 

1039 

1040 sections, warnings = parse_google(docstring) 

1041 assert len(sections) == 0 # empty sections are discarded 

1042 assert len(warnings) == 1 

1043 assert "pair" in warnings[0] 

1044 

1045 

1046def test_warn_about_unknown_type_parameters(parse_google: ParserType) -> None: 

1047 """Warn about unknown type parameters in "Type Parameters" sections. 

1048 

1049 Parameters: 

1050 parse_google: Fixture parser. 

1051 """ 

1052 docstring = """ 

1053 Type Parameters: 

1054 X (int): Integer. 

1055 Y (int): Integer. 

1056 """ 

1057 

1058 _, warnings = parse_google( 

1059 docstring, 

1060 parent=Function( 

1061 "func", 

1062 type_parameters=TypeParameters( 

1063 TypeParameter("A", kind=TypeParameterKind.type_var), 

1064 TypeParameter("Y", kind=TypeParameterKind.type_var), 

1065 ), 

1066 ), 

1067 ) 

1068 assert len(warnings) == 1 

1069 assert "'X' does not appear in the function signature" in warnings[0] 

1070 

1071 

1072def test_unknown_type_params_scan_doesnt_crash_without_type_parameters(parse_google: ParserType) -> None: 

1073 """Assert we don't crash when parsing type parameters sections and parent object does not have type parameters. 

1074 

1075 Parameters: 

1076 parse_google: Fixture parser. 

1077 """ 

1078 docstring = """ 

1079 TypeParameters: 

1080 This (str): This. 

1081 That: That. 

1082 """ 

1083 

1084 _, warnings = parse_google(docstring, parent=Module("mod")) 

1085 assert not warnings 

1086 

1087 

1088# ============================================================================================= 

1089# Attributes sections 

1090def test_retrieve_attributes_annotation_from_parent(parse_google: ParserType) -> None: 

1091 """Retrieve the annotations of attributes from the parent object. 

1092 

1093 Parameters: 

1094 parse_google: Fixture parser. 

1095 """ 

1096 docstring = """ 

1097 Summary. 

1098 

1099 Attributes: 

1100 a: Whatever. 

1101 b: Whatever. 

1102 """ 

1103 parent = Class("cls") 

1104 parent["a"] = Attribute("a", annotation=ExprName("int")) 

1105 parent["b"] = Attribute("b", annotation=ExprName("str")) 

1106 sections, _ = parse_google(docstring, parent=parent) 

1107 attributes = sections[1].value 

1108 assert attributes[0].name == "a" 

1109 assert attributes[0].annotation.name == "int" 

1110 assert attributes[1].name == "b" 

1111 assert attributes[1].annotation.name == "str" 

1112 

1113 

1114# ============================================================================================= 

1115# Yields sections 

1116def test_parse_yields_section_with_return_annotation(parse_google: ParserType) -> None: 

1117 """Parse Yields section with a return annotation in the parent function. 

1118 

1119 Parameters: 

1120 parse_google: Fixture parser. 

1121 """ 

1122 docstring = """ 

1123 Yields: 

1124 Integers. 

1125 """ 

1126 

1127 function = Function("func", returns="Iterator[int]") 

1128 sections, warnings = parse_google(docstring, function) 

1129 assert len(sections) == 1 

1130 annotated = sections[0].value[0] 

1131 assert annotated.annotation == "Iterator[int]" 

1132 assert annotated.description == "Integers." 

1133 assert not warnings 

1134 

1135 

1136@pytest.mark.parametrize( 

1137 "return_annotation", 

1138 [ 

1139 "Iterator[tuple[int, float]]", 

1140 "Generator[tuple[int, float], ..., ...]", 

1141 ], 

1142) 

1143def test_parse_yields_tuple_in_iterator_or_generator(parse_google: ParserType, return_annotation: str) -> None: 

1144 """Parse Yields annotations in Iterator or Generator types. 

1145 

1146 Parameters: 

1147 parse_google: Fixture parser. 

1148 return_annotation: Parametrized return annotation as a string. 

1149 """ 

1150 docstring = """ 

1151 Summary. 

1152 

1153 Yields: 

1154 a: Whatever. 

1155 b: Whatever. 

1156 """ 

1157 sections, _ = parse_google( 

1158 docstring, 

1159 parent=Function( 

1160 "func", 

1161 returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f"))), 

1162 ), 

1163 ) 

1164 yields = sections[1].value 

1165 assert yields[0].name == "a" 

1166 assert yields[0].annotation.name == "int" 

1167 assert yields[1].name == "b" 

1168 assert yields[1].annotation.name == "float" 

1169 

1170 

1171@pytest.mark.parametrize( 

1172 "return_annotation", 

1173 [ 

1174 "Iterator[int]", 

1175 "Generator[int, None, None]", 

1176 ], 

1177) 

1178def test_extract_yielded_type_with_single_return_item(parse_google: ParserType, return_annotation: str) -> None: 

1179 """Extract main type annotation from Iterator or Generator. 

1180 

1181 Parameters: 

1182 parse_google: Fixture parser. 

1183 return_annotation: Parametrized return annotation as a string. 

1184 """ 

1185 docstring = """ 

1186 Summary. 

1187 

1188 Yields: 

1189 A number. 

1190 """ 

1191 sections, _ = parse_google( 

1192 docstring, 

1193 parent=Function( 

1194 "func", 

1195 returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f"))), 

1196 ), 

1197 ) 

1198 yields = sections[1].value 

1199 assert yields[0].annotation.name == "int" 

1200 

1201 

1202def test_yield_section_in_property(parse_google: ParserType) -> None: 

1203 """No warnings when parsing Yields section in a property. 

1204 

1205 Parameters: 

1206 parse_google: Fixture parser. 

1207 """ 

1208 docstring = """ 

1209 Summary. 

1210 

1211 Yields: 

1212 A number. 

1213 """ 

1214 sections, warnings = parse_google( 

1215 docstring, 

1216 parent=Attribute( 

1217 "prop", 

1218 annotation=parse_docstring_annotation("Iterator[int]", Docstring("d", parent=Attribute("a"))), 

1219 ), 

1220 ) 

1221 assert not warnings 

1222 yields = sections[1].value 

1223 assert yields[0].annotation.name == "int" 

1224 

1225 

1226# ============================================================================================= 

1227# Receives sections 

1228def test_parse_receives_tuple_in_generator(parse_google: ParserType) -> None: 

1229 """Parse Receives annotations in Generator type. 

1230 

1231 Parameters: 

1232 parse_google: Fixture parser. 

1233 """ 

1234 docstring = """ 

1235 Summary. 

1236 

1237 Receives: 

1238 a: Whatever. 

1239 b: Whatever. 

1240 """ 

1241 sections, _ = parse_google( 

1242 docstring, 

1243 parent=Function( 

1244 "func", 

1245 returns=parse_docstring_annotation( 

1246 "Generator[..., tuple[int, float], ...]", 

1247 Docstring("d", parent=Function("f")), 

1248 ), 

1249 ), 

1250 ) 

1251 receives = sections[1].value 

1252 assert receives[0].name == "a" 

1253 assert receives[0].annotation.name == "int" 

1254 assert receives[1].name == "b" 

1255 assert receives[1].annotation.name == "float" 

1256 

1257 

1258@pytest.mark.parametrize( 

1259 "return_annotation", 

1260 [ 

1261 "Generator[int, float, None]", 

1262 ], 

1263) 

1264def test_extract_received_type_with_single_return_item(parse_google: ParserType, return_annotation: str) -> None: 

1265 """Extract main type annotation from Iterator or Generator. 

1266 

1267 Parameters: 

1268 parse_google: Fixture parser. 

1269 return_annotation: Parametrized return annotation as a string. 

1270 """ 

1271 docstring = """ 

1272 Summary. 

1273 

1274 Receives: 

1275 A floating point number. 

1276 """ 

1277 sections, _ = parse_google( 

1278 docstring, 

1279 parent=Function( 

1280 "func", 

1281 returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f"))), 

1282 ), 

1283 ) 

1284 receives = sections[1].value 

1285 assert receives[0].annotation.name == "float" 

1286 

1287 

1288# ============================================================================================= 

1289# Returns sections 

1290def test_parse_returns_tuple_in_generator(parse_google: ParserType) -> None: 

1291 """Parse Returns annotations in Generator type. 

1292 

1293 Parameters: 

1294 parse_google: Fixture parser. 

1295 """ 

1296 docstring = """ 

1297 Summary. 

1298 

1299 Returns: 

1300 a: Whatever. 

1301 b: Whatever. 

1302 """ 

1303 sections, _ = parse_google( 

1304 docstring, 

1305 parent=Function( 

1306 "func", 

1307 returns=parse_docstring_annotation( 

1308 "Generator[..., ..., tuple[int, float]]", 

1309 Docstring("d", parent=Function("f")), 

1310 ), 

1311 ), 

1312 ) 

1313 returns = sections[1].value 

1314 assert returns[0].name == "a" 

1315 assert returns[0].annotation.name == "int" 

1316 assert returns[1].name == "b" 

1317 assert returns[1].annotation.name == "float" 

1318 

1319 

1320# ============================================================================================= 

1321# Parser special features 

1322def test_parse_admonitions(parse_google: ParserType) -> None: 

1323 """Parse admonitions. 

1324 

1325 Parameters: 

1326 parse_google: Fixture parser. 

1327 """ 

1328 docstring = """ 

1329 Important note: 

1330 Hello. 

1331 

1332 Note: With title. 

1333 Hello again. 

1334 

1335 Something: 

1336 Something. 

1337 """ 

1338 

1339 sections, warnings = parse_google(docstring) 

1340 assert len(sections) == 3 

1341 assert not warnings 

1342 assert sections[0].title == "Important note" 

1343 assert sections[0].value.kind == "important-note" 

1344 assert sections[0].value.contents == "Hello." 

1345 assert sections[1].title == "With title." 

1346 assert sections[1].value.kind == "note" 

1347 assert sections[1].value.contents == "Hello again." 

1348 assert sections[2].title == "Something" 

1349 assert sections[2].value.kind == "something" 

1350 assert sections[2].value.contents == "Something." 

1351 

1352 

1353@pytest.mark.parametrize( 

1354 "docstring", 

1355 [ 

1356 """ 

1357 ****************************** 

1358 This looks like an admonition: 

1359 ****************************** 

1360 """, 

1361 """ 

1362 Warning: this line also looks 

1363 like an admonition. 

1364 """, 

1365 """ 

1366 Matching but not an admonition: 

1367 

1368 

1369 

1370 - Multiple empty lines above. 

1371 """, 

1372 """Last line:""", 

1373 ], 

1374) 

1375def test_handle_false_admonitions_correctly(parse_google: ParserType, docstring: str) -> None: 

1376 """Correctly handle lines that look like admonitions. 

1377 

1378 Parameters: 

1379 parse_google: Fixture parser. 

1380 docstring: The docstring to parse (parametrized). 

1381 """ 

1382 sections, warnings = parse_google(docstring) 

1383 assert len(sections) == 1 

1384 assert sections[0].kind is DocstringSectionKind.text 

1385 assert len(sections[0].value.splitlines()) == len(inspect.cleandoc(docstring).splitlines()) 

1386 assert not warnings 

1387 

1388 

1389def test_dont_insert_admonition_before_current_section(parse_google: ParserType) -> None: 

1390 """Check that admonitions are inserted at the right place. 

1391 

1392 Parameters: 

1393 parse_google: Fixture parser. 

1394 """ 

1395 docstring = """ 

1396 Summary. 

1397 

1398 Short description. 

1399 

1400 Info: 

1401 Something useful. 

1402 """ 

1403 sections, _ = parse_google(docstring) 

1404 assert len(sections) == 2 

1405 assert sections[0].kind is DocstringSectionKind.text 

1406 assert sections[1].kind is DocstringSectionKind.admonition 

1407 

1408 

1409@pytest.mark.parametrize( 

1410 "docstring", 

1411 [ 

1412 "", 

1413 "\n", 

1414 "\n\n", 

1415 "Summary.", 

1416 "Summary.\n\n\n", 

1417 "Summary.\n\nParagraph.", 

1418 "Summary\non two lines.", 

1419 "Summary\non two lines.\n\nParagraph.", 

1420 ], 

1421) 

1422def test_ignore_init_summary(parse_google: ParserType, docstring: str) -> None: 

1423 """Correctly ignore summary in `__init__` methods' docstrings. 

1424 

1425 Parameters: 

1426 parse_google: Fixture parser. 

1427 docstring: The docstring to parse_google (parametrized). 

1428 """ 

1429 sections, _ = parse_google(docstring, parent=Function("__init__", parent=Class("C")), ignore_init_summary=True) 

1430 for section in sections: 

1431 assert "Summary" not in section.value 

1432 

1433 if docstring.strip(): 

1434 sections, _ = parse_google(docstring, parent=Function("__init__", parent=Module("M")), ignore_init_summary=True) 

1435 assert "Summary" in sections[0].value 

1436 sections, _ = parse_google(docstring, parent=Function("f", parent=Class("C")), ignore_init_summary=True) 

1437 assert "Summary" in sections[0].value 

1438 sections, _ = parse_google(docstring, ignore_init_summary=True) 

1439 assert "Summary" in sections[0].value 

1440 

1441 

1442@pytest.mark.parametrize( 

1443 "docstring", 

1444 [ 

1445 """ 

1446 Examples: 

1447 Base case 1. We want to skip the following test. 

1448 >>> 1 + 1 == 3 # doctest: +SKIP 

1449 True 

1450 """, 

1451 r""" 

1452 Examples: 

1453 Base case 2. We have a blankline test. 

1454 >>> print("a\n\nb") 

1455 a 

1456 <BLANKLINE> 

1457 b 

1458 """, 

1459 ], 

1460) 

1461def test_trim_doctest_flags_basic_example(parse_google: ParserType, docstring: str) -> None: 

1462 """Correctly parse simple example docstrings when `trim_doctest_flags` option is turned on. 

1463 

1464 Parameters: 

1465 parse_google: Fixture parser. 

1466 docstring: The docstring to parse (parametrized). 

1467 """ 

1468 sections, warnings = parse_google(docstring, trim_doctest_flags=True) 

1469 assert len(sections) == 1 

1470 assert len(sections[0].value) == 2 

1471 assert not warnings 

1472 

1473 # Verify that doctest flags have indeed been trimmed. 

1474 example_str = sections[0].value[1][1] 

1475 assert "# doctest: +SKIP" not in example_str 

1476 assert "<BLANKLINE>" not in example_str 

1477 

1478 

1479def test_trim_doctest_flags_multi_example(parse_google: ParserType) -> None: 

1480 """Correctly parse multiline example docstrings when `trim_doctest_flags` option is turned on. 

1481 

1482 Parameters: 

1483 parse_google: Fixture parser. 

1484 """ 

1485 docstring = r""" 

1486 Examples: 

1487 Test multiline example blocks. 

1488 We want to skip the following test. 

1489 >>> 1 + 1 == 3 # doctest: +SKIP 

1490 True 

1491 

1492 And then a few more examples here: 

1493 >>> print("a\n\nb") 

1494 a 

1495 <BLANKLINE> 

1496 b 

1497 >>> 1 + 1 == 2 # doctest: +SKIP 

1498 >>> print(list(range(1, 100))) # doctest: +ELLIPSIS 

1499 [1, 2, ..., 98, 99] 

1500 """ 

1501 sections, warnings = parse_google(docstring, trim_doctest_flags=True) 

1502 assert len(sections) == 1 

1503 assert len(sections[0].value) == 4 

1504 assert not warnings 

1505 

1506 # Verify that doctest flags have indeed been trimmed. 

1507 example_str = sections[0].value[1][1] 

1508 assert "# doctest: +SKIP" not in example_str 

1509 example_str = sections[0].value[3][1] 

1510 assert "<BLANKLINE>" not in example_str 

1511 assert "\n>>> print(list(range(1, 100)))\n" in example_str 

1512 

1513 

1514def test_single_line_with_trailing_whitespace(parse_google: ParserType) -> None: 

1515 """Don't crash on single line docstrings with trailing whitespace. 

1516 

1517 Parameters: 

1518 parse_google: Fixture parser. 

1519 """ 

1520 docstring = "a: b\n " 

1521 sections, warnings = parse_google(docstring, trim_doctest_flags=True) 

1522 assert len(sections) == 1 

1523 assert sections[0].kind is DocstringSectionKind.text 

1524 assert not warnings 

1525 

1526 

1527@pytest.mark.parametrize( 

1528 ("returns_multiple_items", "return_annotation", "expected"), 

1529 [ 

1530 ( 

1531 False, 

1532 None, 

1533 [DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation=None)], 

1534 ), 

1535 ( 

1536 False, 

1537 "tuple[int, int]", 

1538 [DocstringReturn("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation="tuple[int, int]")], 

1539 ), 

1540 ( 

1541 True, 

1542 None, 

1543 [ 

1544 DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation=None), 

1545 DocstringReturn("", description="ZZZZZZZ", annotation=None), 

1546 ], 

1547 ), 

1548 ( 

1549 True, 

1550 "tuple[int,int]", 

1551 [ 

1552 DocstringReturn("", description="XXXXXXX\nYYYYYYY", annotation="int"), 

1553 DocstringReturn("", description="ZZZZZZZ", annotation="int"), 

1554 ], 

1555 ), 

1556 ], 

1557) 

1558def test_parse_returns_multiple_items( 

1559 parse_google: ParserType, 

1560 returns_multiple_items: bool, 

1561 return_annotation: str, 

1562 expected: list[DocstringReturn], 

1563) -> None: 

1564 """Parse Returns section with and without multiple items. 

1565 

1566 Parameters: 

1567 parse_google: Fixture parser. 

1568 returns_multiple_items: Whether the `Returns` section has multiple items. 

1569 return_annotation: The return annotation of the function to parse. 

1570 expected: The expected value of the parsed Returns section. 

1571 """ 

1572 parent = ( 

1573 Function("func", returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f")))) 

1574 if return_annotation is not None 

1575 else None 

1576 ) 

1577 docstring = """ 

1578 Returns: 

1579 XXXXXXX 

1580 YYYYYYY 

1581 ZZZZZZZ 

1582 """ 

1583 sections, _ = parse_google( 

1584 docstring, 

1585 returns_multiple_items=returns_multiple_items, 

1586 parent=parent, 

1587 ) 

1588 

1589 assert len(sections) == 1 

1590 assert len(sections[0].value) == len(expected) 

1591 

1592 for annotated, expected_ in zip(sections[0].value, expected, strict=False): 

1593 assert annotated.name == expected_.name 

1594 assert str(annotated.annotation) == str(expected_.annotation) 

1595 assert annotated.description == expected_.description 

1596 

1597 

1598@pytest.mark.parametrize( 

1599 ("returns_multiple_items", "return_annotation", "expected"), 

1600 [ 

1601 ( 

1602 False, 

1603 None, 

1604 [DocstringYield("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation=None)], 

1605 ), 

1606 ( 

1607 False, 

1608 "Iterator[tuple[int, int]]", 

1609 [DocstringYield("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation="tuple[int, int]")], 

1610 ), 

1611 ( 

1612 True, 

1613 None, 

1614 [ 

1615 DocstringYield("", description="XXXXXXX\nYYYYYYY", annotation=None), 

1616 DocstringYield("", description="ZZZZZZZ", annotation=None), 

1617 ], 

1618 ), 

1619 ( 

1620 True, 

1621 "Iterator[tuple[int,int]]", 

1622 [ 

1623 DocstringYield("", description="XXXXXXX\nYYYYYYY", annotation="int"), 

1624 DocstringYield("", description="ZZZZZZZ", annotation="int"), 

1625 ], 

1626 ), 

1627 ], 

1628) 

1629def test_parse_yields_multiple_items( 

1630 parse_google: ParserType, 

1631 returns_multiple_items: bool, 

1632 return_annotation: str, 

1633 expected: list[DocstringYield], 

1634) -> None: 

1635 """Parse Returns section with and without multiple items. 

1636 

1637 Parameters: 

1638 parse_google: Fixture parser. 

1639 returns_multiple_items: Whether the `Returns` and `Yields` sections have multiple items. 

1640 return_annotation: The return annotation of the function to parse. Usually an `Iterator`. 

1641 expected: The expected value of the parsed Yields section. 

1642 """ 

1643 parent = ( 

1644 Function("func", returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f")))) 

1645 if return_annotation is not None 

1646 else None 

1647 ) 

1648 docstring = """ 

1649 Yields: 

1650 XXXXXXX 

1651 YYYYYYY 

1652 ZZZZZZZ 

1653 """ 

1654 sections, _ = parse_google( 

1655 docstring, 

1656 returns_multiple_items=returns_multiple_items, 

1657 parent=parent, 

1658 ) 

1659 

1660 assert len(sections) == 1 

1661 assert len(sections[0].value) == len(expected) 

1662 

1663 for annotated, expected_ in zip(sections[0].value, expected, strict=False): 

1664 assert annotated.name == expected_.name 

1665 assert str(annotated.annotation) == str(expected_.annotation) 

1666 assert annotated.description == expected_.description 

1667 

1668 

1669@pytest.mark.parametrize( 

1670 ("receives_multiple_items", "return_annotation", "expected"), 

1671 [ 

1672 ( 

1673 False, 

1674 None, 

1675 [DocstringReceive("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation=None)], 

1676 ), 

1677 ( 

1678 False, 

1679 "Generator[..., tuple[int, int], ...]", 

1680 [DocstringReceive("", description="XXXXXXX\n YYYYYYY\nZZZZZZZ", annotation="tuple[int, int]")], 

1681 ), 

1682 ( 

1683 True, 

1684 None, 

1685 [ 

1686 DocstringReceive("", description="XXXXXXX\nYYYYYYY", annotation=None), 

1687 DocstringReceive("", description="ZZZZZZZ", annotation=None), 

1688 ], 

1689 ), 

1690 ( 

1691 True, 

1692 "Generator[..., tuple[int, int], ...]", 

1693 [ 

1694 DocstringReceive("", description="XXXXXXX\nYYYYYYY", annotation="int"), 

1695 DocstringReceive("", description="ZZZZZZZ", annotation="int"), 

1696 ], 

1697 ), 

1698 ], 

1699) 

1700def test_parse_receives_multiple_items( 

1701 parse_google: ParserType, 

1702 receives_multiple_items: bool, 

1703 return_annotation: str, 

1704 expected: list[DocstringReceive], 

1705) -> None: 

1706 """Parse Returns section with and without multiple items. 

1707 

1708 Parameters: 

1709 parse_google: Fixture parser. 

1710 receives_multiple_items: Whether the `Receives` section has multiple items. 

1711 return_annotation: The return annotation of the function to parse. Usually a `Generator`. 

1712 expected: The expected value of the parsed Receives section. 

1713 """ 

1714 parent = ( 

1715 Function("func", returns=parse_docstring_annotation(return_annotation, Docstring("d", parent=Function("f")))) 

1716 if return_annotation is not None 

1717 else None 

1718 ) 

1719 docstring = """ 

1720 Receives: 

1721 XXXXXXX 

1722 YYYYYYY 

1723 ZZZZZZZ 

1724 """ 

1725 sections, _ = parse_google( 

1726 docstring, 

1727 receives_multiple_items=receives_multiple_items, 

1728 parent=parent, 

1729 ) 

1730 

1731 assert len(sections) == 1 

1732 assert len(sections[0].value) == len(expected) 

1733 

1734 for annotated, expected_ in zip(sections[0].value, expected, strict=False): 

1735 assert annotated.name == expected_.name 

1736 assert str(annotated.annotation) == str(expected_.annotation) 

1737 assert annotated.description == expected_.description 

1738 

1739 

1740def test_avoid_false_positive_sections(parse_google: ParserType) -> None: 

1741 """Avoid false positive when parsing sections. 

1742 

1743 Parameters: 

1744 parse_google: Fixture parser. 

1745 """ 

1746 docstring = """ 

1747 Summary. 

1748 Modules: 

1749 Not a modules section. 

1750 No blank line before title: 

1751 Not an admonition. 

1752 

1753 Blank line after title: 

1754 

1755 Not an admonition. 

1756 

1757 Modules: 

1758 

1759 Not a modules section. 

1760 Modules: 

1761 

1762 Not a modules section. 

1763 No blank line before and blank line after: 

1764 

1765 Not an admonition. 

1766 

1767 Classes: 

1768 

1769 - Text. 

1770 """ 

1771 sections, warnings = parse_google(docstring) 

1772 assert len(sections) == 1 

1773 assert "Classes" in sections[0].value 

1774 assert "Text" in sections[0].value 

1775 assert len(warnings) == 6 

1776 assert warnings == [ 

1777 "Possible section skipped, reasons: Missing blank line above section", 

1778 "Possible admonition skipped, reasons: Missing blank line above admonition", 

1779 "Possible admonition skipped, reasons: Extraneous blank line below admonition title", 

1780 "Possible section skipped, reasons: Extraneous blank line below section title", 

1781 "Possible section skipped, reasons: Missing blank line above section; Extraneous blank line below section title", 

1782 "Possible admonition skipped, reasons: Missing blank line above admonition; Extraneous blank line below admonition title", 

1783 ] 

1784 

1785 

1786def test_type_in_returns_without_parentheses(parse_google: ParserType) -> None: 

1787 """Assert we can parse the return type without parentheses. 

1788 

1789 Parameters: 

1790 parse_google: Fixture parser. 

1791 """ 

1792 docstring = """ 

1793 Summary. 

1794 

1795 Returns: 

1796 int: Description 

1797 on several lines. 

1798 """ 

1799 sections, warnings = parse_google(docstring, returns_named_value=False) 

1800 assert len(sections) == 2 

1801 assert not warnings 

1802 retval = sections[1].value[0] 

1803 assert retval.name == "" 

1804 assert retval.annotation == "int" 

1805 assert retval.description == "Description\non several lines." 

1806 

1807 docstring = """ 

1808 Summary. 

1809 

1810 Returns: 

1811 Description 

1812 on several lines. 

1813 """ 

1814 sections, warnings = parse_google(docstring, returns_named_value=False) 

1815 assert len(sections) == 2 

1816 assert len(warnings) == 1 

1817 retval = sections[1].value[0] 

1818 assert retval.name == "" 

1819 assert retval.annotation is None 

1820 assert retval.description == "Description\non several lines." 

1821 

1822 

1823def test_type_in_yields_without_parentheses(parse_google: ParserType) -> None: 

1824 """Assert we can parse the return type without parentheses. 

1825 

1826 Parameters: 

1827 parse_google: Fixture parser. 

1828 """ 

1829 docstring = """ 

1830 Summary. 

1831 

1832 Yields: 

1833 int: Description 

1834 on several lines. 

1835 """ 

1836 sections, warnings = parse_google(docstring, returns_named_value=False) 

1837 assert len(sections) == 2 

1838 assert not warnings 

1839 retval = sections[1].value[0] 

1840 assert retval.name == "" 

1841 assert retval.annotation == "int" 

1842 assert retval.description == "Description\non several lines." 

1843 

1844 docstring = """ 

1845 Summary. 

1846 

1847 Yields: 

1848 Description 

1849 on several lines. 

1850 """ 

1851 sections, warnings = parse_google(docstring, returns_named_value=False) 

1852 assert len(sections) == 2 

1853 assert len(warnings) == 1 

1854 retval = sections[1].value[0] 

1855 assert retval.name == "" 

1856 assert retval.annotation is None 

1857 assert retval.description == "Description\non several lines." 

1858 

1859 

1860def test_type_in_receives_without_parentheses(parse_google: ParserType) -> None: 

1861 """Assert we can parse the return type without parentheses. 

1862 

1863 Parameters: 

1864 parse_google: Fixture parser. 

1865 """ 

1866 docstring = """ 

1867 Summary. 

1868 

1869 Receives: 

1870 int: Description 

1871 on several lines. 

1872 """ 

1873 sections, warnings = parse_google(docstring, receives_named_value=False) 

1874 assert len(sections) == 2 

1875 assert not warnings 

1876 retval = sections[1].value[0] 

1877 assert retval.name == "" 

1878 assert retval.annotation == "int" 

1879 assert retval.description == "Description\non several lines." 

1880 

1881 docstring = """ 

1882 Summary. 

1883 

1884 Receives: 

1885 Description 

1886 on several lines. 

1887 """ 

1888 sections, warnings = parse_google(docstring, receives_named_value=False) 

1889 assert len(sections) == 2 

1890 assert len(warnings) == 1 

1891 retval = sections[1].value[0] 

1892 assert retval.name == "" 

1893 assert retval.annotation is None 

1894 assert retval.description == "Description\non several lines." 

1895 

1896 

1897def test_reading_property_type_in_summary(parse_google: ParserType) -> None: 

1898 """Assert we can parse the return type of properties in their summary. 

1899 

1900 Parameters: 

1901 parse_google: Fixture parser. 

1902 """ 

1903 docstring = "str: Description of the property." 

1904 parent = Attribute("prop") 

1905 parent.labels.add("property") 

1906 sections, _ = parse_google(docstring, returns_type_in_property_summary=True, parent=parent) 

1907 assert len(sections) == 2 

1908 assert sections[0].kind is DocstringSectionKind.text 

1909 assert sections[1].kind is DocstringSectionKind.returns 

1910 retval = sections[1].value[0] 

1911 assert retval.name == "" 

1912 assert retval.annotation.name == "str" 

1913 assert retval.description == "" 

1914 

1915 

1916# ============================================================================================= 

1917# Warnings 

1918def test_disabled_warnings(parse_google: ParserType) -> None: 

1919 """Assert warnings are disabled. 

1920 

1921 Parameters: 

1922 parse_google: Fixture parser. 

1923 """ 

1924 docstring = """ 

1925 Parameters: 

1926 x: X value. 

1927 """ 

1928 _, warnings = parse_google(docstring, warnings=True) 

1929 assert warnings 

1930 _, warnings = parse_google(docstring, warnings=False) 

1931 assert not warnings