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

23 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-16 15:54 +0200

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

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Any, Iterator, List, Protocol, Tuple, 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 types import ModuleType 

19 

20 

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

22ParseResultType = Tuple[List[DocstringSection], List[str]] 

23 

24 

25class ParserType(Protocol): # noqa: D101 

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

27 self, 

28 docstring: str, 

29 parent: ParentType | None = None, 

30 **parser_opts: Any, 

31 ) -> ParseResultType: ... 

32 

33 

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

35 """Wrap a parser to help testing. 

36 

37 Parameters: 

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

39 

40 Yields: 

41 The wrapped function. 

42 """ 

43 original_warn = parser_module.docstring_warning 

44 

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

46 """Parse a doctring. 

47 

48 Parameters: 

49 docstring: The docstring to parse. 

50 parent: The docstring's parent object. 

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

52 

53 Returns: 

54 The parsed sections, and warnings. 

55 """ 

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

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

58 if parent is not None: 

59 docstring_object.parent = parent 

60 parent.docstring = docstring_object 

61 warnings = [] 

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

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

64 ) 

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

66 func = getattr(parser_module, func_name) 

67 sections = func(docstring_object, **parser_opts) 

68 return sections, warnings 

69 

70 yield parse 

71 

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