Coverage for tests/test_docstrings/helpers.py: 96.30%

23 statements  

« prev     ^ index     » next       coverage.py v7.6.2, created at 2024-10-12 01:34 +0200

1"""This module contains helpers for testing docstring parsing.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Any, Protocol, Union 

6 

7from griffe import ( 

8 Attribute, 

9 Class, 

10 Docstring, 

11 DocstringSection, 

12 Function, 

13 LogLevel, 

14 Module, 

15) 

16 

17if TYPE_CHECKING: 

18 from collections.abc import Iterator 

19 from types import ModuleType 

20 

21 

22ParentType = Union[Module, Class, Function, Attribute, None] 

23ParseResultType = tuple[list[DocstringSection], list[str]] 

24 

25 

26class ParserType(Protocol): # noqa: D101 

27 def __call__( # noqa: D102 27 ↛ exitline 27 didn't jump to the function exit

28 self, 

29 docstring: str, 

30 parent: ParentType | None = None, 

31 **parser_opts: Any, 

32 ) -> ParseResultType: ... 

33 

34 

35def parser(parser_module: ModuleType) -> Iterator[ParserType]: 

36 """Wrap a parser to help testing. 

37 

38 Parameters: 

39 parser_module: The parser module containing a `parse` function. 

40 

41 Yields: 

42 The wrapped function. 

43 """ 

44 original_warn = parser_module.docstring_warning 

45 

46 def parse(docstring: str, parent: ParentType | None = None, **parser_opts: Any) -> ParseResultType: 

47 """Parse a docstring. 

48 

49 Parameters: 

50 docstring: The docstring to parse. 

51 parent: The docstring's parent object. 

52 **parser_opts: Additional options accepted by the parser. 

53 

54 Returns: 

55 The parsed sections, and warnings. 

56 """ 

57 docstring_object = Docstring(docstring, lineno=1, endlineno=None) 

58 docstring_object.endlineno = len(docstring_object.lines) + 1 

59 if parent is not None: 

60 docstring_object.parent = parent 

61 parent.docstring = docstring_object 

62 warnings = [] 

63 parser_module.docstring_warning = ( # type: ignore[attr-defined] 

64 lambda _docstring, _offset, message, log_level=LogLevel.warning: warnings.append(message) 

65 ) 

66 func_name = f"parse_{parser_module.__name__.split('.')[-1]}" 

67 func = getattr(parser_module, func_name) 

68 sections = func(docstring_object, **parser_opts) 

69 return sections, warnings 

70 

71 yield parse 

72 

73 parser_module.docstring_warning = original_warn # type: ignore[attr-defined]