fishertools 0.2.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.
- fishertools/__init__.py +82 -0
- fishertools/config/__init__.py +24 -0
- fishertools/config/manager.py +247 -0
- fishertools/config/models.py +96 -0
- fishertools/config/parser.py +265 -0
- fishertools/decorators.py +93 -0
- fishertools/documentation/__init__.py +38 -0
- fishertools/documentation/api.py +242 -0
- fishertools/documentation/generator.py +502 -0
- fishertools/documentation/models.py +126 -0
- fishertools/documentation/visual.py +583 -0
- fishertools/errors/__init__.py +29 -0
- fishertools/errors/exceptions.py +191 -0
- fishertools/errors/explainer.py +303 -0
- fishertools/errors/formatters.py +386 -0
- fishertools/errors/models.py +228 -0
- fishertools/errors/patterns.py +119 -0
- fishertools/errors/recovery.py +467 -0
- fishertools/examples/__init__.py +22 -0
- fishertools/examples/models.py +118 -0
- fishertools/examples/repository.py +770 -0
- fishertools/helpers.py +116 -0
- fishertools/integration.py +451 -0
- fishertools/learn/__init__.py +18 -0
- fishertools/learn/examples.py +550 -0
- fishertools/learn/tips.py +281 -0
- fishertools/learning/__init__.py +32 -0
- fishertools/learning/core.py +349 -0
- fishertools/learning/models.py +112 -0
- fishertools/learning/progress.py +314 -0
- fishertools/learning/session.py +500 -0
- fishertools/learning/tutorial.py +626 -0
- fishertools/legacy/__init__.py +76 -0
- fishertools/legacy/deprecated.py +261 -0
- fishertools/legacy/deprecation.py +149 -0
- fishertools/safe/__init__.py +16 -0
- fishertools/safe/collections.py +242 -0
- fishertools/safe/files.py +240 -0
- fishertools/safe/strings.py +15 -0
- fishertools/utils.py +57 -0
- fishertools-0.2.1.dist-info/METADATA +256 -0
- fishertools-0.2.1.dist-info/RECORD +81 -0
- fishertools-0.2.1.dist-info/WHEEL +5 -0
- fishertools-0.2.1.dist-info/licenses/LICENSE +21 -0
- fishertools-0.2.1.dist-info/top_level.txt +2 -0
- tests/__init__.py +6 -0
- tests/conftest.py +25 -0
- tests/test_config/__init__.py +3 -0
- tests/test_config/test_basic_config.py +57 -0
- tests/test_config/test_config_error_handling.py +287 -0
- tests/test_config/test_config_properties.py +435 -0
- tests/test_documentation/__init__.py +3 -0
- tests/test_documentation/test_documentation_properties.py +253 -0
- tests/test_documentation/test_visual_documentation_properties.py +444 -0
- tests/test_errors/__init__.py +3 -0
- tests/test_errors/test_api.py +301 -0
- tests/test_errors/test_error_handling.py +354 -0
- tests/test_errors/test_explainer.py +173 -0
- tests/test_errors/test_formatters.py +338 -0
- tests/test_errors/test_models.py +248 -0
- tests/test_errors/test_patterns.py +270 -0
- tests/test_examples/__init__.py +3 -0
- tests/test_examples/test_example_repository_properties.py +204 -0
- tests/test_examples/test_specific_examples.py +303 -0
- tests/test_integration.py +298 -0
- tests/test_integration_enhancements.py +462 -0
- tests/test_learn/__init__.py +3 -0
- tests/test_learn/test_examples.py +221 -0
- tests/test_learn/test_tips.py +285 -0
- tests/test_learning/__init__.py +3 -0
- tests/test_learning/test_interactive_learning_properties.py +337 -0
- tests/test_learning/test_learning_system_properties.py +194 -0
- tests/test_learning/test_progress_tracking_properties.py +279 -0
- tests/test_legacy/__init__.py +3 -0
- tests/test_legacy/test_backward_compatibility.py +236 -0
- tests/test_legacy/test_deprecation_warnings.py +208 -0
- tests/test_safe/__init__.py +3 -0
- tests/test_safe/test_collections_properties.py +189 -0
- tests/test_safe/test_files.py +104 -0
- tests/test_structure.py +58 -0
- tests/test_structure_enhancements.py +115 -0
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Main documentation generator with Sphinx integration.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import json
|
|
7
|
+
from typing import List, Dict, Any
|
|
8
|
+
from .models import (
|
|
9
|
+
APIInfo, SphinxDocuments, NavigationTree,
|
|
10
|
+
ExampleCode, PublishResult, FunctionInfo, PublishStatus
|
|
11
|
+
)
|
|
12
|
+
from .api import APIGenerator
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DocumentationGenerator:
|
|
16
|
+
"""
|
|
17
|
+
Automatic API documentation generator with ReadTheDocs integration.
|
|
18
|
+
|
|
19
|
+
Extracts API information, generates Sphinx documentation,
|
|
20
|
+
and publishes to ReadTheDocs automatically.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, project_name: str, output_dir: str = "docs"):
|
|
24
|
+
"""
|
|
25
|
+
Initialize the documentation generator.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
project_name: Name of the project
|
|
29
|
+
output_dir: Directory for generated documentation
|
|
30
|
+
"""
|
|
31
|
+
self.project_name = project_name
|
|
32
|
+
self.output_dir = output_dir
|
|
33
|
+
self.api_generator = APIGenerator()
|
|
34
|
+
|
|
35
|
+
# Integration point for visual documentation
|
|
36
|
+
self._visual_docs = None
|
|
37
|
+
|
|
38
|
+
def extract_api_info(self, module_path: str) -> APIInfo:
|
|
39
|
+
"""
|
|
40
|
+
Extract API information from a Python module.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
module_path: Path to the Python module
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
APIInfo: Extracted API information
|
|
47
|
+
"""
|
|
48
|
+
return self.api_generator.parse_module(module_path)
|
|
49
|
+
|
|
50
|
+
def generate_sphinx_docs(self, api_info: APIInfo) -> SphinxDocuments:
|
|
51
|
+
"""
|
|
52
|
+
Generate Sphinx documentation from API information.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
api_info: API information to document
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
SphinxDocuments: Generated Sphinx documentation
|
|
59
|
+
"""
|
|
60
|
+
source_files = {}
|
|
61
|
+
|
|
62
|
+
# Generate main module RST file
|
|
63
|
+
rst_content = self.api_generator.generate_sphinx_rst(api_info)
|
|
64
|
+
source_files[f"{api_info.module_name}.rst"] = rst_content
|
|
65
|
+
|
|
66
|
+
# Generate index.rst
|
|
67
|
+
index_content = self._generate_index_rst([api_info.module_name])
|
|
68
|
+
source_files["index.rst"] = index_content
|
|
69
|
+
|
|
70
|
+
# Generate conf.py
|
|
71
|
+
config = self._generate_sphinx_config()
|
|
72
|
+
source_files["conf.py"] = self._config_to_python_file(config)
|
|
73
|
+
|
|
74
|
+
# Create navigation tree
|
|
75
|
+
navigation = NavigationTree(
|
|
76
|
+
name=self.project_name,
|
|
77
|
+
path="index.rst",
|
|
78
|
+
children=[
|
|
79
|
+
NavigationTree(
|
|
80
|
+
name=api_info.module_name,
|
|
81
|
+
path=f"{api_info.module_name}.rst"
|
|
82
|
+
)
|
|
83
|
+
]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return SphinxDocuments(
|
|
87
|
+
source_files=source_files,
|
|
88
|
+
config=config,
|
|
89
|
+
navigation=navigation,
|
|
90
|
+
build_path=self.output_dir
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def create_navigation_structure(self, modules: List[str]) -> NavigationTree:
|
|
94
|
+
"""
|
|
95
|
+
Create structured navigation for documentation.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
modules: List of module names to include
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
NavigationTree: Hierarchical navigation structure
|
|
102
|
+
"""
|
|
103
|
+
children = []
|
|
104
|
+
for module in modules:
|
|
105
|
+
children.append(NavigationTree(
|
|
106
|
+
name=module,
|
|
107
|
+
path=f"{module}.rst"
|
|
108
|
+
))
|
|
109
|
+
|
|
110
|
+
return NavigationTree(
|
|
111
|
+
name=self.project_name,
|
|
112
|
+
path="index.rst",
|
|
113
|
+
children=children
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def add_usage_examples(self, function: FunctionInfo) -> List[ExampleCode]:
|
|
117
|
+
"""
|
|
118
|
+
Generate usage examples for a function.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
function: Function information
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
List[ExampleCode]: Generated usage examples
|
|
125
|
+
"""
|
|
126
|
+
examples = []
|
|
127
|
+
|
|
128
|
+
# Generate basic usage example
|
|
129
|
+
basic_example = self._generate_basic_example(function)
|
|
130
|
+
if basic_example:
|
|
131
|
+
examples.append(basic_example)
|
|
132
|
+
|
|
133
|
+
# Generate example with error handling if applicable
|
|
134
|
+
error_example = self._generate_error_handling_example(function)
|
|
135
|
+
if error_example:
|
|
136
|
+
examples.append(error_example)
|
|
137
|
+
|
|
138
|
+
# Generate advanced example if function has complex parameters
|
|
139
|
+
if len(function.parameters) > 2:
|
|
140
|
+
advanced_example = self._generate_advanced_example(function)
|
|
141
|
+
if advanced_example:
|
|
142
|
+
examples.append(advanced_example)
|
|
143
|
+
|
|
144
|
+
return examples
|
|
145
|
+
|
|
146
|
+
def publish_to_readthedocs(self, docs: SphinxDocuments) -> PublishResult:
|
|
147
|
+
"""
|
|
148
|
+
Publish documentation to ReadTheDocs.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
docs: Sphinx documentation to publish
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
PublishResult: Result of the publishing operation
|
|
155
|
+
"""
|
|
156
|
+
try:
|
|
157
|
+
# Create output directory if it doesn't exist
|
|
158
|
+
os.makedirs(docs.build_path, exist_ok=True)
|
|
159
|
+
|
|
160
|
+
# Write all source files
|
|
161
|
+
for filename, content in docs.source_files.items():
|
|
162
|
+
file_path = os.path.join(docs.build_path, filename)
|
|
163
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
164
|
+
f.write(content)
|
|
165
|
+
|
|
166
|
+
# Create .readthedocs.yaml configuration
|
|
167
|
+
readthedocs_config = self._generate_readthedocs_config()
|
|
168
|
+
config_path = os.path.join(docs.build_path, ".readthedocs.yaml")
|
|
169
|
+
with open(config_path, 'w', encoding='utf-8') as f:
|
|
170
|
+
f.write(readthedocs_config)
|
|
171
|
+
|
|
172
|
+
# Create requirements.txt for ReadTheDocs
|
|
173
|
+
requirements_content = self._generate_requirements_txt()
|
|
174
|
+
req_path = os.path.join(docs.build_path, "requirements.txt")
|
|
175
|
+
with open(req_path, 'w', encoding='utf-8') as f:
|
|
176
|
+
f.write(requirements_content)
|
|
177
|
+
|
|
178
|
+
return PublishResult(
|
|
179
|
+
status=PublishStatus.SUCCESS,
|
|
180
|
+
url=f"https://{self.project_name.lower()}.readthedocs.io",
|
|
181
|
+
build_log=["Documentation files generated successfully"]
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
return PublishResult(
|
|
186
|
+
status=PublishStatus.FAILED,
|
|
187
|
+
error_message=str(e),
|
|
188
|
+
build_log=[f"Error: {str(e)}"]
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def build_documentation(self, module_paths: List[str]) -> SphinxDocuments:
|
|
192
|
+
"""
|
|
193
|
+
Build complete documentation for multiple modules.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
module_paths: List of module paths to document
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
SphinxDocuments: Complete generated documentation
|
|
200
|
+
"""
|
|
201
|
+
all_modules = []
|
|
202
|
+
source_files = {}
|
|
203
|
+
|
|
204
|
+
# Process each module
|
|
205
|
+
for module_path in module_paths:
|
|
206
|
+
api_info = self.extract_api_info(module_path)
|
|
207
|
+
all_modules.append(api_info.module_name)
|
|
208
|
+
|
|
209
|
+
# Generate RST for this module
|
|
210
|
+
rst_content = self.api_generator.generate_sphinx_rst(api_info)
|
|
211
|
+
source_files[f"{api_info.module_name}.rst"] = rst_content
|
|
212
|
+
|
|
213
|
+
# Generate index.rst for all modules
|
|
214
|
+
index_content = self._generate_index_rst(all_modules)
|
|
215
|
+
source_files["index.rst"] = index_content
|
|
216
|
+
|
|
217
|
+
# Generate conf.py
|
|
218
|
+
config = self._generate_sphinx_config()
|
|
219
|
+
source_files["conf.py"] = self._config_to_python_file(config)
|
|
220
|
+
|
|
221
|
+
# Create navigation structure
|
|
222
|
+
navigation = self.create_navigation_structure(all_modules)
|
|
223
|
+
|
|
224
|
+
return SphinxDocuments(
|
|
225
|
+
source_files=source_files,
|
|
226
|
+
config=config,
|
|
227
|
+
navigation=navigation,
|
|
228
|
+
build_path=self.output_dir
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def _generate_index_rst(self, modules: List[str]) -> str:
|
|
232
|
+
"""Generate the main index.rst file."""
|
|
233
|
+
content = []
|
|
234
|
+
|
|
235
|
+
title = f"{self.project_name} Documentation"
|
|
236
|
+
content.append(title)
|
|
237
|
+
content.append("=" * len(title))
|
|
238
|
+
content.append("")
|
|
239
|
+
content.append("Welcome to the API documentation.")
|
|
240
|
+
content.append("")
|
|
241
|
+
content.append(".. toctree::")
|
|
242
|
+
content.append(" :maxdepth: 2")
|
|
243
|
+
content.append(" :caption: Contents:")
|
|
244
|
+
content.append("")
|
|
245
|
+
|
|
246
|
+
for module in modules:
|
|
247
|
+
content.append(f" {module}")
|
|
248
|
+
|
|
249
|
+
content.append("")
|
|
250
|
+
content.append("Indices and tables")
|
|
251
|
+
content.append("==================")
|
|
252
|
+
content.append("")
|
|
253
|
+
content.append("* :ref:`genindex`")
|
|
254
|
+
content.append("* :ref:`modindex`")
|
|
255
|
+
content.append("* :ref:`search`")
|
|
256
|
+
|
|
257
|
+
return "\n".join(content)
|
|
258
|
+
|
|
259
|
+
def _generate_sphinx_config(self) -> Dict[str, Any]:
|
|
260
|
+
"""Generate Sphinx configuration."""
|
|
261
|
+
return {
|
|
262
|
+
'project': self.project_name,
|
|
263
|
+
'copyright': '2024, Auto-generated',
|
|
264
|
+
'author': 'Auto-generated',
|
|
265
|
+
'extensions': [
|
|
266
|
+
'sphinx.ext.autodoc',
|
|
267
|
+
'sphinx.ext.viewcode',
|
|
268
|
+
'sphinx.ext.napoleon',
|
|
269
|
+
'sphinx.ext.intersphinx'
|
|
270
|
+
],
|
|
271
|
+
'templates_path': ['_templates'],
|
|
272
|
+
'exclude_patterns': ['_build', 'Thumbs.db', '.DS_Store'],
|
|
273
|
+
'html_theme': 'sphinx_rtd_theme',
|
|
274
|
+
'html_static_path': ['_static'],
|
|
275
|
+
'autodoc_default_options': {
|
|
276
|
+
'members': True,
|
|
277
|
+
'undoc-members': True,
|
|
278
|
+
'show-inheritance': True
|
|
279
|
+
},
|
|
280
|
+
'napoleon_google_docstring': True,
|
|
281
|
+
'napoleon_numpy_docstring': True,
|
|
282
|
+
'intersphinx_mapping': {
|
|
283
|
+
'python': ('https://docs.python.org/3', None)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
def _config_to_python_file(self, config: Dict[str, Any]) -> str:
|
|
288
|
+
"""Convert configuration dict to Python file content."""
|
|
289
|
+
lines = []
|
|
290
|
+
lines.append("# Configuration file for the Sphinx documentation builder.")
|
|
291
|
+
lines.append("# Auto-generated by fishertools DocumentationGenerator")
|
|
292
|
+
lines.append("")
|
|
293
|
+
|
|
294
|
+
for key, value in config.items():
|
|
295
|
+
if isinstance(value, str):
|
|
296
|
+
lines.append(f"{key} = '{value}'")
|
|
297
|
+
elif isinstance(value, list):
|
|
298
|
+
lines.append(f"{key} = {repr(value)}")
|
|
299
|
+
elif isinstance(value, dict):
|
|
300
|
+
lines.append(f"{key} = {repr(value)}")
|
|
301
|
+
else:
|
|
302
|
+
lines.append(f"{key} = {repr(value)}")
|
|
303
|
+
|
|
304
|
+
return "\n".join(lines)
|
|
305
|
+
|
|
306
|
+
def _generate_basic_example(self, function: FunctionInfo) -> ExampleCode:
|
|
307
|
+
"""Generate a basic usage example for a function."""
|
|
308
|
+
# Create simple parameter values based on type hints
|
|
309
|
+
param_values = []
|
|
310
|
+
for param_name, param_type in function.parameters.items():
|
|
311
|
+
if param_name == 'self':
|
|
312
|
+
continue
|
|
313
|
+
|
|
314
|
+
if 'str' in param_type.lower():
|
|
315
|
+
param_values.append(f'"{param_name}_value"')
|
|
316
|
+
elif 'int' in param_type.lower():
|
|
317
|
+
param_values.append('42')
|
|
318
|
+
elif 'float' in param_type.lower():
|
|
319
|
+
param_values.append('3.14')
|
|
320
|
+
elif 'bool' in param_type.lower():
|
|
321
|
+
param_values.append('True')
|
|
322
|
+
elif 'list' in param_type.lower():
|
|
323
|
+
param_values.append('[1, 2, 3]')
|
|
324
|
+
elif 'dict' in param_type.lower():
|
|
325
|
+
param_values.append('{"key": "value"}')
|
|
326
|
+
else:
|
|
327
|
+
param_values.append('None')
|
|
328
|
+
|
|
329
|
+
# Generate function call
|
|
330
|
+
if param_values:
|
|
331
|
+
call = f"{function.name}({', '.join(param_values)})"
|
|
332
|
+
else:
|
|
333
|
+
call = f"{function.name}()"
|
|
334
|
+
|
|
335
|
+
code = f"""# Basic usage example
|
|
336
|
+
result = {call}
|
|
337
|
+
print(result)"""
|
|
338
|
+
|
|
339
|
+
return ExampleCode(
|
|
340
|
+
code=code,
|
|
341
|
+
description=f"Basic usage of {function.name}",
|
|
342
|
+
expected_output="# Output will depend on the function implementation"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
def _generate_error_handling_example(self, function: FunctionInfo) -> ExampleCode:
|
|
346
|
+
"""Generate an example with error handling."""
|
|
347
|
+
if not function.docstring or 'raise' not in function.docstring.lower():
|
|
348
|
+
return None
|
|
349
|
+
|
|
350
|
+
# Create a simple error handling example
|
|
351
|
+
param_values = ['invalid_input'] * len([p for p in function.parameters.keys() if p != 'self'])
|
|
352
|
+
|
|
353
|
+
if param_values:
|
|
354
|
+
call = f"{function.name}({', '.join(param_values)})"
|
|
355
|
+
else:
|
|
356
|
+
call = f"{function.name}()"
|
|
357
|
+
|
|
358
|
+
code = f"""# Error handling example
|
|
359
|
+
try:
|
|
360
|
+
result = {call}
|
|
361
|
+
print(f"Success: {{result}}")
|
|
362
|
+
except Exception as e:
|
|
363
|
+
print(f"Error: {{e}}")"""
|
|
364
|
+
|
|
365
|
+
return ExampleCode(
|
|
366
|
+
code=code,
|
|
367
|
+
description=f"Error handling with {function.name}",
|
|
368
|
+
expected_output="# Will show either success or error message"
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
def _generate_advanced_example(self, function: FunctionInfo) -> ExampleCode:
|
|
372
|
+
"""Generate an advanced usage example."""
|
|
373
|
+
# Create more realistic parameter values
|
|
374
|
+
param_assignments = []
|
|
375
|
+
param_names = []
|
|
376
|
+
|
|
377
|
+
for param_name, param_type in function.parameters.items():
|
|
378
|
+
if param_name == 'self':
|
|
379
|
+
continue
|
|
380
|
+
|
|
381
|
+
var_name = f"{param_name}_data"
|
|
382
|
+
param_names.append(var_name)
|
|
383
|
+
|
|
384
|
+
if 'str' in param_type.lower():
|
|
385
|
+
param_assignments.append(f'{var_name} = "example_{param_name}"')
|
|
386
|
+
elif 'list' in param_type.lower():
|
|
387
|
+
param_assignments.append(f'{var_name} = ["item1", "item2", "item3"]')
|
|
388
|
+
elif 'dict' in param_type.lower():
|
|
389
|
+
param_assignments.append(f'{var_name} = {{"key1": "value1", "key2": "value2"}}')
|
|
390
|
+
else:
|
|
391
|
+
param_assignments.append(f'{var_name} = None # Replace with appropriate value')
|
|
392
|
+
|
|
393
|
+
assignments = '\n'.join(param_assignments)
|
|
394
|
+
call = f"{function.name}({', '.join(param_names)})"
|
|
395
|
+
|
|
396
|
+
code = f"""# Advanced usage example
|
|
397
|
+
{assignments}
|
|
398
|
+
|
|
399
|
+
result = {call}
|
|
400
|
+
print(f"Result: {{result}}")"""
|
|
401
|
+
|
|
402
|
+
return ExampleCode(
|
|
403
|
+
code=code,
|
|
404
|
+
description=f"Advanced usage of {function.name} with realistic data",
|
|
405
|
+
expected_output="# Output will show the processed result"
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
def _generate_readthedocs_config(self) -> str:
|
|
409
|
+
"""Generate .readthedocs.yaml configuration."""
|
|
410
|
+
config = f"""# .readthedocs.yaml
|
|
411
|
+
# Read the Docs configuration file
|
|
412
|
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
413
|
+
|
|
414
|
+
version: 2
|
|
415
|
+
|
|
416
|
+
build:
|
|
417
|
+
os: ubuntu-22.04
|
|
418
|
+
tools:
|
|
419
|
+
python: "3.11"
|
|
420
|
+
|
|
421
|
+
sphinx:
|
|
422
|
+
configuration: conf.py
|
|
423
|
+
|
|
424
|
+
python:
|
|
425
|
+
install:
|
|
426
|
+
- requirements: requirements.txt
|
|
427
|
+
- method: pip
|
|
428
|
+
path: .
|
|
429
|
+
"""
|
|
430
|
+
return config
|
|
431
|
+
|
|
432
|
+
def _generate_requirements_txt(self) -> str:
|
|
433
|
+
"""Generate requirements.txt for ReadTheDocs."""
|
|
434
|
+
requirements = """# Documentation requirements
|
|
435
|
+
sphinx>=4.0.0
|
|
436
|
+
sphinx-rtd-theme>=1.0.0
|
|
437
|
+
sphinx-autodoc-typehints>=1.12.0
|
|
438
|
+
"""
|
|
439
|
+
return requirements
|
|
440
|
+
|
|
441
|
+
def generate_enhanced_documentation(self, module_paths: List[str]) -> Dict[str, Any]:
|
|
442
|
+
"""
|
|
443
|
+
Generate enhanced documentation with visual elements.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
module_paths: List of module paths to document
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
Dictionary containing documentation and visual artifacts
|
|
450
|
+
"""
|
|
451
|
+
try:
|
|
452
|
+
# Generate standard Sphinx documentation
|
|
453
|
+
sphinx_docs = self.build_documentation(module_paths)
|
|
454
|
+
|
|
455
|
+
result = {
|
|
456
|
+
'sphinx_docs': sphinx_docs,
|
|
457
|
+
'visual_artifacts': {},
|
|
458
|
+
'enhanced_files': {}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
# Add visual elements if visual documentation is available
|
|
462
|
+
if self._visual_docs:
|
|
463
|
+
for module_path in module_paths:
|
|
464
|
+
try:
|
|
465
|
+
api_info = self.extract_api_info(module_path)
|
|
466
|
+
|
|
467
|
+
# Create architecture diagram
|
|
468
|
+
arch_diagram = self._visual_docs.create_architecture_diagram([api_info.module_name])
|
|
469
|
+
result['visual_artifacts'][f"{api_info.module_name}_architecture"] = arch_diagram
|
|
470
|
+
|
|
471
|
+
# Create enhanced RST with visual elements
|
|
472
|
+
enhanced_rst = self._create_enhanced_rst(api_info, arch_diagram)
|
|
473
|
+
result['enhanced_files'][f"{api_info.module_name}_enhanced.rst"] = enhanced_rst
|
|
474
|
+
|
|
475
|
+
except Exception as e:
|
|
476
|
+
logging.warning(f"Failed to create visuals for {module_path}: {e}")
|
|
477
|
+
|
|
478
|
+
return result
|
|
479
|
+
|
|
480
|
+
except Exception as e:
|
|
481
|
+
logging.error(f"Failed to generate enhanced documentation: {e}")
|
|
482
|
+
raise
|
|
483
|
+
|
|
484
|
+
def _create_enhanced_rst(self, api_info, architecture_diagram) -> str:
|
|
485
|
+
"""Create enhanced RST file with visual elements."""
|
|
486
|
+
base_rst = self.api_generator.generate_sphinx_rst(api_info)
|
|
487
|
+
|
|
488
|
+
# Add architecture diagram at the beginning
|
|
489
|
+
enhanced_rst = f"""
|
|
490
|
+
{api_info.module_name} Module
|
|
491
|
+
{'=' * (len(api_info.module_name) + 7)}
|
|
492
|
+
|
|
493
|
+
Architecture Overview
|
|
494
|
+
--------------------
|
|
495
|
+
|
|
496
|
+
.. mermaid::
|
|
497
|
+
|
|
498
|
+
{architecture_diagram.content if hasattr(architecture_diagram, 'content') else 'graph TD; A[Module] --> B[Components]'}
|
|
499
|
+
|
|
500
|
+
{base_rst}
|
|
501
|
+
"""
|
|
502
|
+
return enhanced_rst
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data models for the Documentation Generation module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import List, Optional, Dict, Any
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DiagramType(Enum):
|
|
11
|
+
"""Types of diagrams that can be generated."""
|
|
12
|
+
ARCHITECTURE = "architecture"
|
|
13
|
+
DATA_FLOW = "data_flow"
|
|
14
|
+
FLOWCHART = "flowchart"
|
|
15
|
+
STRUCTURE = "structure"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PublishStatus(Enum):
|
|
19
|
+
"""Status of documentation publishing."""
|
|
20
|
+
SUCCESS = "success"
|
|
21
|
+
FAILED = "failed"
|
|
22
|
+
IN_PROGRESS = "in_progress"
|
|
23
|
+
PENDING = "pending"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class FunctionInfo:
|
|
28
|
+
"""Information about a function for documentation."""
|
|
29
|
+
name: str
|
|
30
|
+
docstring: Optional[str]
|
|
31
|
+
parameters: Dict[str, str] # param_name -> type_annotation
|
|
32
|
+
return_type: Optional[str]
|
|
33
|
+
module_path: str
|
|
34
|
+
line_number: int
|
|
35
|
+
examples: List[str] = None
|
|
36
|
+
|
|
37
|
+
def __post_init__(self):
|
|
38
|
+
if self.examples is None:
|
|
39
|
+
self.examples = []
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class APIInfo:
|
|
44
|
+
"""Complete API information for a module."""
|
|
45
|
+
module_name: str
|
|
46
|
+
functions: List[FunctionInfo]
|
|
47
|
+
classes: List[Dict[str, Any]]
|
|
48
|
+
constants: Dict[str, Any]
|
|
49
|
+
imports: List[str]
|
|
50
|
+
docstring: Optional[str] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class NavigationTree:
|
|
55
|
+
"""Navigation structure for documentation."""
|
|
56
|
+
name: str
|
|
57
|
+
path: str
|
|
58
|
+
children: List['NavigationTree'] = None
|
|
59
|
+
|
|
60
|
+
def __post_init__(self):
|
|
61
|
+
if self.children is None:
|
|
62
|
+
self.children = []
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class ExampleCode:
|
|
67
|
+
"""Code example with explanation."""
|
|
68
|
+
code: str
|
|
69
|
+
description: str
|
|
70
|
+
expected_output: Optional[str] = None
|
|
71
|
+
language: str = "python"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class SphinxDocuments:
|
|
76
|
+
"""Generated Sphinx documentation."""
|
|
77
|
+
source_files: Dict[str, str] # filename -> content
|
|
78
|
+
config: Dict[str, Any]
|
|
79
|
+
navigation: NavigationTree
|
|
80
|
+
build_path: str
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class PublishResult:
|
|
85
|
+
"""Result of publishing documentation."""
|
|
86
|
+
status: PublishStatus
|
|
87
|
+
url: Optional[str] = None
|
|
88
|
+
error_message: Optional[str] = None
|
|
89
|
+
build_log: List[str] = None
|
|
90
|
+
|
|
91
|
+
def __post_init__(self):
|
|
92
|
+
if self.build_log is None:
|
|
93
|
+
self.build_log = []
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass
|
|
97
|
+
class MermaidDiagram:
|
|
98
|
+
"""Mermaid diagram representation."""
|
|
99
|
+
diagram_type: DiagramType
|
|
100
|
+
content: str
|
|
101
|
+
title: Optional[str] = None
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass
|
|
105
|
+
class FlowDiagram:
|
|
106
|
+
"""Data flow diagram."""
|
|
107
|
+
nodes: List[Dict[str, str]]
|
|
108
|
+
edges: List[Dict[str, str]]
|
|
109
|
+
title: str
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass
|
|
113
|
+
class Flowchart:
|
|
114
|
+
"""Algorithm flowchart."""
|
|
115
|
+
steps: List[Dict[str, Any]]
|
|
116
|
+
connections: List[Dict[str, str]]
|
|
117
|
+
title: str
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class StructureDiagram:
|
|
122
|
+
"""Data structure visualization."""
|
|
123
|
+
structure_type: str
|
|
124
|
+
data: Any
|
|
125
|
+
visualization: str
|
|
126
|
+
title: Optional[str] = None
|