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
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
1"""The base module for docstring parsing."""
3import inspect
4from abc import ABCMeta, abstractmethod
5from typing import Any, List, Optional, Tuple
7empty = inspect.Signature.empty
10class AnnotatedObject:
11 """A helper class to store information about an annotated object."""
13 def __init__(self, annotation: Any, description: str) -> None:
14 """
15 Initialize the object.
17 Arguments:
18 annotation: The object's annotation.
19 description: The object's description.
20 """
21 self.annotation = annotation
22 self.description = description
25class Attribute(AnnotatedObject):
26 """A helper class to store information about a documented attribute."""
28 def __init__(self, name: str, annotation: Any, description: str) -> None:
29 """
30 Initialize the object.
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
41class Parameter(AnnotatedObject):
42 """A helper class to store information about a signature parameter."""
44 def __init__(self, name: str, annotation: Any, description: str, kind: Any, default: Any = empty) -> None:
45 """
46 Initialize the object.
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
60 def __str__(self):
61 return self.name
63 def __repr__(self):
64 return f"<Parameter({self.name}, {self.annotation}, {self.description}, {self.kind}, {self.default})>"
66 @property
67 def is_optional(self):
68 """Tell if this parameter is optional."""
69 return self.default is not empty
71 @property
72 def is_required(self):
73 """Tell if this parameter is required."""
74 return not self.is_optional
76 @property
77 def is_args(self):
78 """Tell if this parameter is positional."""
79 return self.kind is inspect.Parameter.VAR_POSITIONAL
81 @property
82 def is_kwargs(self):
83 """Tell if this parameter is a keyword."""
84 return self.kind is inspect.Parameter.VAR_KEYWORD
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)
98class Section:
99 """A helper class to store a docstring section."""
101 class Type:
102 """The possible section types."""
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"
113 def __init__(self, section_type: str, value: Any) -> None:
114 """
115 Initialize the object.
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
124 def __str__(self):
125 return self.type
127 def __repr__(self):
128 return f"<Section(type={self.type!r})>"
131class Parser(metaclass=ABCMeta):
132 """
133 A class to parse docstrings.
135 It is instantiated with an object's path, docstring, signature and return type.
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 """
142 def __init__(self) -> None:
143 """Initialize the object."""
144 self.context: dict = {}
145 self.errors: List[str] = []
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.
151 Arguments:
152 docstring: The docstring to parse.
153 context: Some context helping to parse the docstring.
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
164 def error(self, message) -> None:
165 """
166 Record a parsing error.
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)
175 @abstractmethod
176 def parse_sections(self, docstring: str) -> List[Section]:
177 """
178 Parse a docstring as a list of sections.
180 Arguments:
181 docstring: The docstring to parse.
183 Returns:
184 A list of [`Section`][pytkdocs.parsers.docstrings.base.Section]s.
185 """
186 raise NotImplementedError
189class UnavailableParser:
190 def __init__(self, message):
191 self.message = message
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]
200 def __call__(self, *args, **kwargs):
201 return self