handsdown-fork 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- handsdown/__init__.py +4 -0
- handsdown/__main__.py +5 -0
- handsdown/ast_parser/__init__.py +28 -0
- handsdown/ast_parser/analyzers/__init__.py +1 -0
- handsdown/ast_parser/analyzers/base_analyzer.py +29 -0
- handsdown/ast_parser/analyzers/class_analyzer.py +176 -0
- handsdown/ast_parser/analyzers/expression_analyzer.py +740 -0
- handsdown/ast_parser/analyzers/function_analyzer.py +170 -0
- handsdown/ast_parser/analyzers/module_analyzer.py +210 -0
- handsdown/ast_parser/module_record_list.py +75 -0
- handsdown/ast_parser/node_records/__init__.py +1 -0
- handsdown/ast_parser/node_records/argument_record.py +107 -0
- handsdown/ast_parser/node_records/attribute_record.py +69 -0
- handsdown/ast_parser/node_records/class_record.py +136 -0
- handsdown/ast_parser/node_records/expression_record.py +60 -0
- handsdown/ast_parser/node_records/function_record.py +141 -0
- handsdown/ast_parser/node_records/import_record.py +96 -0
- handsdown/ast_parser/node_records/module_record.py +298 -0
- handsdown/ast_parser/node_records/node_record.py +159 -0
- handsdown/ast_parser/node_records/text_record.py +49 -0
- handsdown/ast_parser/smart_ast.py +160 -0
- handsdown/ast_parser/type_defs.py +24 -0
- handsdown/cli_parser.py +294 -0
- handsdown/constants.py +22 -0
- handsdown/exceptions.py +21 -0
- handsdown/generators/__init__.py +0 -0
- handsdown/generators/base.py +418 -0
- handsdown/generators/material.py +23 -0
- handsdown/generators/rtd.py +13 -0
- handsdown/jinja_manager.py +60 -0
- handsdown/loader.py +159 -0
- handsdown/main.py +63 -0
- handsdown/md_document.py +327 -0
- handsdown/processors/__init__.py +6 -0
- handsdown/processors/base.py +308 -0
- handsdown/processors/pep257.py +116 -0
- handsdown/processors/rst.py +147 -0
- handsdown/processors/section.py +43 -0
- handsdown/processors/section_block.py +28 -0
- handsdown/processors/section_map.py +107 -0
- handsdown/processors/smart.py +45 -0
- handsdown/py.typed +0 -0
- handsdown/templates/common/argument.py.jinja2 +10 -0
- handsdown/templates/common/class.md.jinja2 +31 -0
- handsdown/templates/common/class_signature.py.jinja2 +15 -0
- handsdown/templates/common/docstring.md.jinja2 +8 -0
- handsdown/templates/common/function.md.jinja2 +19 -0
- handsdown/templates/common/function_signature.py.jinja2 +21 -0
- handsdown/templates/common/gh_pages_config.yml.jinja2 +5 -0
- handsdown/templates/common/index.md.jinja2 +28 -0
- handsdown/templates/common/method.md.jinja2 +21 -0
- handsdown/templates/material/mkdocs.yml.jinja2 +41 -0
- handsdown/templates/material/module.md.jinja2 +56 -0
- handsdown/templates/material/readthedocs.yml.jinja2 +19 -0
- handsdown/templates/material/requirements.mkdocs.txt.jinja2 +2 -0
- handsdown/templates/readthedocs/mkdocs.yml.jinja2 +9 -0
- handsdown/templates/readthedocs/module.md.jinja2 +56 -0
- handsdown/templates/readthedocs/readthedocs.yml.jinja2 +15 -0
- handsdown/utils/__init__.py +1 -0
- handsdown/utils/blackify.py +33 -0
- handsdown/utils/docstring_formatter.py +66 -0
- handsdown/utils/import_string.py +206 -0
- handsdown/utils/indent_trimmer.py +157 -0
- handsdown/utils/logger.py +32 -0
- handsdown/utils/markdown.py +104 -0
- handsdown/utils/path.py +20 -0
- handsdown/utils/path_finder.py +204 -0
- handsdown/utils/strings.py +74 -0
- handsdown_fork-0.1.0.dist-info/METADATA +436 -0
- handsdown_fork-0.1.0.dist-info/RECORD +74 -0
- handsdown_fork-0.1.0.dist-info/WHEEL +5 -0
- handsdown_fork-0.1.0.dist-info/entry_points.txt +2 -0
- handsdown_fork-0.1.0.dist-info/licenses/LICENSE +22 -0
- handsdown_fork-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,740 @@
|
|
|
1
|
+
"""AST analyzer for `ast.expr` records."""
|
|
2
|
+
|
|
3
|
+
import handsdown.ast_parser.smart_ast as ast
|
|
4
|
+
from handsdown.ast_parser.analyzers.base_analyzer import BaseAnalyzer
|
|
5
|
+
from handsdown.ast_parser.type_defs import ASTIterable, Node
|
|
6
|
+
from handsdown.constants import ENCODING
|
|
7
|
+
from handsdown.utils.logger import get_logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ExpressionAnalyzer(BaseAnalyzer):
|
|
11
|
+
"""
|
|
12
|
+
AST analyzer for `ast.expr` records.
|
|
13
|
+
|
|
14
|
+
Prepares `parts` for `NodeRecord.render` method.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
super().__init__()
|
|
19
|
+
self._logger = get_logger()
|
|
20
|
+
self.parts: list[Node] = []
|
|
21
|
+
|
|
22
|
+
# dummy value to replace unknown nodes and operators
|
|
23
|
+
UNKNOWN = "..."
|
|
24
|
+
|
|
25
|
+
# representation map for binary operators
|
|
26
|
+
BINOP_SYMBOLS: dict[type[ast.AST], str] = {
|
|
27
|
+
ast.Add: "+",
|
|
28
|
+
ast.Sub: "-",
|
|
29
|
+
ast.Mult: "*",
|
|
30
|
+
ast.Div: "/",
|
|
31
|
+
ast.Mod: "%",
|
|
32
|
+
ast.Pow: "**",
|
|
33
|
+
ast.LShift: "<<",
|
|
34
|
+
ast.RShift: ">>",
|
|
35
|
+
ast.BitOr: "|",
|
|
36
|
+
ast.BitXor: "^",
|
|
37
|
+
ast.BitAnd: "&",
|
|
38
|
+
ast.FloorDiv: "//",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# representation map for boolean operators
|
|
42
|
+
BOOLOP_SYMBOLS: dict[type[ast.AST], str] = {ast.And: "and", ast.Or: "or"}
|
|
43
|
+
|
|
44
|
+
# representation map for comparison operators
|
|
45
|
+
CMPOP_SYMBOLS: dict[type[ast.AST], str] = {
|
|
46
|
+
ast.Eq: "==",
|
|
47
|
+
ast.NotEq: "!=",
|
|
48
|
+
ast.Lt: "<",
|
|
49
|
+
ast.LtE: "<=",
|
|
50
|
+
ast.Gt: ">",
|
|
51
|
+
ast.GtE: ">=",
|
|
52
|
+
ast.Is: "is",
|
|
53
|
+
ast.IsNot: "is not",
|
|
54
|
+
ast.In: "in",
|
|
55
|
+
ast.NotIn: "not in",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# representation map for unary operators
|
|
59
|
+
UNARYOP_SYMBOLS: dict[type[ast.AST], str] = {
|
|
60
|
+
ast.Invert: "~",
|
|
61
|
+
ast.Not: "not",
|
|
62
|
+
ast.UAdd: "+",
|
|
63
|
+
ast.USub: "-",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def visit_Constant(self, node: ast.Constant) -> None:
|
|
67
|
+
"""
|
|
68
|
+
Parse info from `ast.Str` node and put it to `parts`.
|
|
69
|
+
|
|
70
|
+
Examples::
|
|
71
|
+
|
|
72
|
+
"my_string"
|
|
73
|
+
|
|
74
|
+
Arguments:
|
|
75
|
+
node -- AST node.
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
value = node.value
|
|
79
|
+
if isinstance(value, bytes):
|
|
80
|
+
value = value.decode(ENCODING)
|
|
81
|
+
self.parts.append(repr(value))
|
|
82
|
+
|
|
83
|
+
def visit_Name(self, node: ast.Name) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Parse info from `ast.Name` node and put it to `parts`.
|
|
86
|
+
|
|
87
|
+
Examples::
|
|
88
|
+
|
|
89
|
+
my_value
|
|
90
|
+
|
|
91
|
+
Arguments:
|
|
92
|
+
node -- AST node.
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
self.parts.append(node.id)
|
|
96
|
+
self.related_names.append(node.id)
|
|
97
|
+
|
|
98
|
+
def visit_Subscript(self, node: ast.Subscript) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Parse info from `ast.Subscript` node and put it to `parts`.
|
|
101
|
+
|
|
102
|
+
Type annotations are also matched by this method.
|
|
103
|
+
|
|
104
|
+
Examples::
|
|
105
|
+
|
|
106
|
+
Union[Name, bool]
|
|
107
|
+
List[1:4]
|
|
108
|
+
|
|
109
|
+
Arguments:
|
|
110
|
+
node -- AST node.
|
|
111
|
+
|
|
112
|
+
"""
|
|
113
|
+
self.parts.append(node.value)
|
|
114
|
+
self.parts.append("[")
|
|
115
|
+
if isinstance(node.slice, ast.Index) and isinstance(node.slice.value, ast.Tuple): # type: ignore
|
|
116
|
+
self._visit_iterable(node.slice.value) # type: ignore
|
|
117
|
+
elif isinstance(node.slice, ast.Tuple):
|
|
118
|
+
self._visit_iterable(node.slice)
|
|
119
|
+
else:
|
|
120
|
+
self._analyze_child(node.slice)
|
|
121
|
+
self.parts.append("]")
|
|
122
|
+
|
|
123
|
+
def visit_Attribute(self, node: ast.Attribute) -> None:
|
|
124
|
+
"""
|
|
125
|
+
Parse info from `ast.Attribute` node and put it to `parts`.
|
|
126
|
+
|
|
127
|
+
Examples::
|
|
128
|
+
|
|
129
|
+
my_object.attribute
|
|
130
|
+
|
|
131
|
+
Arguments:
|
|
132
|
+
node -- AST node.
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
self.parts.append(node.value)
|
|
136
|
+
self.parts.append(".")
|
|
137
|
+
self.parts.append(node.attr)
|
|
138
|
+
|
|
139
|
+
def _visit_iterable(self, node: ASTIterable) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Parse info from an iterable node and put it to `parts`.
|
|
142
|
+
|
|
143
|
+
Used for `ast.Tuple`, `ast.Subscript`, `ast.List`, `ast.Set`
|
|
144
|
+
|
|
145
|
+
Examples::
|
|
146
|
+
|
|
147
|
+
[1, 2, 3]
|
|
148
|
+
{1, 2, 3}
|
|
149
|
+
(1, 2, 3)
|
|
150
|
+
Union[str, bool]
|
|
151
|
+
|
|
152
|
+
Arguments:
|
|
153
|
+
node -- AST node.
|
|
154
|
+
|
|
155
|
+
"""
|
|
156
|
+
if node.elts:
|
|
157
|
+
for index, element in enumerate(node.elts):
|
|
158
|
+
if index:
|
|
159
|
+
self.parts.append(", ")
|
|
160
|
+
self._analyze_child(element)
|
|
161
|
+
|
|
162
|
+
def _analyze_child(self, node: ast.AST) -> None:
|
|
163
|
+
if isinstance(node, str):
|
|
164
|
+
self.parts.append(node)
|
|
165
|
+
return
|
|
166
|
+
analyzer = self.__class__()
|
|
167
|
+
analyzer.visit(node)
|
|
168
|
+
self.parts.extend(analyzer.parts)
|
|
169
|
+
self.related_names.extend(analyzer.related_names)
|
|
170
|
+
|
|
171
|
+
def visit_List(self, node: ast.List) -> None:
|
|
172
|
+
"""
|
|
173
|
+
Parse info from `ast.List` node and put it to `parts`.
|
|
174
|
+
|
|
175
|
+
Examples::
|
|
176
|
+
|
|
177
|
+
[1, 2, 3]
|
|
178
|
+
|
|
179
|
+
Arguments:
|
|
180
|
+
node -- AST node.
|
|
181
|
+
|
|
182
|
+
"""
|
|
183
|
+
self.parts.append("[")
|
|
184
|
+
self._visit_iterable(node)
|
|
185
|
+
self.parts.append("]")
|
|
186
|
+
|
|
187
|
+
def visit_Set(self, node: ast.Set) -> None:
|
|
188
|
+
"""
|
|
189
|
+
Parse info from `ast.Set` node and put it to `parts`.
|
|
190
|
+
|
|
191
|
+
Examples::
|
|
192
|
+
|
|
193
|
+
{1, 2, 3}
|
|
194
|
+
|
|
195
|
+
Arguments:
|
|
196
|
+
node -- AST node.
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
self.parts.append("{")
|
|
200
|
+
self._visit_iterable(node)
|
|
201
|
+
self.parts.append("}")
|
|
202
|
+
|
|
203
|
+
def visit_Tuple(self, node: ast.Tuple) -> None:
|
|
204
|
+
"""
|
|
205
|
+
Parse info from `ast.Tuple` node and put it to `parts`.
|
|
206
|
+
|
|
207
|
+
Examples::
|
|
208
|
+
|
|
209
|
+
(1, 2, 3)
|
|
210
|
+
|
|
211
|
+
Arguments:
|
|
212
|
+
node -- AST node.
|
|
213
|
+
|
|
214
|
+
"""
|
|
215
|
+
self.parts.append("(")
|
|
216
|
+
self._visit_iterable(node)
|
|
217
|
+
self.parts.append(")")
|
|
218
|
+
|
|
219
|
+
def visit_Call(self, node: ast.Call) -> None:
|
|
220
|
+
"""
|
|
221
|
+
Parse info from `ast.Call` node and put it to `parts`.
|
|
222
|
+
|
|
223
|
+
Arguments:
|
|
224
|
+
node -- AST node.
|
|
225
|
+
|
|
226
|
+
"""
|
|
227
|
+
self.parts.append(node.func)
|
|
228
|
+
self.parts.append("(")
|
|
229
|
+
|
|
230
|
+
# FIXME: `AST2` ast.Call stores args argument in `starargs`
|
|
231
|
+
starargs = getattr(node, "starargs", None)
|
|
232
|
+
|
|
233
|
+
# FIXME: `AST2` ast.Call stores kwargs argument in `kwargs`
|
|
234
|
+
kwargs = getattr(node, "kwargs", None)
|
|
235
|
+
|
|
236
|
+
elements = [
|
|
237
|
+
*node.args,
|
|
238
|
+
*node.keywords,
|
|
239
|
+
*([starargs] if starargs else []),
|
|
240
|
+
*([kwargs] if kwargs else []),
|
|
241
|
+
]
|
|
242
|
+
for index, element in enumerate(elements):
|
|
243
|
+
if index:
|
|
244
|
+
self.parts.append(", ")
|
|
245
|
+
if element is starargs:
|
|
246
|
+
self.parts.append("*")
|
|
247
|
+
if element is kwargs:
|
|
248
|
+
self.parts.append("**")
|
|
249
|
+
|
|
250
|
+
self.parts.append(element)
|
|
251
|
+
|
|
252
|
+
self.parts.append(")")
|
|
253
|
+
|
|
254
|
+
def visit_Starred(self, node: ast.Starred) -> None:
|
|
255
|
+
"""
|
|
256
|
+
Parse info from `ast.Starred` node and put it to `parts`.
|
|
257
|
+
|
|
258
|
+
Examples::
|
|
259
|
+
|
|
260
|
+
*arg
|
|
261
|
+
|
|
262
|
+
Arguments:
|
|
263
|
+
node -- AST node.
|
|
264
|
+
|
|
265
|
+
"""
|
|
266
|
+
self.parts.append("*")
|
|
267
|
+
self.parts.append(node.value)
|
|
268
|
+
|
|
269
|
+
def visit_keyword(self, node: ast.keyword) -> None:
|
|
270
|
+
"""
|
|
271
|
+
Parse info from `ast.keyword` node and put it to `parts`.
|
|
272
|
+
|
|
273
|
+
Examples::
|
|
274
|
+
|
|
275
|
+
my_func(**{"kwarg": "value"})
|
|
276
|
+
my_func(kwarg="value")
|
|
277
|
+
|
|
278
|
+
Arguments:
|
|
279
|
+
node -- AST node.
|
|
280
|
+
|
|
281
|
+
"""
|
|
282
|
+
if not node.arg:
|
|
283
|
+
self.parts.append("**")
|
|
284
|
+
self.parts.append(node.value)
|
|
285
|
+
return
|
|
286
|
+
|
|
287
|
+
self.parts.append(node.arg)
|
|
288
|
+
self.parts.append("=")
|
|
289
|
+
self.parts.append(node.value)
|
|
290
|
+
|
|
291
|
+
def visit_Dict(self, node: ast.Dict) -> None:
|
|
292
|
+
"""
|
|
293
|
+
Parse info from `ast.Dict` node and put it to `parts`.
|
|
294
|
+
|
|
295
|
+
Arguments:
|
|
296
|
+
node -- AST node.
|
|
297
|
+
|
|
298
|
+
"""
|
|
299
|
+
self.parts.append("{")
|
|
300
|
+
for index, key in enumerate(node.keys or []):
|
|
301
|
+
if key is None:
|
|
302
|
+
continue
|
|
303
|
+
if index:
|
|
304
|
+
self.parts.append(", ")
|
|
305
|
+
self.parts.append(key)
|
|
306
|
+
self.parts.append(": ")
|
|
307
|
+
self.parts.append(node.values[index])
|
|
308
|
+
self.parts.append("}")
|
|
309
|
+
|
|
310
|
+
def visit_Compare(self, node: ast.Compare) -> None:
|
|
311
|
+
"""
|
|
312
|
+
Parse info from `ast.Compare` node and put it to `parts`.
|
|
313
|
+
|
|
314
|
+
Examples::
|
|
315
|
+
|
|
316
|
+
value < 5
|
|
317
|
+
1 < weekday < 7
|
|
318
|
+
|
|
319
|
+
Arguments:
|
|
320
|
+
node -- AST node.
|
|
321
|
+
|
|
322
|
+
"""
|
|
323
|
+
self.parts.append(node.left)
|
|
324
|
+
for index, right in enumerate(node.comparators):
|
|
325
|
+
operator_class = type(node.ops[index])
|
|
326
|
+
self.parts.append(" ")
|
|
327
|
+
operator = self.CMPOP_SYMBOLS.get(operator_class, self.UNKNOWN)
|
|
328
|
+
if operator == self.UNKNOWN:
|
|
329
|
+
self._logger.warning(f"Unknown comparison operator: {operator_class.__name__}")
|
|
330
|
+
self.parts.append(operator)
|
|
331
|
+
self.parts.append(" ")
|
|
332
|
+
self.parts.append(right)
|
|
333
|
+
|
|
334
|
+
def visit_BinOp(self, node: ast.BinOp) -> None:
|
|
335
|
+
"""
|
|
336
|
+
Parse info from `ast.BinOp` node and put it to `parts`.
|
|
337
|
+
|
|
338
|
+
Examples::
|
|
339
|
+
|
|
340
|
+
1 + 5
|
|
341
|
+
value + 1
|
|
342
|
+
|
|
343
|
+
Arguments:
|
|
344
|
+
node -- AST node.
|
|
345
|
+
|
|
346
|
+
"""
|
|
347
|
+
self.parts.append(node.left)
|
|
348
|
+
self.parts.append(" ")
|
|
349
|
+
operator = self.BINOP_SYMBOLS.get(type(node.op), self.UNKNOWN)
|
|
350
|
+
if operator == self.UNKNOWN:
|
|
351
|
+
self._logger.warning(f"Unknown binary operator: {node.op.__class__.__name__}")
|
|
352
|
+
self.parts.append(operator)
|
|
353
|
+
self.parts.append(" ")
|
|
354
|
+
self.parts.append(node.right)
|
|
355
|
+
|
|
356
|
+
def visit_BoolOp(self, node: ast.BoolOp) -> None:
|
|
357
|
+
"""
|
|
358
|
+
Parse info from `ast.BoolOp` node and put it to `parts`.
|
|
359
|
+
|
|
360
|
+
Examples::
|
|
361
|
+
|
|
362
|
+
value or True
|
|
363
|
+
a and b
|
|
364
|
+
|
|
365
|
+
Arguments:
|
|
366
|
+
node -- AST node.
|
|
367
|
+
|
|
368
|
+
"""
|
|
369
|
+
operator = self.BOOLOP_SYMBOLS.get(type(node.op), self.UNKNOWN)
|
|
370
|
+
if operator == self.UNKNOWN:
|
|
371
|
+
self._logger.warning(f"Unknown boolean operator: {node.op.__class__.__name__}")
|
|
372
|
+
for index, value in enumerate(node.values):
|
|
373
|
+
if index:
|
|
374
|
+
self.parts.append(" ")
|
|
375
|
+
self.parts.append(operator)
|
|
376
|
+
self.parts.append(" ")
|
|
377
|
+
self.parts.append(value)
|
|
378
|
+
|
|
379
|
+
def visit_UnaryOp(self, node: ast.UnaryOp) -> None:
|
|
380
|
+
"""
|
|
381
|
+
Parse info from `ast.UnaryOp` node and put it to `parts`.
|
|
382
|
+
|
|
383
|
+
Examples::
|
|
384
|
+
|
|
385
|
+
+5
|
|
386
|
+
-12
|
|
387
|
+
~1
|
|
388
|
+
not True
|
|
389
|
+
|
|
390
|
+
Arguments:
|
|
391
|
+
node -- AST node.
|
|
392
|
+
|
|
393
|
+
"""
|
|
394
|
+
operator = self.UNARYOP_SYMBOLS.get(type(node.op), self.UNKNOWN)
|
|
395
|
+
if operator == self.UNKNOWN:
|
|
396
|
+
self._logger.warning(f"Unknown unary operator: {node.op.__class__.__name__}")
|
|
397
|
+
self.parts.append(operator)
|
|
398
|
+
if operator == "not":
|
|
399
|
+
self.parts.append(" ")
|
|
400
|
+
self.parts.append(node.operand)
|
|
401
|
+
|
|
402
|
+
def visit_Lambda(self, node: ast.Lambda) -> None:
|
|
403
|
+
"""
|
|
404
|
+
Parse info from `ast.Lambda` node and put it to `parts`.
|
|
405
|
+
|
|
406
|
+
Examples::
|
|
407
|
+
|
|
408
|
+
lambda x: x + 5
|
|
409
|
+
|
|
410
|
+
Arguments:
|
|
411
|
+
node -- AST node.
|
|
412
|
+
|
|
413
|
+
"""
|
|
414
|
+
self.parts.append("lambda ")
|
|
415
|
+
self.parts.append(node.args)
|
|
416
|
+
self.parts.append(": ")
|
|
417
|
+
self.parts.append(node.body)
|
|
418
|
+
|
|
419
|
+
def visit_arguments(self, node: ast.arguments) -> None:
|
|
420
|
+
"""
|
|
421
|
+
Parse info from `ast.arguments` node and put it to `parts`.
|
|
422
|
+
|
|
423
|
+
Examples::
|
|
424
|
+
|
|
425
|
+
def my_func(arg, *args, **kwargs)
|
|
426
|
+
|
|
427
|
+
Arguments:
|
|
428
|
+
node -- AST node.
|
|
429
|
+
|
|
430
|
+
"""
|
|
431
|
+
arg_count = 0
|
|
432
|
+
for index, arg in enumerate(node.args):
|
|
433
|
+
if arg_count:
|
|
434
|
+
self.parts.append(", ")
|
|
435
|
+
arg_count += 1
|
|
436
|
+
default = None
|
|
437
|
+
default_index = len(node.args) - len(node.defaults) + index
|
|
438
|
+
if default_index < len(node.defaults):
|
|
439
|
+
default = node.defaults[default_index]
|
|
440
|
+
|
|
441
|
+
self.parts.append(arg)
|
|
442
|
+
if default is not None:
|
|
443
|
+
self.parts.append("=")
|
|
444
|
+
self.parts.append(default)
|
|
445
|
+
if node.vararg is not None:
|
|
446
|
+
if arg_count:
|
|
447
|
+
self.parts.append(", ")
|
|
448
|
+
|
|
449
|
+
arg_count += 1
|
|
450
|
+
self.parts.append("*")
|
|
451
|
+
self.parts.append(node.vararg)
|
|
452
|
+
if node.kwarg is not None:
|
|
453
|
+
if arg_count:
|
|
454
|
+
self.parts.append(", ")
|
|
455
|
+
|
|
456
|
+
arg_count += 1
|
|
457
|
+
self.parts.append("**")
|
|
458
|
+
self.parts.append(node.kwarg)
|
|
459
|
+
|
|
460
|
+
if arg_count:
|
|
461
|
+
self.parts.append(",")
|
|
462
|
+
|
|
463
|
+
def visit_arg(self, node: ast.arg) -> None:
|
|
464
|
+
"""
|
|
465
|
+
Parse info from `ast.arg` node and put it to `parts`.
|
|
466
|
+
|
|
467
|
+
Examples::
|
|
468
|
+
|
|
469
|
+
def my_func(arg)
|
|
470
|
+
def my_func(arg: str)
|
|
471
|
+
|
|
472
|
+
Arguments:
|
|
473
|
+
node -- AST node.
|
|
474
|
+
|
|
475
|
+
"""
|
|
476
|
+
self.parts.append(node.arg)
|
|
477
|
+
if node.annotation:
|
|
478
|
+
self.parts.append(": ")
|
|
479
|
+
self.parts.append(node.annotation)
|
|
480
|
+
|
|
481
|
+
def visit_Index(self, node: ast.Index) -> None:
|
|
482
|
+
"""
|
|
483
|
+
Parse info from `ast.Index` node and put it to `parts`.
|
|
484
|
+
|
|
485
|
+
Examples::
|
|
486
|
+
|
|
487
|
+
Union[str, bool]
|
|
488
|
+
Union[str]
|
|
489
|
+
|
|
490
|
+
Arguments:
|
|
491
|
+
node -- AST node.
|
|
492
|
+
|
|
493
|
+
"""
|
|
494
|
+
if isinstance(node.value, ast.Tuple): # type: ignore
|
|
495
|
+
self._visit_iterable(node.value) # type: ignore
|
|
496
|
+
return
|
|
497
|
+
self.parts.append(node.value) # type: ignore
|
|
498
|
+
|
|
499
|
+
def visit_Slice(self, node: ast.Slice) -> None:
|
|
500
|
+
"""
|
|
501
|
+
Parse info from `ast.Slice` node and put it to `parts`.
|
|
502
|
+
|
|
503
|
+
Examples::
|
|
504
|
+
|
|
505
|
+
[1:]
|
|
506
|
+
[:2]
|
|
507
|
+
[1:2]
|
|
508
|
+
[1:2:-1]
|
|
509
|
+
[::-1]
|
|
510
|
+
|
|
511
|
+
Arguments:
|
|
512
|
+
node -- AST node.
|
|
513
|
+
|
|
514
|
+
"""
|
|
515
|
+
if node.lower:
|
|
516
|
+
self.parts.append(node.lower)
|
|
517
|
+
self.parts.append(":")
|
|
518
|
+
if node.upper:
|
|
519
|
+
self.parts.append(node.upper)
|
|
520
|
+
if node.step:
|
|
521
|
+
self.parts.append(":")
|
|
522
|
+
self.parts.append(node.step)
|
|
523
|
+
|
|
524
|
+
def visit_JoinedStr(self, node: ast.JoinedStr) -> None:
|
|
525
|
+
"""
|
|
526
|
+
Parse info from `ast.JoinedStr` node and put it to `parts`.
|
|
527
|
+
|
|
528
|
+
Examples::
|
|
529
|
+
|
|
530
|
+
f'str: {my_string}'
|
|
531
|
+
|
|
532
|
+
Arguments:
|
|
533
|
+
node -- AST node.
|
|
534
|
+
|
|
535
|
+
"""
|
|
536
|
+
self.parts.append("f'")
|
|
537
|
+
for value in node.values:
|
|
538
|
+
if isinstance(value, ast.Constant):
|
|
539
|
+
str_value = value.value
|
|
540
|
+
if isinstance(str_value, bytes):
|
|
541
|
+
str_value = str_value.decode(ENCODING)
|
|
542
|
+
self.parts.append(str_value)
|
|
543
|
+
else:
|
|
544
|
+
self.parts.append(value)
|
|
545
|
+
self.parts.append("'")
|
|
546
|
+
|
|
547
|
+
def visit_FormattedValue(self, node: ast.FormattedValue) -> None:
|
|
548
|
+
"""
|
|
549
|
+
Parse info from `ast.FormattedValue` node and put it to `parts`.
|
|
550
|
+
|
|
551
|
+
Examples::
|
|
552
|
+
|
|
553
|
+
f"{formatted_value}"
|
|
554
|
+
|
|
555
|
+
Arguments:
|
|
556
|
+
node -- AST node.
|
|
557
|
+
|
|
558
|
+
"""
|
|
559
|
+
self.parts.append("{")
|
|
560
|
+
self.parts.append(node.value)
|
|
561
|
+
self.parts.append("}")
|
|
562
|
+
|
|
563
|
+
def visit_comprehension(self, node: ast.comprehension) -> None:
|
|
564
|
+
"""
|
|
565
|
+
Parse info from `ast.comprehension` node and put it to `parts`.
|
|
566
|
+
|
|
567
|
+
Examples::
|
|
568
|
+
|
|
569
|
+
for k in range(3) if k > 0 if True
|
|
570
|
+
|
|
571
|
+
Arguments:
|
|
572
|
+
node -- AST node.
|
|
573
|
+
|
|
574
|
+
"""
|
|
575
|
+
self.parts.append("for ")
|
|
576
|
+
self.parts.append(node.target)
|
|
577
|
+
self.parts.append(" in ")
|
|
578
|
+
self.parts.append(node.iter)
|
|
579
|
+
for expr in node.ifs:
|
|
580
|
+
self.parts.append(" if ")
|
|
581
|
+
self.parts.append(expr)
|
|
582
|
+
|
|
583
|
+
def visit_DictComp(self, node: ast.DictComp) -> None:
|
|
584
|
+
"""
|
|
585
|
+
Parse info from `ast.DictComp` node and put it to `parts`.
|
|
586
|
+
|
|
587
|
+
Examples::
|
|
588
|
+
|
|
589
|
+
{k: 1 for k in range(3)}
|
|
590
|
+
|
|
591
|
+
Arguments:
|
|
592
|
+
node -- AST node.
|
|
593
|
+
|
|
594
|
+
"""
|
|
595
|
+
self.parts.append("{")
|
|
596
|
+
self.parts.append(node.key)
|
|
597
|
+
self.parts.append(": ")
|
|
598
|
+
self.parts.append(node.value)
|
|
599
|
+
self.parts.append(" ")
|
|
600
|
+
for comprehension in node.generators:
|
|
601
|
+
self.parts.append(comprehension)
|
|
602
|
+
self.parts.append("}")
|
|
603
|
+
|
|
604
|
+
def visit_ListComp(self, node: ast.ListComp) -> None:
|
|
605
|
+
"""
|
|
606
|
+
Parse info from `ast.ListComp` node and put it to `parts`.
|
|
607
|
+
|
|
608
|
+
Examples::
|
|
609
|
+
|
|
610
|
+
[k + 1 for k in range(3)]
|
|
611
|
+
|
|
612
|
+
Arguments:
|
|
613
|
+
node -- AST node.
|
|
614
|
+
|
|
615
|
+
"""
|
|
616
|
+
self.parts.append("[")
|
|
617
|
+
self.parts.append(node.elt)
|
|
618
|
+
self.parts.append(" ")
|
|
619
|
+
for comprehension in node.generators:
|
|
620
|
+
self.parts.append(comprehension)
|
|
621
|
+
self.parts.append("]")
|
|
622
|
+
|
|
623
|
+
def visit_SetComp(self, node: ast.SetComp) -> None:
|
|
624
|
+
"""
|
|
625
|
+
Parse info from `ast.SetComp` node and put it to `parts`.
|
|
626
|
+
|
|
627
|
+
Examples::
|
|
628
|
+
|
|
629
|
+
{k + 1 for k in range(3)}
|
|
630
|
+
|
|
631
|
+
Arguments:
|
|
632
|
+
node -- AST node.
|
|
633
|
+
|
|
634
|
+
"""
|
|
635
|
+
self.parts.append("{")
|
|
636
|
+
self.parts.append(node.elt)
|
|
637
|
+
self.parts.append(" ")
|
|
638
|
+
for comprehension in node.generators:
|
|
639
|
+
self.parts.append(comprehension)
|
|
640
|
+
self.parts.append("}")
|
|
641
|
+
|
|
642
|
+
def visit_GeneratorExp(self, node: ast.GeneratorExp) -> None:
|
|
643
|
+
"""
|
|
644
|
+
Parse info from `ast.GeneratorExp` node and put it to `parts`.
|
|
645
|
+
|
|
646
|
+
Examples::
|
|
647
|
+
|
|
648
|
+
(k + 1 for k in range(3))
|
|
649
|
+
|
|
650
|
+
Arguments:
|
|
651
|
+
node -- AST node.
|
|
652
|
+
|
|
653
|
+
"""
|
|
654
|
+
self.parts.append("(")
|
|
655
|
+
self.parts.append(node.elt)
|
|
656
|
+
self.parts.append(" ")
|
|
657
|
+
for comprehension in node.generators:
|
|
658
|
+
self.parts.append(comprehension)
|
|
659
|
+
self.parts.append(")")
|
|
660
|
+
|
|
661
|
+
def visit_IfExp(self, node: ast.IfExp) -> None:
|
|
662
|
+
"""
|
|
663
|
+
Parse info from `ast.IfExp` node and put it to `parts`.
|
|
664
|
+
|
|
665
|
+
Examples::
|
|
666
|
+
|
|
667
|
+
5 if my_value else 6
|
|
668
|
+
|
|
669
|
+
Arguments:
|
|
670
|
+
node -- AST node.
|
|
671
|
+
|
|
672
|
+
"""
|
|
673
|
+
self.parts.append(node.body)
|
|
674
|
+
self.parts.append(" if ")
|
|
675
|
+
self.parts.append(node.test)
|
|
676
|
+
self.parts.append(" else ")
|
|
677
|
+
self.parts.append(node.orelse)
|
|
678
|
+
|
|
679
|
+
def visit_Await(self, node: ast.Await) -> None:
|
|
680
|
+
"""
|
|
681
|
+
Parse info from `ast.Await` node and put it to `parts`.
|
|
682
|
+
|
|
683
|
+
Examples::
|
|
684
|
+
|
|
685
|
+
await result
|
|
686
|
+
|
|
687
|
+
Arguments:
|
|
688
|
+
node -- AST node.
|
|
689
|
+
|
|
690
|
+
"""
|
|
691
|
+
self.parts.append("await ")
|
|
692
|
+
self.parts.append(node.value)
|
|
693
|
+
|
|
694
|
+
def visit_Yield(self, node: ast.Yield) -> None:
|
|
695
|
+
"""
|
|
696
|
+
Parse info from `ast.Yield` node and put it to `parts`.
|
|
697
|
+
|
|
698
|
+
Examples::
|
|
699
|
+
|
|
700
|
+
Yield:
|
|
701
|
+
yield value
|
|
702
|
+
|
|
703
|
+
Arguments:
|
|
704
|
+
node -- AST node.
|
|
705
|
+
|
|
706
|
+
"""
|
|
707
|
+
self.parts.append("yield")
|
|
708
|
+
if node.value:
|
|
709
|
+
self.parts.append(" ")
|
|
710
|
+
self.parts.append(node.value)
|
|
711
|
+
|
|
712
|
+
def visit_YieldFrom(self, node: ast.YieldFrom) -> None:
|
|
713
|
+
"""
|
|
714
|
+
Parse info from `ast.YieldFrom` node and put it to `parts`.
|
|
715
|
+
|
|
716
|
+
Examples::
|
|
717
|
+
|
|
718
|
+
yield from my_generator
|
|
719
|
+
|
|
720
|
+
Arguments:
|
|
721
|
+
node -- AST node.
|
|
722
|
+
|
|
723
|
+
"""
|
|
724
|
+
self.parts.append("yield from ")
|
|
725
|
+
self.parts.append(node.value)
|
|
726
|
+
|
|
727
|
+
def generic_visit(self, node: ast.AST) -> None:
|
|
728
|
+
"""
|
|
729
|
+
Parse info from an unknown `ast.AST` node and put `...` to `parts`.
|
|
730
|
+
|
|
731
|
+
Logs warning with node class.
|
|
732
|
+
|
|
733
|
+
Arguments:
|
|
734
|
+
node -- AST node.
|
|
735
|
+
|
|
736
|
+
"""
|
|
737
|
+
self._logger.warning(
|
|
738
|
+
f"Could not render node {node.__class__.__name__}, replaced with `{self.UNKNOWN}`",
|
|
739
|
+
)
|
|
740
|
+
self.parts.append(self.UNKNOWN)
|