Coverage for src/pytkdocs/parsers/docstrings/base.py: 86.61%

Shortcuts on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

88 statements  

1"""The base module for docstring parsing.""" 

2 

3import inspect 

4from abc import ABCMeta, abstractmethod 

5from typing import Any, List, Optional, Tuple 

6 

7empty = inspect.Signature.empty 

8 

9 

10class AnnotatedObject: 

11 """A helper class to store information about an annotated object.""" 

12 

13 def __init__(self, annotation: Any, description: str) -> None: 

14 """ 

15 Initialize the object. 

16 

17 Arguments: 

18 annotation: The object's annotation. 

19 description: The object's description. 

20 """ 

21 self.annotation = annotation 

22 self.description = description 

23 

24 

25class Attribute(AnnotatedObject): 

26 """A helper class to store information about a documented attribute.""" 

27 

28 def __init__(self, name: str, annotation: Any, description: str) -> None: 

29 """ 

30 Initialize the object. 

31 

32 Arguments: 

33 name: The attribute's name. 

34 annotation: The object's annotation. 

35 description: The object's description. 

36 """ 

37 super().__init__(annotation, description) 

38 self.name = name 

39 

40 

41class Parameter(AnnotatedObject): 

42 """A helper class to store information about a signature parameter.""" 

43 

44 def __init__(self, name: str, annotation: Any, description: str, kind: Any, default: Any = empty) -> None: 

45 """ 

46 Initialize the object. 

47 

48 Arguments: 

49 name: The parameter's name. 

50 annotation: The parameter's annotation. 

51 description: The parameter's description. 

52 kind: The parameter's kind (positional only, keyword only, etc.). 

53 default: The parameter's default value. 

54 """ 

55 super().__init__(annotation, description) 

56 self.name = name 

57 self.kind = kind 

58 self.default = default 

59 

60 def __str__(self): 

61 return self.name 

62 

63 def __repr__(self): 

64 return f"<Parameter({self.name}, {self.annotation}, {self.description}, {self.kind}, {self.default})>" 

65 

66 @property 

67 def is_optional(self): 

68 """Tell if this parameter is optional.""" 

69 return self.default is not empty 

70 

71 @property 

72 def is_required(self): 

73 """Tell if this parameter is required.""" 

74 return not self.is_optional 

75 

76 @property 

77 def is_args(self): 

78 """Tell if this parameter is positional.""" 

79 return self.kind is inspect.Parameter.VAR_POSITIONAL 

80 

81 @property 

82 def is_kwargs(self): 

83 """Tell if this parameter is a keyword.""" 

84 return self.kind is inspect.Parameter.VAR_KEYWORD 

85 

86 @property 

87 def default_string(self): 

88 """Return the default value as a string.""" 

89 if self.is_kwargs: 

90 return "{}" 

91 if self.is_args: 

92 return "()" 

93 if self.is_required: 

94 return "" 

95 return repr(self.default) 

96 

97 

98class Section: 

99 """A helper class to store a docstring section.""" 

100 

101 class Type: 

102 """The possible section types.""" 

103 

104 MARKDOWN = "markdown" 

105 PARAMETERS = "parameters" 

106 EXCEPTIONS = "exceptions" 

107 RETURN = "return" 

108 YIELD = "yield" 

109 EXAMPLES = "examples" 

110 ATTRIBUTES = "attributes" 

111 KEYWORD_ARGS = "keyword_args" 

112 

113 def __init__(self, section_type: str, value: Any) -> None: 

114 """ 

115 Initialize the object. 

116 

117 Arguments: 

118 section_type: The type of the section, from the [`Type`][pytkdocs.parsers.docstrings.base.Section.Type] enum. 

119 value: The section value. 

120 """ 

121 self.type = section_type 

122 self.value = value 

123 

124 def __str__(self): 

125 return self.type 

126 

127 def __repr__(self): 

128 return f"<Section(type={self.type!r})>" 

129 

130 

131class Parser(metaclass=ABCMeta): 

132 """ 

133 A class to parse docstrings. 

134 

135 It is instantiated with an object's path, docstring, signature and return type. 

136 

137 The `parse` method then returns structured data, 

138 in the form of a list of [`Section`][pytkdocs.parsers.docstrings.base.Section]s. 

139 It also return the list of errors that occurred during parsing. 

140 """ 

141 

142 def __init__(self) -> None: 

143 """Initialize the object.""" 

144 self.context: dict = {} 

145 self.errors: List[str] = [] 

146 

147 def parse(self, docstring: str, context: Optional[dict] = None) -> Tuple[List[Section], List[str]]: 

148 """ 

149 Parse a docstring and return a list of sections and parsing errors. 

150 

151 Arguments: 

152 docstring: The docstring to parse. 

153 context: Some context helping to parse the docstring. 

154 

155 Returns: 

156 A tuple containing the list of sections and the parsing errors. 

157 """ 

158 self.context = context or {} 

159 self.errors = [] 

160 sections = self.parse_sections(docstring) 

161 errors = self.errors 

162 return sections, errors 

163 

164 def error(self, message) -> None: 

165 """ 

166 Record a parsing error. 

167 

168 Arguments: 

169 message: A message described the error. 

170 """ 

171 if self.context["obj"]: 171 ↛ 173line 171 didn't jump to line 173, because the condition on line 171 was never false

172 message = f"{self.context['obj'].path}: {message}" 

173 self.errors.append(message) 

174 

175 @abstractmethod 

176 def parse_sections(self, docstring: str) -> List[Section]: 

177 """ 

178 Parse a docstring as a list of sections. 

179 

180 Arguments: 

181 docstring: The docstring to parse. 

182 

183 Returns: 

184 A list of [`Section`][pytkdocs.parsers.docstrings.base.Section]s. 

185 """ 

186 raise NotImplementedError 

187 

188 

189class UnavailableParser: 

190 def __init__(self, message): 

191 self.message = message 

192 

193 def parse(self, docstring: str, context: Optional[dict] = None) -> Tuple[List[Section], List[str]]: 

194 context = context or {} 

195 message = self.message 

196 if "obj" in context: 

197 message = f"{context['obj'].path}: {message}" 

198 return [], [message] 

199 

200 def __call__(self, *args, **kwargs): 

201 return self