truthound-dashboard 1.3.1__py3-none-any.whl → 1.4.1__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.
- truthound_dashboard/api/alerts.py +258 -0
- truthound_dashboard/api/anomaly.py +1302 -0
- truthound_dashboard/api/cross_alerts.py +352 -0
- truthound_dashboard/api/deps.py +143 -0
- truthound_dashboard/api/drift_monitor.py +540 -0
- truthound_dashboard/api/lineage.py +1151 -0
- truthound_dashboard/api/maintenance.py +363 -0
- truthound_dashboard/api/middleware.py +373 -1
- truthound_dashboard/api/model_monitoring.py +805 -0
- truthound_dashboard/api/notifications_advanced.py +2452 -0
- truthound_dashboard/api/plugins.py +2096 -0
- truthound_dashboard/api/profile.py +211 -14
- truthound_dashboard/api/reports.py +853 -0
- truthound_dashboard/api/router.py +147 -0
- truthound_dashboard/api/rule_suggestions.py +310 -0
- truthound_dashboard/api/schema_evolution.py +231 -0
- truthound_dashboard/api/sources.py +47 -3
- truthound_dashboard/api/triggers.py +190 -0
- truthound_dashboard/api/validations.py +13 -0
- truthound_dashboard/api/validators.py +333 -4
- truthound_dashboard/api/versioning.py +309 -0
- truthound_dashboard/api/websocket.py +301 -0
- truthound_dashboard/core/__init__.py +27 -0
- truthound_dashboard/core/anomaly.py +1395 -0
- truthound_dashboard/core/anomaly_explainer.py +633 -0
- truthound_dashboard/core/cache.py +206 -0
- truthound_dashboard/core/cached_services.py +422 -0
- truthound_dashboard/core/charts.py +352 -0
- truthound_dashboard/core/connections.py +1069 -42
- truthound_dashboard/core/cross_alerts.py +837 -0
- truthound_dashboard/core/drift_monitor.py +1477 -0
- truthound_dashboard/core/drift_sampling.py +669 -0
- truthound_dashboard/core/i18n/__init__.py +42 -0
- truthound_dashboard/core/i18n/detector.py +173 -0
- truthound_dashboard/core/i18n/messages.py +564 -0
- truthound_dashboard/core/lineage.py +971 -0
- truthound_dashboard/core/maintenance.py +443 -5
- truthound_dashboard/core/model_monitoring.py +1043 -0
- truthound_dashboard/core/notifications/channels.py +1020 -1
- truthound_dashboard/core/notifications/deduplication/__init__.py +143 -0
- truthound_dashboard/core/notifications/deduplication/policies.py +274 -0
- truthound_dashboard/core/notifications/deduplication/service.py +400 -0
- truthound_dashboard/core/notifications/deduplication/stores.py +2365 -0
- truthound_dashboard/core/notifications/deduplication/strategies.py +422 -0
- truthound_dashboard/core/notifications/dispatcher.py +43 -0
- truthound_dashboard/core/notifications/escalation/__init__.py +149 -0
- truthound_dashboard/core/notifications/escalation/backends.py +1384 -0
- truthound_dashboard/core/notifications/escalation/engine.py +429 -0
- truthound_dashboard/core/notifications/escalation/models.py +336 -0
- truthound_dashboard/core/notifications/escalation/scheduler.py +1187 -0
- truthound_dashboard/core/notifications/escalation/state_machine.py +330 -0
- truthound_dashboard/core/notifications/escalation/stores.py +2896 -0
- truthound_dashboard/core/notifications/events.py +49 -0
- truthound_dashboard/core/notifications/metrics/__init__.py +115 -0
- truthound_dashboard/core/notifications/metrics/base.py +528 -0
- truthound_dashboard/core/notifications/metrics/collectors.py +583 -0
- truthound_dashboard/core/notifications/routing/__init__.py +169 -0
- truthound_dashboard/core/notifications/routing/combinators.py +184 -0
- truthound_dashboard/core/notifications/routing/config.py +375 -0
- truthound_dashboard/core/notifications/routing/config_parser.py +867 -0
- truthound_dashboard/core/notifications/routing/engine.py +382 -0
- truthound_dashboard/core/notifications/routing/expression_engine.py +1269 -0
- truthound_dashboard/core/notifications/routing/jinja2_engine.py +774 -0
- truthound_dashboard/core/notifications/routing/rules.py +625 -0
- truthound_dashboard/core/notifications/routing/validator.py +678 -0
- truthound_dashboard/core/notifications/service.py +2 -0
- truthound_dashboard/core/notifications/stats_aggregator.py +850 -0
- truthound_dashboard/core/notifications/throttling/__init__.py +83 -0
- truthound_dashboard/core/notifications/throttling/builder.py +311 -0
- truthound_dashboard/core/notifications/throttling/stores.py +1859 -0
- truthound_dashboard/core/notifications/throttling/throttlers.py +633 -0
- truthound_dashboard/core/openlineage.py +1028 -0
- truthound_dashboard/core/plugins/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/__init__.py +39 -0
- truthound_dashboard/core/plugins/docs/extractor.py +703 -0
- truthound_dashboard/core/plugins/docs/renderers.py +804 -0
- truthound_dashboard/core/plugins/hooks/__init__.py +63 -0
- truthound_dashboard/core/plugins/hooks/decorators.py +367 -0
- truthound_dashboard/core/plugins/hooks/manager.py +403 -0
- truthound_dashboard/core/plugins/hooks/protocols.py +265 -0
- truthound_dashboard/core/plugins/lifecycle/__init__.py +41 -0
- truthound_dashboard/core/plugins/lifecycle/hot_reload.py +584 -0
- truthound_dashboard/core/plugins/lifecycle/machine.py +419 -0
- truthound_dashboard/core/plugins/lifecycle/states.py +266 -0
- truthound_dashboard/core/plugins/loader.py +504 -0
- truthound_dashboard/core/plugins/registry.py +810 -0
- truthound_dashboard/core/plugins/reporter_executor.py +588 -0
- truthound_dashboard/core/plugins/sandbox/__init__.py +59 -0
- truthound_dashboard/core/plugins/sandbox/code_validator.py +243 -0
- truthound_dashboard/core/plugins/sandbox/engines.py +770 -0
- truthound_dashboard/core/plugins/sandbox/protocols.py +194 -0
- truthound_dashboard/core/plugins/sandbox.py +617 -0
- truthound_dashboard/core/plugins/security/__init__.py +68 -0
- truthound_dashboard/core/plugins/security/analyzer.py +535 -0
- truthound_dashboard/core/plugins/security/policies.py +311 -0
- truthound_dashboard/core/plugins/security/protocols.py +296 -0
- truthound_dashboard/core/plugins/security/signing.py +842 -0
- truthound_dashboard/core/plugins/security.py +446 -0
- truthound_dashboard/core/plugins/validator_executor.py +401 -0
- truthound_dashboard/core/plugins/versioning/__init__.py +51 -0
- truthound_dashboard/core/plugins/versioning/constraints.py +377 -0
- truthound_dashboard/core/plugins/versioning/dependencies.py +541 -0
- truthound_dashboard/core/plugins/versioning/semver.py +266 -0
- truthound_dashboard/core/profile_comparison.py +601 -0
- truthound_dashboard/core/report_history.py +570 -0
- truthound_dashboard/core/reporters/__init__.py +57 -0
- truthound_dashboard/core/reporters/base.py +296 -0
- truthound_dashboard/core/reporters/csv_reporter.py +155 -0
- truthound_dashboard/core/reporters/html_reporter.py +598 -0
- truthound_dashboard/core/reporters/i18n/__init__.py +65 -0
- truthound_dashboard/core/reporters/i18n/base.py +494 -0
- truthound_dashboard/core/reporters/i18n/catalogs.py +930 -0
- truthound_dashboard/core/reporters/json_reporter.py +160 -0
- truthound_dashboard/core/reporters/junit_reporter.py +233 -0
- truthound_dashboard/core/reporters/markdown_reporter.py +207 -0
- truthound_dashboard/core/reporters/pdf_reporter.py +209 -0
- truthound_dashboard/core/reporters/registry.py +272 -0
- truthound_dashboard/core/rule_generator.py +2088 -0
- truthound_dashboard/core/scheduler.py +822 -12
- truthound_dashboard/core/schema_evolution.py +858 -0
- truthound_dashboard/core/services.py +152 -9
- truthound_dashboard/core/statistics.py +718 -0
- truthound_dashboard/core/streaming_anomaly.py +883 -0
- truthound_dashboard/core/triggers/__init__.py +45 -0
- truthound_dashboard/core/triggers/base.py +226 -0
- truthound_dashboard/core/triggers/evaluators.py +609 -0
- truthound_dashboard/core/triggers/factory.py +363 -0
- truthound_dashboard/core/unified_alerts.py +870 -0
- truthound_dashboard/core/validation_limits.py +509 -0
- truthound_dashboard/core/versioning.py +709 -0
- truthound_dashboard/core/websocket/__init__.py +59 -0
- truthound_dashboard/core/websocket/manager.py +512 -0
- truthound_dashboard/core/websocket/messages.py +130 -0
- truthound_dashboard/db/__init__.py +30 -0
- truthound_dashboard/db/models.py +3375 -3
- truthound_dashboard/main.py +22 -0
- truthound_dashboard/schemas/__init__.py +396 -1
- truthound_dashboard/schemas/anomaly.py +1258 -0
- truthound_dashboard/schemas/base.py +4 -0
- truthound_dashboard/schemas/cross_alerts.py +334 -0
- truthound_dashboard/schemas/drift_monitor.py +890 -0
- truthound_dashboard/schemas/lineage.py +428 -0
- truthound_dashboard/schemas/maintenance.py +154 -0
- truthound_dashboard/schemas/model_monitoring.py +374 -0
- truthound_dashboard/schemas/notifications_advanced.py +1363 -0
- truthound_dashboard/schemas/openlineage.py +704 -0
- truthound_dashboard/schemas/plugins.py +1293 -0
- truthound_dashboard/schemas/profile.py +420 -34
- truthound_dashboard/schemas/profile_comparison.py +242 -0
- truthound_dashboard/schemas/reports.py +285 -0
- truthound_dashboard/schemas/rule_suggestion.py +434 -0
- truthound_dashboard/schemas/schema_evolution.py +164 -0
- truthound_dashboard/schemas/source.py +117 -2
- truthound_dashboard/schemas/triggers.py +511 -0
- truthound_dashboard/schemas/unified_alerts.py +223 -0
- truthound_dashboard/schemas/validation.py +25 -1
- truthound_dashboard/schemas/validators/__init__.py +11 -0
- truthound_dashboard/schemas/validators/base.py +151 -0
- truthound_dashboard/schemas/versioning.py +152 -0
- truthound_dashboard/static/index.html +2 -2
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/METADATA +147 -23
- truthound_dashboard-1.4.1.dist-info/RECORD +239 -0
- truthound_dashboard/static/assets/index-BZG20KuF.js +0 -586
- truthound_dashboard/static/assets/index-D_HyZ3pb.css +0 -1
- truthound_dashboard/static/assets/unmerged_dictionaries-CtpqQBm0.js +0 -1
- truthound_dashboard-1.3.1.dist-info/RECORD +0 -110
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/WHEEL +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/entry_points.txt +0 -0
- {truthound_dashboard-1.3.1.dist-info → truthound_dashboard-1.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
"""Documentation Renderers.
|
|
2
|
+
|
|
3
|
+
This module provides renderers for converting extracted documentation
|
|
4
|
+
into various output formats (Markdown, HTML, JSON).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import html
|
|
10
|
+
import json
|
|
11
|
+
import logging
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
from .extractor import (
|
|
17
|
+
ModuleDoc,
|
|
18
|
+
ClassDoc,
|
|
19
|
+
FunctionDoc,
|
|
20
|
+
ParameterDoc,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class RenderOptions:
|
|
28
|
+
"""Options for documentation rendering.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
include_private: Include private members (starting with _).
|
|
32
|
+
include_source: Include source code snippets.
|
|
33
|
+
include_examples: Include usage examples.
|
|
34
|
+
include_deprecation: Include deprecation notices.
|
|
35
|
+
max_depth: Maximum nesting depth for classes/methods.
|
|
36
|
+
toc: Generate table of contents.
|
|
37
|
+
syntax_highlight: Enable syntax highlighting (HTML).
|
|
38
|
+
css_class_prefix: CSS class prefix for HTML output.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
include_private: bool = False
|
|
42
|
+
include_source: bool = True
|
|
43
|
+
include_examples: bool = True
|
|
44
|
+
include_deprecation: bool = True
|
|
45
|
+
max_depth: int = 3
|
|
46
|
+
toc: bool = True
|
|
47
|
+
syntax_highlight: bool = True
|
|
48
|
+
css_class_prefix: str = "plugin-doc"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class DocumentationRenderer(ABC):
|
|
52
|
+
"""Abstract base class for documentation renderers."""
|
|
53
|
+
|
|
54
|
+
def __init__(self, options: RenderOptions | None = None) -> None:
|
|
55
|
+
"""Initialize the renderer.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
options: Rendering options.
|
|
59
|
+
"""
|
|
60
|
+
self.options = options or RenderOptions()
|
|
61
|
+
|
|
62
|
+
@abstractmethod
|
|
63
|
+
def render_module(self, doc: ModuleDoc) -> str:
|
|
64
|
+
"""Render module documentation.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
doc: Module documentation.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
Rendered documentation string.
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def render_class(self, doc: ClassDoc, depth: int = 0) -> str:
|
|
76
|
+
"""Render class documentation.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
doc: Class documentation.
|
|
80
|
+
depth: Current nesting depth.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Rendered documentation string.
|
|
84
|
+
"""
|
|
85
|
+
pass
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
def render_function(self, doc: FunctionDoc, depth: int = 0) -> str:
|
|
89
|
+
"""Render function documentation.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
doc: Function documentation.
|
|
93
|
+
depth: Current nesting depth.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Rendered documentation string.
|
|
97
|
+
"""
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def _should_include(self, name: str) -> bool:
|
|
101
|
+
"""Check if a member should be included.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
name: Member name.
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
True if should be included.
|
|
108
|
+
"""
|
|
109
|
+
if name.startswith("__") and name.endswith("__"):
|
|
110
|
+
# Always include dunder methods
|
|
111
|
+
return True
|
|
112
|
+
if name.startswith("_"):
|
|
113
|
+
return self.options.include_private
|
|
114
|
+
return True
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class MarkdownRenderer(DocumentationRenderer):
|
|
118
|
+
"""Renders documentation as Markdown."""
|
|
119
|
+
|
|
120
|
+
def render_module(self, doc: ModuleDoc) -> str:
|
|
121
|
+
"""Render module documentation as Markdown.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
doc: Module documentation.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
Markdown string.
|
|
128
|
+
"""
|
|
129
|
+
lines: list[str] = []
|
|
130
|
+
|
|
131
|
+
# Module header
|
|
132
|
+
lines.append(f"# {doc.name}")
|
|
133
|
+
lines.append("")
|
|
134
|
+
|
|
135
|
+
if doc.description:
|
|
136
|
+
lines.append(doc.description)
|
|
137
|
+
lines.append("")
|
|
138
|
+
|
|
139
|
+
# Table of contents
|
|
140
|
+
if self.options.toc and (doc.classes or doc.functions):
|
|
141
|
+
lines.append("## Table of Contents")
|
|
142
|
+
lines.append("")
|
|
143
|
+
|
|
144
|
+
if doc.classes:
|
|
145
|
+
lines.append("### Classes")
|
|
146
|
+
lines.append("")
|
|
147
|
+
for cls in doc.classes:
|
|
148
|
+
if self._should_include(cls.name):
|
|
149
|
+
lines.append(f"- [{cls.name}](#{cls.name.lower()})")
|
|
150
|
+
lines.append("")
|
|
151
|
+
|
|
152
|
+
if doc.functions:
|
|
153
|
+
lines.append("### Functions")
|
|
154
|
+
lines.append("")
|
|
155
|
+
for func in doc.functions:
|
|
156
|
+
if self._should_include(func.name):
|
|
157
|
+
lines.append(f"- [{func.name}](#{func.name.lower()})")
|
|
158
|
+
lines.append("")
|
|
159
|
+
|
|
160
|
+
# Classes
|
|
161
|
+
if doc.classes:
|
|
162
|
+
lines.append("## Classes")
|
|
163
|
+
lines.append("")
|
|
164
|
+
for cls in doc.classes:
|
|
165
|
+
if self._should_include(cls.name):
|
|
166
|
+
lines.append(self.render_class(cls, depth=0))
|
|
167
|
+
lines.append("")
|
|
168
|
+
|
|
169
|
+
# Functions
|
|
170
|
+
if doc.functions:
|
|
171
|
+
lines.append("## Functions")
|
|
172
|
+
lines.append("")
|
|
173
|
+
for func in doc.functions:
|
|
174
|
+
if self._should_include(func.name):
|
|
175
|
+
lines.append(self.render_function(func, depth=0))
|
|
176
|
+
lines.append("")
|
|
177
|
+
|
|
178
|
+
return "\n".join(lines)
|
|
179
|
+
|
|
180
|
+
def render_class(self, doc: ClassDoc, depth: int = 0) -> str:
|
|
181
|
+
"""Render class documentation as Markdown.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
doc: Class documentation.
|
|
185
|
+
depth: Current nesting depth.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
Markdown string.
|
|
189
|
+
"""
|
|
190
|
+
if depth > self.options.max_depth:
|
|
191
|
+
return ""
|
|
192
|
+
|
|
193
|
+
lines: list[str] = []
|
|
194
|
+
header_level = "###" + "#" * depth
|
|
195
|
+
|
|
196
|
+
# Class header
|
|
197
|
+
lines.append(f"{header_level} {doc.name}")
|
|
198
|
+
lines.append("")
|
|
199
|
+
|
|
200
|
+
# Inheritance
|
|
201
|
+
if doc.bases:
|
|
202
|
+
bases_str = ", ".join(doc.bases)
|
|
203
|
+
lines.append(f"**Inherits from:** `{bases_str}`")
|
|
204
|
+
lines.append("")
|
|
205
|
+
|
|
206
|
+
# Description
|
|
207
|
+
if doc.description:
|
|
208
|
+
lines.append(doc.description)
|
|
209
|
+
lines.append("")
|
|
210
|
+
|
|
211
|
+
# Deprecation warning
|
|
212
|
+
if self.options.include_deprecation and doc.deprecated:
|
|
213
|
+
lines.append("> **Deprecated:** This class is deprecated.")
|
|
214
|
+
lines.append("")
|
|
215
|
+
|
|
216
|
+
# Constructor
|
|
217
|
+
if doc.init_params:
|
|
218
|
+
lines.append(f"{header_level}# Constructor")
|
|
219
|
+
lines.append("")
|
|
220
|
+
lines.append("**Parameters:**")
|
|
221
|
+
lines.append("")
|
|
222
|
+
for param in doc.init_params:
|
|
223
|
+
lines.append(self._render_parameter(param))
|
|
224
|
+
lines.append("")
|
|
225
|
+
|
|
226
|
+
# Attributes
|
|
227
|
+
if doc.attributes:
|
|
228
|
+
lines.append(f"{header_level}# Attributes")
|
|
229
|
+
lines.append("")
|
|
230
|
+
for attr_name, attr_info in doc.attributes.items():
|
|
231
|
+
if self._should_include(attr_name):
|
|
232
|
+
type_str = f": `{attr_info['type']}`" if attr_info.get("type") else ""
|
|
233
|
+
desc = attr_info.get("description", "")
|
|
234
|
+
lines.append(f"- **{attr_name}**{type_str} - {desc}")
|
|
235
|
+
lines.append("")
|
|
236
|
+
|
|
237
|
+
# Methods
|
|
238
|
+
if doc.methods:
|
|
239
|
+
lines.append(f"{header_level}# Methods")
|
|
240
|
+
lines.append("")
|
|
241
|
+
for method in doc.methods:
|
|
242
|
+
if self._should_include(method.name):
|
|
243
|
+
lines.append(self.render_function(method, depth=depth + 1))
|
|
244
|
+
lines.append("")
|
|
245
|
+
|
|
246
|
+
# Examples
|
|
247
|
+
if self.options.include_examples and doc.examples:
|
|
248
|
+
lines.append(f"{header_level}# Examples")
|
|
249
|
+
lines.append("")
|
|
250
|
+
for example in doc.examples:
|
|
251
|
+
lines.append("```python")
|
|
252
|
+
lines.append(example)
|
|
253
|
+
lines.append("```")
|
|
254
|
+
lines.append("")
|
|
255
|
+
|
|
256
|
+
return "\n".join(lines)
|
|
257
|
+
|
|
258
|
+
def render_function(self, doc: FunctionDoc, depth: int = 0) -> str:
|
|
259
|
+
"""Render function documentation as Markdown.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
doc: Function documentation.
|
|
263
|
+
depth: Current nesting depth.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Markdown string.
|
|
267
|
+
"""
|
|
268
|
+
if depth > self.options.max_depth:
|
|
269
|
+
return ""
|
|
270
|
+
|
|
271
|
+
lines: list[str] = []
|
|
272
|
+
header_level = "####" + "#" * depth
|
|
273
|
+
|
|
274
|
+
# Function signature
|
|
275
|
+
params_str = ", ".join(
|
|
276
|
+
f"{p.name}: {p.type}" if p.type else p.name
|
|
277
|
+
for p in doc.parameters
|
|
278
|
+
)
|
|
279
|
+
return_str = f" -> {doc.return_type}" if doc.return_type else ""
|
|
280
|
+
async_prefix = "async " if doc.is_async else ""
|
|
281
|
+
|
|
282
|
+
lines.append(f"{header_level} `{async_prefix}{doc.name}({params_str}){return_str}`")
|
|
283
|
+
lines.append("")
|
|
284
|
+
|
|
285
|
+
# Deprecation warning
|
|
286
|
+
if self.options.include_deprecation and doc.deprecated:
|
|
287
|
+
lines.append("> **Deprecated:** This function is deprecated.")
|
|
288
|
+
lines.append("")
|
|
289
|
+
|
|
290
|
+
# Description
|
|
291
|
+
if doc.description:
|
|
292
|
+
lines.append(doc.description)
|
|
293
|
+
lines.append("")
|
|
294
|
+
|
|
295
|
+
# Parameters
|
|
296
|
+
if doc.parameters:
|
|
297
|
+
lines.append("**Parameters:**")
|
|
298
|
+
lines.append("")
|
|
299
|
+
for param in doc.parameters:
|
|
300
|
+
lines.append(self._render_parameter(param))
|
|
301
|
+
lines.append("")
|
|
302
|
+
|
|
303
|
+
# Returns
|
|
304
|
+
if doc.return_type or doc.return_description:
|
|
305
|
+
lines.append("**Returns:**")
|
|
306
|
+
lines.append("")
|
|
307
|
+
return_type = f"`{doc.return_type}`" if doc.return_type else "Any"
|
|
308
|
+
return_desc = doc.return_description or ""
|
|
309
|
+
lines.append(f"- {return_type} - {return_desc}")
|
|
310
|
+
lines.append("")
|
|
311
|
+
|
|
312
|
+
# Raises
|
|
313
|
+
if doc.raises:
|
|
314
|
+
lines.append("**Raises:**")
|
|
315
|
+
lines.append("")
|
|
316
|
+
for exc_type, exc_desc in doc.raises.items():
|
|
317
|
+
lines.append(f"- `{exc_type}` - {exc_desc}")
|
|
318
|
+
lines.append("")
|
|
319
|
+
|
|
320
|
+
# Examples
|
|
321
|
+
if self.options.include_examples and doc.examples:
|
|
322
|
+
lines.append("**Examples:**")
|
|
323
|
+
lines.append("")
|
|
324
|
+
for example in doc.examples:
|
|
325
|
+
lines.append("```python")
|
|
326
|
+
lines.append(example)
|
|
327
|
+
lines.append("```")
|
|
328
|
+
lines.append("")
|
|
329
|
+
|
|
330
|
+
return "\n".join(lines)
|
|
331
|
+
|
|
332
|
+
def _render_parameter(self, param: ParameterDoc) -> str:
|
|
333
|
+
"""Render a parameter as Markdown list item.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
param: Parameter documentation.
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
Markdown list item.
|
|
340
|
+
"""
|
|
341
|
+
type_str = f": `{param.type}`" if param.type else ""
|
|
342
|
+
default_str = f" (default: `{param.default}`)" if param.default else ""
|
|
343
|
+
required_str = " **(required)**" if param.required and not param.default else ""
|
|
344
|
+
desc = param.description or ""
|
|
345
|
+
|
|
346
|
+
return f"- **{param.name}**{type_str}{required_str}{default_str} - {desc}"
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class HTMLRenderer(DocumentationRenderer):
|
|
350
|
+
"""Renders documentation as HTML."""
|
|
351
|
+
|
|
352
|
+
def render_module(self, doc: ModuleDoc) -> str:
|
|
353
|
+
"""Render module documentation as HTML.
|
|
354
|
+
|
|
355
|
+
Args:
|
|
356
|
+
doc: Module documentation.
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
HTML string.
|
|
360
|
+
"""
|
|
361
|
+
prefix = self.options.css_class_prefix
|
|
362
|
+
lines: list[str] = []
|
|
363
|
+
|
|
364
|
+
lines.append(f'<div class="{prefix}-module">')
|
|
365
|
+
|
|
366
|
+
# Module header
|
|
367
|
+
lines.append(f'<h1 class="{prefix}-module-title">{html.escape(doc.name)}</h1>')
|
|
368
|
+
|
|
369
|
+
if doc.description:
|
|
370
|
+
lines.append(f'<div class="{prefix}-description">{html.escape(doc.description)}</div>')
|
|
371
|
+
|
|
372
|
+
# Table of contents
|
|
373
|
+
if self.options.toc and (doc.classes or doc.functions):
|
|
374
|
+
lines.append(f'<nav class="{prefix}-toc">')
|
|
375
|
+
lines.append(f'<h2 class="{prefix}-toc-title">Table of Contents</h2>')
|
|
376
|
+
|
|
377
|
+
if doc.classes:
|
|
378
|
+
lines.append(f'<div class="{prefix}-toc-section">')
|
|
379
|
+
lines.append("<h3>Classes</h3>")
|
|
380
|
+
lines.append("<ul>")
|
|
381
|
+
for cls in doc.classes:
|
|
382
|
+
if self._should_include(cls.name):
|
|
383
|
+
anchor = cls.name.lower().replace("_", "-")
|
|
384
|
+
lines.append(f'<li><a href="#{anchor}">{html.escape(cls.name)}</a></li>')
|
|
385
|
+
lines.append("</ul>")
|
|
386
|
+
lines.append("</div>")
|
|
387
|
+
|
|
388
|
+
if doc.functions:
|
|
389
|
+
lines.append(f'<div class="{prefix}-toc-section">')
|
|
390
|
+
lines.append("<h3>Functions</h3>")
|
|
391
|
+
lines.append("<ul>")
|
|
392
|
+
for func in doc.functions:
|
|
393
|
+
if self._should_include(func.name):
|
|
394
|
+
anchor = func.name.lower().replace("_", "-")
|
|
395
|
+
lines.append(f'<li><a href="#{anchor}">{html.escape(func.name)}</a></li>')
|
|
396
|
+
lines.append("</ul>")
|
|
397
|
+
lines.append("</div>")
|
|
398
|
+
|
|
399
|
+
lines.append("</nav>")
|
|
400
|
+
|
|
401
|
+
# Classes
|
|
402
|
+
if doc.classes:
|
|
403
|
+
lines.append(f'<section class="{prefix}-classes">')
|
|
404
|
+
lines.append(f'<h2 class="{prefix}-section-title">Classes</h2>')
|
|
405
|
+
for cls in doc.classes:
|
|
406
|
+
if self._should_include(cls.name):
|
|
407
|
+
lines.append(self.render_class(cls, depth=0))
|
|
408
|
+
lines.append("</section>")
|
|
409
|
+
|
|
410
|
+
# Functions
|
|
411
|
+
if doc.functions:
|
|
412
|
+
lines.append(f'<section class="{prefix}-functions">')
|
|
413
|
+
lines.append(f'<h2 class="{prefix}-section-title">Functions</h2>')
|
|
414
|
+
for func in doc.functions:
|
|
415
|
+
if self._should_include(func.name):
|
|
416
|
+
lines.append(self.render_function(func, depth=0))
|
|
417
|
+
lines.append("</section>")
|
|
418
|
+
|
|
419
|
+
lines.append("</div>")
|
|
420
|
+
|
|
421
|
+
return "\n".join(lines)
|
|
422
|
+
|
|
423
|
+
def render_class(self, doc: ClassDoc, depth: int = 0) -> str:
|
|
424
|
+
"""Render class documentation as HTML.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
doc: Class documentation.
|
|
428
|
+
depth: Current nesting depth.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
HTML string.
|
|
432
|
+
"""
|
|
433
|
+
if depth > self.options.max_depth:
|
|
434
|
+
return ""
|
|
435
|
+
|
|
436
|
+
prefix = self.options.css_class_prefix
|
|
437
|
+
anchor = doc.name.lower().replace("_", "-")
|
|
438
|
+
lines: list[str] = []
|
|
439
|
+
|
|
440
|
+
lines.append(f'<article class="{prefix}-class" id="{anchor}">')
|
|
441
|
+
|
|
442
|
+
# Class header
|
|
443
|
+
header_tag = f"h{min(3 + depth, 6)}"
|
|
444
|
+
lines.append(f'<{header_tag} class="{prefix}-class-title">{html.escape(doc.name)}</{header_tag}>')
|
|
445
|
+
|
|
446
|
+
# Inheritance
|
|
447
|
+
if doc.bases:
|
|
448
|
+
bases_str = ", ".join(html.escape(b) for b in doc.bases)
|
|
449
|
+
lines.append(f'<div class="{prefix}-inheritance">Inherits from: <code>{bases_str}</code></div>')
|
|
450
|
+
|
|
451
|
+
# Deprecation warning
|
|
452
|
+
if self.options.include_deprecation and doc.deprecated:
|
|
453
|
+
lines.append(f'<div class="{prefix}-deprecated">Deprecated: This class is deprecated.</div>')
|
|
454
|
+
|
|
455
|
+
# Description
|
|
456
|
+
if doc.description:
|
|
457
|
+
lines.append(f'<div class="{prefix}-description">{html.escape(doc.description)}</div>')
|
|
458
|
+
|
|
459
|
+
# Constructor
|
|
460
|
+
if doc.init_params:
|
|
461
|
+
lines.append(f'<div class="{prefix}-constructor">')
|
|
462
|
+
lines.append("<h4>Constructor</h4>")
|
|
463
|
+
lines.append(self._render_parameters_html(doc.init_params))
|
|
464
|
+
lines.append("</div>")
|
|
465
|
+
|
|
466
|
+
# Attributes
|
|
467
|
+
if doc.attributes:
|
|
468
|
+
lines.append(f'<div class="{prefix}-attributes">')
|
|
469
|
+
lines.append("<h4>Attributes</h4>")
|
|
470
|
+
lines.append("<dl>")
|
|
471
|
+
for attr_name, attr_info in doc.attributes.items():
|
|
472
|
+
if self._should_include(attr_name):
|
|
473
|
+
type_str = f": <code>{html.escape(attr_info.get('type', ''))}</code>" if attr_info.get("type") else ""
|
|
474
|
+
desc = html.escape(attr_info.get("description", ""))
|
|
475
|
+
lines.append(f"<dt><strong>{html.escape(attr_name)}</strong>{type_str}</dt>")
|
|
476
|
+
lines.append(f"<dd>{desc}</dd>")
|
|
477
|
+
lines.append("</dl>")
|
|
478
|
+
lines.append("</div>")
|
|
479
|
+
|
|
480
|
+
# Methods
|
|
481
|
+
if doc.methods:
|
|
482
|
+
lines.append(f'<div class="{prefix}-methods">')
|
|
483
|
+
lines.append("<h4>Methods</h4>")
|
|
484
|
+
for method in doc.methods:
|
|
485
|
+
if self._should_include(method.name):
|
|
486
|
+
lines.append(self.render_function(method, depth=depth + 1))
|
|
487
|
+
lines.append("</div>")
|
|
488
|
+
|
|
489
|
+
# Examples
|
|
490
|
+
if self.options.include_examples and doc.examples:
|
|
491
|
+
lines.append(f'<div class="{prefix}-examples">')
|
|
492
|
+
lines.append("<h4>Examples</h4>")
|
|
493
|
+
for example in doc.examples:
|
|
494
|
+
code_class = "language-python" if self.options.syntax_highlight else ""
|
|
495
|
+
lines.append(f'<pre><code class="{code_class}">{html.escape(example)}</code></pre>')
|
|
496
|
+
lines.append("</div>")
|
|
497
|
+
|
|
498
|
+
lines.append("</article>")
|
|
499
|
+
|
|
500
|
+
return "\n".join(lines)
|
|
501
|
+
|
|
502
|
+
def render_function(self, doc: FunctionDoc, depth: int = 0) -> str:
|
|
503
|
+
"""Render function documentation as HTML.
|
|
504
|
+
|
|
505
|
+
Args:
|
|
506
|
+
doc: Function documentation.
|
|
507
|
+
depth: Current nesting depth.
|
|
508
|
+
|
|
509
|
+
Returns:
|
|
510
|
+
HTML string.
|
|
511
|
+
"""
|
|
512
|
+
if depth > self.options.max_depth:
|
|
513
|
+
return ""
|
|
514
|
+
|
|
515
|
+
prefix = self.options.css_class_prefix
|
|
516
|
+
anchor = doc.name.lower().replace("_", "-")
|
|
517
|
+
lines: list[str] = []
|
|
518
|
+
|
|
519
|
+
lines.append(f'<div class="{prefix}-function" id="{anchor}">')
|
|
520
|
+
|
|
521
|
+
# Function signature
|
|
522
|
+
params_str = ", ".join(
|
|
523
|
+
f"{html.escape(p.name)}: {html.escape(p.type or '')}" if p.type else html.escape(p.name)
|
|
524
|
+
for p in doc.parameters
|
|
525
|
+
)
|
|
526
|
+
return_str = f" -> {html.escape(doc.return_type)}" if doc.return_type else ""
|
|
527
|
+
async_prefix = "async " if doc.is_async else ""
|
|
528
|
+
|
|
529
|
+
header_tag = f"h{min(4 + depth, 6)}"
|
|
530
|
+
lines.append(
|
|
531
|
+
f'<{header_tag} class="{prefix}-function-signature">'
|
|
532
|
+
f'<code>{async_prefix}{html.escape(doc.name)}({params_str}){return_str}</code>'
|
|
533
|
+
f'</{header_tag}>'
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
# Deprecation warning
|
|
537
|
+
if self.options.include_deprecation and doc.deprecated:
|
|
538
|
+
lines.append(f'<div class="{prefix}-deprecated">Deprecated: This function is deprecated.</div>')
|
|
539
|
+
|
|
540
|
+
# Description
|
|
541
|
+
if doc.description:
|
|
542
|
+
lines.append(f'<div class="{prefix}-description">{html.escape(doc.description)}</div>')
|
|
543
|
+
|
|
544
|
+
# Parameters
|
|
545
|
+
if doc.parameters:
|
|
546
|
+
lines.append(f'<div class="{prefix}-params">')
|
|
547
|
+
lines.append("<h5>Parameters</h5>")
|
|
548
|
+
lines.append(self._render_parameters_html(doc.parameters))
|
|
549
|
+
lines.append("</div>")
|
|
550
|
+
|
|
551
|
+
# Returns
|
|
552
|
+
if doc.return_type or doc.return_description:
|
|
553
|
+
lines.append(f'<div class="{prefix}-returns">')
|
|
554
|
+
lines.append("<h5>Returns</h5>")
|
|
555
|
+
return_type = html.escape(doc.return_type) if doc.return_type else "Any"
|
|
556
|
+
return_desc = html.escape(doc.return_description or "")
|
|
557
|
+
lines.append(f"<p><code>{return_type}</code> - {return_desc}</p>")
|
|
558
|
+
lines.append("</div>")
|
|
559
|
+
|
|
560
|
+
# Raises
|
|
561
|
+
if doc.raises:
|
|
562
|
+
lines.append(f'<div class="{prefix}-raises">')
|
|
563
|
+
lines.append("<h5>Raises</h5>")
|
|
564
|
+
lines.append("<dl>")
|
|
565
|
+
for exc_type, exc_desc in doc.raises.items():
|
|
566
|
+
lines.append(f"<dt><code>{html.escape(exc_type)}</code></dt>")
|
|
567
|
+
lines.append(f"<dd>{html.escape(exc_desc)}</dd>")
|
|
568
|
+
lines.append("</dl>")
|
|
569
|
+
lines.append("</div>")
|
|
570
|
+
|
|
571
|
+
# Examples
|
|
572
|
+
if self.options.include_examples and doc.examples:
|
|
573
|
+
lines.append(f'<div class="{prefix}-examples">')
|
|
574
|
+
lines.append("<h5>Examples</h5>")
|
|
575
|
+
for example in doc.examples:
|
|
576
|
+
code_class = "language-python" if self.options.syntax_highlight else ""
|
|
577
|
+
lines.append(f'<pre><code class="{code_class}">{html.escape(example)}</code></pre>')
|
|
578
|
+
lines.append("</div>")
|
|
579
|
+
|
|
580
|
+
lines.append("</div>")
|
|
581
|
+
|
|
582
|
+
return "\n".join(lines)
|
|
583
|
+
|
|
584
|
+
def _render_parameters_html(self, params: list[ParameterDoc]) -> str:
|
|
585
|
+
"""Render parameters as HTML definition list.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
params: List of parameters.
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
HTML string.
|
|
592
|
+
"""
|
|
593
|
+
lines: list[str] = ["<dl>"]
|
|
594
|
+
|
|
595
|
+
for param in params:
|
|
596
|
+
type_str = f": <code>{html.escape(param.type)}</code>" if param.type else ""
|
|
597
|
+
default_str = f" (default: <code>{html.escape(str(param.default))}</code>)" if param.default else ""
|
|
598
|
+
required_str = " <em>(required)</em>" if param.required and not param.default else ""
|
|
599
|
+
desc = html.escape(param.description or "")
|
|
600
|
+
|
|
601
|
+
lines.append(f"<dt><strong>{html.escape(param.name)}</strong>{type_str}{required_str}{default_str}</dt>")
|
|
602
|
+
lines.append(f"<dd>{desc}</dd>")
|
|
603
|
+
|
|
604
|
+
lines.append("</dl>")
|
|
605
|
+
return "\n".join(lines)
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
class JSONRenderer(DocumentationRenderer):
|
|
609
|
+
"""Renders documentation as JSON."""
|
|
610
|
+
|
|
611
|
+
def render_module(self, doc: ModuleDoc) -> str:
|
|
612
|
+
"""Render module documentation as JSON.
|
|
613
|
+
|
|
614
|
+
Args:
|
|
615
|
+
doc: Module documentation.
|
|
616
|
+
|
|
617
|
+
Returns:
|
|
618
|
+
JSON string.
|
|
619
|
+
"""
|
|
620
|
+
data = self._module_to_dict(doc)
|
|
621
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
622
|
+
|
|
623
|
+
def render_class(self, doc: ClassDoc, depth: int = 0) -> str:
|
|
624
|
+
"""Render class documentation as JSON.
|
|
625
|
+
|
|
626
|
+
Args:
|
|
627
|
+
doc: Class documentation.
|
|
628
|
+
depth: Current nesting depth.
|
|
629
|
+
|
|
630
|
+
Returns:
|
|
631
|
+
JSON string.
|
|
632
|
+
"""
|
|
633
|
+
data = self._class_to_dict(doc, depth)
|
|
634
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
635
|
+
|
|
636
|
+
def render_function(self, doc: FunctionDoc, depth: int = 0) -> str:
|
|
637
|
+
"""Render function documentation as JSON.
|
|
638
|
+
|
|
639
|
+
Args:
|
|
640
|
+
doc: Function documentation.
|
|
641
|
+
depth: Current nesting depth.
|
|
642
|
+
|
|
643
|
+
Returns:
|
|
644
|
+
JSON string.
|
|
645
|
+
"""
|
|
646
|
+
data = self._function_to_dict(doc)
|
|
647
|
+
return json.dumps(data, indent=2, ensure_ascii=False)
|
|
648
|
+
|
|
649
|
+
def _module_to_dict(self, doc: ModuleDoc) -> dict[str, Any]:
|
|
650
|
+
"""Convert module documentation to dictionary.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
doc: Module documentation.
|
|
654
|
+
|
|
655
|
+
Returns:
|
|
656
|
+
Dictionary representation.
|
|
657
|
+
"""
|
|
658
|
+
return {
|
|
659
|
+
"type": "module",
|
|
660
|
+
"name": doc.name,
|
|
661
|
+
"description": doc.description,
|
|
662
|
+
"file_path": doc.file_path,
|
|
663
|
+
"classes": [
|
|
664
|
+
self._class_to_dict(cls, 0)
|
|
665
|
+
for cls in doc.classes
|
|
666
|
+
if self._should_include(cls.name)
|
|
667
|
+
],
|
|
668
|
+
"functions": [
|
|
669
|
+
self._function_to_dict(func)
|
|
670
|
+
for func in doc.functions
|
|
671
|
+
if self._should_include(func.name)
|
|
672
|
+
],
|
|
673
|
+
"constants": doc.constants,
|
|
674
|
+
"metadata": doc.metadata,
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
def _class_to_dict(self, doc: ClassDoc, depth: int) -> dict[str, Any]:
|
|
678
|
+
"""Convert class documentation to dictionary.
|
|
679
|
+
|
|
680
|
+
Args:
|
|
681
|
+
doc: Class documentation.
|
|
682
|
+
depth: Current nesting depth.
|
|
683
|
+
|
|
684
|
+
Returns:
|
|
685
|
+
Dictionary representation.
|
|
686
|
+
"""
|
|
687
|
+
methods = []
|
|
688
|
+
if depth < self.options.max_depth:
|
|
689
|
+
methods = [
|
|
690
|
+
self._function_to_dict(method)
|
|
691
|
+
for method in doc.methods
|
|
692
|
+
if self._should_include(method.name)
|
|
693
|
+
]
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
"type": "class",
|
|
697
|
+
"name": doc.name,
|
|
698
|
+
"description": doc.description,
|
|
699
|
+
"bases": doc.bases,
|
|
700
|
+
"deprecated": doc.deprecated,
|
|
701
|
+
"init_params": [self._param_to_dict(p) for p in doc.init_params],
|
|
702
|
+
"attributes": doc.attributes,
|
|
703
|
+
"methods": methods,
|
|
704
|
+
"examples": doc.examples if self.options.include_examples else [],
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
def _function_to_dict(self, doc: FunctionDoc) -> dict[str, Any]:
|
|
708
|
+
"""Convert function documentation to dictionary.
|
|
709
|
+
|
|
710
|
+
Args:
|
|
711
|
+
doc: Function documentation.
|
|
712
|
+
|
|
713
|
+
Returns:
|
|
714
|
+
Dictionary representation.
|
|
715
|
+
"""
|
|
716
|
+
return {
|
|
717
|
+
"type": "function",
|
|
718
|
+
"name": doc.name,
|
|
719
|
+
"description": doc.description,
|
|
720
|
+
"parameters": [self._param_to_dict(p) for p in doc.parameters],
|
|
721
|
+
"return_type": doc.return_type,
|
|
722
|
+
"return_description": doc.return_description,
|
|
723
|
+
"raises": doc.raises,
|
|
724
|
+
"is_async": doc.is_async,
|
|
725
|
+
"is_generator": doc.is_generator,
|
|
726
|
+
"is_classmethod": doc.is_classmethod,
|
|
727
|
+
"is_staticmethod": doc.is_staticmethod,
|
|
728
|
+
"deprecated": doc.deprecated,
|
|
729
|
+
"examples": doc.examples if self.options.include_examples else [],
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
def _param_to_dict(self, param: ParameterDoc) -> dict[str, Any]:
|
|
733
|
+
"""Convert parameter documentation to dictionary.
|
|
734
|
+
|
|
735
|
+
Args:
|
|
736
|
+
param: Parameter documentation.
|
|
737
|
+
|
|
738
|
+
Returns:
|
|
739
|
+
Dictionary representation.
|
|
740
|
+
"""
|
|
741
|
+
return {
|
|
742
|
+
"name": param.name,
|
|
743
|
+
"type": param.type,
|
|
744
|
+
"description": param.description,
|
|
745
|
+
"default": param.default,
|
|
746
|
+
"required": param.required,
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
def render_documentation(
|
|
751
|
+
doc: ModuleDoc | ClassDoc | FunctionDoc,
|
|
752
|
+
format: str = "markdown",
|
|
753
|
+
options: RenderOptions | None = None,
|
|
754
|
+
) -> str:
|
|
755
|
+
"""Render documentation in the specified format.
|
|
756
|
+
|
|
757
|
+
This is a convenience function for rendering documentation
|
|
758
|
+
without creating a renderer instance directly.
|
|
759
|
+
|
|
760
|
+
Args:
|
|
761
|
+
doc: Documentation to render.
|
|
762
|
+
format: Output format (markdown, html, json).
|
|
763
|
+
options: Rendering options.
|
|
764
|
+
|
|
765
|
+
Returns:
|
|
766
|
+
Rendered documentation string.
|
|
767
|
+
|
|
768
|
+
Raises:
|
|
769
|
+
ValueError: If format is not supported.
|
|
770
|
+
|
|
771
|
+
Examples:
|
|
772
|
+
>>> from truthound_dashboard.core.plugins.docs import (
|
|
773
|
+
... DocumentationExtractor,
|
|
774
|
+
... render_documentation,
|
|
775
|
+
... )
|
|
776
|
+
>>> extractor = DocumentationExtractor()
|
|
777
|
+
>>> module_doc = extractor.extract_module("my_plugin.py")
|
|
778
|
+
>>> markdown = render_documentation(module_doc, "markdown")
|
|
779
|
+
>>> html = render_documentation(module_doc, "html")
|
|
780
|
+
"""
|
|
781
|
+
renderers = {
|
|
782
|
+
"markdown": MarkdownRenderer,
|
|
783
|
+
"md": MarkdownRenderer,
|
|
784
|
+
"html": HTMLRenderer,
|
|
785
|
+
"json": JSONRenderer,
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
format_lower = format.lower()
|
|
789
|
+
if format_lower not in renderers:
|
|
790
|
+
raise ValueError(
|
|
791
|
+
f"Unsupported format: {format}. "
|
|
792
|
+
f"Supported formats: {', '.join(renderers.keys())}"
|
|
793
|
+
)
|
|
794
|
+
|
|
795
|
+
renderer = renderers[format_lower](options)
|
|
796
|
+
|
|
797
|
+
if isinstance(doc, ModuleDoc):
|
|
798
|
+
return renderer.render_module(doc)
|
|
799
|
+
elif isinstance(doc, ClassDoc):
|
|
800
|
+
return renderer.render_class(doc)
|
|
801
|
+
elif isinstance(doc, FunctionDoc):
|
|
802
|
+
return renderer.render_function(doc)
|
|
803
|
+
else:
|
|
804
|
+
raise TypeError(f"Unsupported documentation type: {type(doc)}")
|