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
handsdown/__init__.py
ADDED
handsdown/__main__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""
|
|
2
|
+
# AST Parser.
|
|
3
|
+
|
|
4
|
+
Collection of tools for analyzing AST and also rendering it back to a valid Python code.
|
|
5
|
+
|
|
6
|
+
## Usage
|
|
7
|
+
|
|
8
|
+
Use `handsdown.ast_parser.node_records.ModuleRecord` to parse the source code.
|
|
9
|
+
|
|
10
|
+
### Examples
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
from handsdown.utils.import_string import ImportString
|
|
16
|
+
from handsdown.ast_parser.node_records import ModuleRecord
|
|
17
|
+
|
|
18
|
+
source_path = Path("my_module.py")
|
|
19
|
+
import_string = ImportString("my_module")
|
|
20
|
+
module_record = ModuleRecord.create_from_source(source_path, import_string)
|
|
21
|
+
module_record.build_children() # generate records for imports, classes, attributes
|
|
22
|
+
and function in module
|
|
23
|
+
|
|
24
|
+
function_record = module_record.function_records[0] # get the first function in module
|
|
25
|
+
print(function_record.render(allow_multiline=True)) # print function definition
|
|
26
|
+
print(function_record.return_type_hint.render()) # print function return type annotation
|
|
27
|
+
```
|
|
28
|
+
"""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""AST Analyzers."""
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Base AST analyzer."""
|
|
2
|
+
|
|
3
|
+
import handsdown.ast_parser.smart_ast as ast
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseAnalyzer(ast.NodeVisitor):
|
|
7
|
+
"""
|
|
8
|
+
Base AST analyzer.
|
|
9
|
+
|
|
10
|
+
Has lists for all objects for different analyzers.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
self.related_names: list[str] = []
|
|
15
|
+
|
|
16
|
+
def get_docstring(self, node: ast.AST) -> str:
|
|
17
|
+
"""
|
|
18
|
+
Get docstring from node.
|
|
19
|
+
|
|
20
|
+
Arguments:
|
|
21
|
+
node -- AST node.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Docstring.
|
|
25
|
+
|
|
26
|
+
"""
|
|
27
|
+
if isinstance(node, (ast.AsyncFunctionDef, ast.FunctionDef, ast.ClassDef, ast.Module)):
|
|
28
|
+
return ast.get_docstring(node, clean=False) or ""
|
|
29
|
+
return ""
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""AST analyzer for `ast.ClassDef` records."""
|
|
2
|
+
from typing import Union
|
|
3
|
+
|
|
4
|
+
import handsdown.ast_parser.smart_ast as ast
|
|
5
|
+
from handsdown.ast_parser.analyzers.base_analyzer import BaseAnalyzer
|
|
6
|
+
from handsdown.ast_parser.type_defs import ASTFunctionDef
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ClassAnalyzer(BaseAnalyzer):
|
|
10
|
+
"""AST analyzer for `ast.ClassDef` records."""
|
|
11
|
+
|
|
12
|
+
def __init__(self) -> None:
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.base_nodes: list[ast.expr] = []
|
|
15
|
+
self.decorator_nodes: list[ast.expr] = []
|
|
16
|
+
self.method_nodes: list[ASTFunctionDef] = []
|
|
17
|
+
self.attribute_nodes: list[Union[ast.Assign, ast.AnnAssign]] = []
|
|
18
|
+
|
|
19
|
+
def visit_ClassDef(self, node: ast.ClassDef) -> None:
|
|
20
|
+
"""
|
|
21
|
+
Entrypoint for the analyzer.
|
|
22
|
+
|
|
23
|
+
Adds new `ast.expr` entry to `decorator_nodes` for each node
|
|
24
|
+
from `node.decorator_list`.
|
|
25
|
+
Adds new `ast.expr` entry to `base_nodes` for each node
|
|
26
|
+
from `node.bases`.
|
|
27
|
+
Visits each node from `node.body` list to parse methods.
|
|
28
|
+
|
|
29
|
+
Examples::
|
|
30
|
+
|
|
31
|
+
def my_func():
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
Arguments:
|
|
35
|
+
node -- AST node.
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
for decorator_node in node.decorator_list:
|
|
39
|
+
self.decorator_nodes.append(decorator_node)
|
|
40
|
+
for base_node in node.bases:
|
|
41
|
+
self.base_nodes.append(base_node)
|
|
42
|
+
for element in node.body:
|
|
43
|
+
self.visit(element)
|
|
44
|
+
|
|
45
|
+
def _visit_FunctionDef(self, node: ASTFunctionDef) -> None:
|
|
46
|
+
name = node.name
|
|
47
|
+
|
|
48
|
+
docstring = self.get_docstring(node)
|
|
49
|
+
|
|
50
|
+
# skip private methods with no docstrings
|
|
51
|
+
if name.startswith("_") and not name.startswith("__") and not docstring:
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
# skip magic methods with no docstrings
|
|
55
|
+
if name.startswith("__") and name != "__init__" and not docstring:
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
self.method_nodes.append(node)
|
|
59
|
+
|
|
60
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Parse info about class method statements.
|
|
63
|
+
|
|
64
|
+
Adds new `FunctionRecord` entry to `method_records`.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
```python
|
|
68
|
+
class MyClass:
|
|
69
|
+
def my_method(self, arg):
|
|
70
|
+
return arg
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Arguments:
|
|
74
|
+
node -- AST node.
|
|
75
|
+
|
|
76
|
+
"""
|
|
77
|
+
self._visit_FunctionDef(node)
|
|
78
|
+
|
|
79
|
+
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> None:
|
|
80
|
+
"""
|
|
81
|
+
Parse info about class asynchronous method statements.
|
|
82
|
+
|
|
83
|
+
Adds new `FunctionRecord` entry to `method_records`.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
```python
|
|
87
|
+
class MyClass:
|
|
88
|
+
async def my_method(self, arg):
|
|
89
|
+
return await arg
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Arguments:
|
|
93
|
+
node -- AST node.
|
|
94
|
+
|
|
95
|
+
"""
|
|
96
|
+
self._visit_FunctionDef(node)
|
|
97
|
+
|
|
98
|
+
def visit_Assign(self, node: ast.Assign) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Parse info about class attribute statements.
|
|
101
|
+
|
|
102
|
+
Adds new `ast.Assign` entry to `attribute_nodes`.
|
|
103
|
+
Skips assignments to anything pther that a new variable.
|
|
104
|
+
Skips multiple assignments.
|
|
105
|
+
Skips assignments with names starting with `_`.
|
|
106
|
+
|
|
107
|
+
Examples:
|
|
108
|
+
```python
|
|
109
|
+
class MyClass:
|
|
110
|
+
MY_MODULE_ATTR = "value"
|
|
111
|
+
my_attr = "value"
|
|
112
|
+
|
|
113
|
+
# these entries are skipped
|
|
114
|
+
_MY_MODULE_ATTR = "value"
|
|
115
|
+
multi_attr_1, multi_attr_2 = [1, 2]
|
|
116
|
+
my_object.name = "value"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Arguments:
|
|
120
|
+
node -- AST node.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
# skip multiple assignments
|
|
124
|
+
if len(node.targets) != 1:
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
# skip complex assignments
|
|
128
|
+
if not isinstance(node.targets[0], ast.Name):
|
|
129
|
+
return
|
|
130
|
+
|
|
131
|
+
name = node.targets[0].id
|
|
132
|
+
|
|
133
|
+
# skip private attributes
|
|
134
|
+
if name.startswith("_"):
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
self.attribute_nodes.append(node)
|
|
138
|
+
|
|
139
|
+
def visit_AnnAssign(self, node: ast.AnnAssign) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Parse info about class annotated attribute statements.
|
|
142
|
+
|
|
143
|
+
Adds new `ast.AnnAssign` entry to `attribute_nodes`.
|
|
144
|
+
Skips assignments with names starting with `_`.
|
|
145
|
+
|
|
146
|
+
Examples:
|
|
147
|
+
```python
|
|
148
|
+
class MyClass:
|
|
149
|
+
my_attr: int
|
|
150
|
+
my_value: int = 5
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Arguments:
|
|
154
|
+
node -- AST node.
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
# skip complex assignments
|
|
158
|
+
if not isinstance(node.target, ast.Name):
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
name = node.target.id
|
|
162
|
+
|
|
163
|
+
# skip private attributes
|
|
164
|
+
if name.startswith("_"):
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
self.attribute_nodes.append(node)
|
|
168
|
+
|
|
169
|
+
def generic_visit(self, node: ast.AST) -> None:
|
|
170
|
+
"""
|
|
171
|
+
Do nothing for unknown `ast.AST` nodes.
|
|
172
|
+
|
|
173
|
+
Arguments:
|
|
174
|
+
node -- AST node.
|
|
175
|
+
|
|
176
|
+
"""
|