-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.py
78 lines (65 loc) · 3.55 KB
/
script.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import ast
import re
def format_docstring(docstring):
"""Formats Google-style docstrings for better Markdown output."""
if not docstring:
return ""
# Add bold headers for Args and Returns
docstring = re.sub(r"(Args|Parameters):", r"**\1:**", docstring)
docstring = re.sub(r"(Returns|Return):", r"**\1:**", docstring)
docstring = re.sub(r"(Raises|Rise):", r"**\1:**", docstring)
# Convert parameter list into Markdown bullets
docstring = re.sub(r"(\n\s{4}(\w+)\s*\(([^)]+)\):)", r"\n- **\2** (*\3*):", docstring)
docstring = re.sub(r"(\n\s{4}(\w+):)", r"\n- **\2**:", docstring)
return docstring.strip()
def extract_python_docstrings(code):
"""Parses Python code and extracts docstrings in a structured Markdown format."""
tree = ast.parse(code)
markdown_output = []
# Extract module-level docstring
module_docstring = ast.get_docstring(tree)
if module_docstring:
markdown_output.append(f"# 📖 {module_docstring}\n")
# Extract imports
imports = [name.name for node in tree.body if isinstance(node, ast.Import) for name in node.names]
import_froms = [f"{node.module}.{name.name}" if node.module else name.name for node in tree.body if isinstance(node, ast.ImportFrom) for name in node.names]
all_imports = sorted(set(imports + import_froms))
module_dict = {}
for imp in all_imports:
parts = imp.split(".")
if len(parts) > 1:
parent, submodule = parts[0], ".".join(parts[1:])
module_dict.setdefault(parent, []).append(submodule)
else:
module_dict[imp] = []
if module_dict:
markdown_output.append("## 📦 Imported Modules\n")
for module, submodules in sorted(module_dict.items()):
markdown_output.append(f"- **{module}**")
for sub in sorted(submodules):
markdown_output.append(f" - {sub}")
markdown_output.append("\n")
# Extract class and function docstrings
for node in tree.body:
if isinstance(node, ast.ClassDef):
class_docstring = format_docstring(ast.get_docstring(node))
markdown_output.append(f"## 🏷️ Class `{node.name}`\n")
if class_docstring:
markdown_output.append(f"{class_docstring}\n")
# Extract methods inside the class
for subnode in node.body:
if isinstance(subnode, (ast.FunctionDef, ast.AsyncFunctionDef)):
method_docstring = format_docstring(ast.get_docstring(subnode))
if method_docstring:
method_type = "🔹 Async Method" if isinstance(subnode, ast.AsyncFunctionDef) else "🔹 Method"
markdown_output.append(f"### {method_type} `{subnode.name}()`\n{method_docstring}\n")
elif isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
function_docstring = format_docstring(ast.get_docstring(node))
if function_docstring:
function_type = "🔹 Async Function" if isinstance(node, ast.AsyncFunctionDef) else "🔹 Function"
markdown_output.append(f"## {function_type} `{node.name}()`\n{function_docstring}\n")
# Add project reference footer
markdown_output.append("\n---\n")
markdown_output.append("🚀 *This Markdown was generated by [SPIKEPyDocstringsToMarkdown](https://lonlof.github.io/SPIKEPyDocstringsToMarkdown/).* \n")
markdown_output.append("🔗 *View the project on [GitHub](https://github.com/LonLoF/SPIKEPyDocstringsToMarkdown/).*")
return "\n".join(markdown_output)