rdf-construct 0.2.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.
- rdf_construct/__init__.py +12 -0
- rdf_construct/__main__.py +0 -0
- rdf_construct/cli.py +1762 -0
- rdf_construct/core/__init__.py +33 -0
- rdf_construct/core/config.py +116 -0
- rdf_construct/core/ordering.py +219 -0
- rdf_construct/core/predicate_order.py +212 -0
- rdf_construct/core/profile.py +157 -0
- rdf_construct/core/selector.py +64 -0
- rdf_construct/core/serialiser.py +232 -0
- rdf_construct/core/utils.py +89 -0
- rdf_construct/cq/__init__.py +77 -0
- rdf_construct/cq/expectations.py +365 -0
- rdf_construct/cq/formatters/__init__.py +45 -0
- rdf_construct/cq/formatters/json.py +104 -0
- rdf_construct/cq/formatters/junit.py +104 -0
- rdf_construct/cq/formatters/text.py +146 -0
- rdf_construct/cq/loader.py +300 -0
- rdf_construct/cq/runner.py +321 -0
- rdf_construct/diff/__init__.py +59 -0
- rdf_construct/diff/change_types.py +214 -0
- rdf_construct/diff/comparator.py +338 -0
- rdf_construct/diff/filters.py +133 -0
- rdf_construct/diff/formatters/__init__.py +71 -0
- rdf_construct/diff/formatters/json.py +192 -0
- rdf_construct/diff/formatters/markdown.py +210 -0
- rdf_construct/diff/formatters/text.py +195 -0
- rdf_construct/docs/__init__.py +60 -0
- rdf_construct/docs/config.py +238 -0
- rdf_construct/docs/extractors.py +603 -0
- rdf_construct/docs/generator.py +360 -0
- rdf_construct/docs/renderers/__init__.py +7 -0
- rdf_construct/docs/renderers/html.py +803 -0
- rdf_construct/docs/renderers/json.py +390 -0
- rdf_construct/docs/renderers/markdown.py +628 -0
- rdf_construct/docs/search.py +278 -0
- rdf_construct/docs/templates/html/base.html.jinja +44 -0
- rdf_construct/docs/templates/html/class.html.jinja +152 -0
- rdf_construct/docs/templates/html/hierarchy.html.jinja +28 -0
- rdf_construct/docs/templates/html/index.html.jinja +110 -0
- rdf_construct/docs/templates/html/instance.html.jinja +90 -0
- rdf_construct/docs/templates/html/namespaces.html.jinja +37 -0
- rdf_construct/docs/templates/html/property.html.jinja +124 -0
- rdf_construct/docs/templates/html/single_page.html.jinja +169 -0
- rdf_construct/lint/__init__.py +75 -0
- rdf_construct/lint/config.py +214 -0
- rdf_construct/lint/engine.py +396 -0
- rdf_construct/lint/formatters.py +327 -0
- rdf_construct/lint/rules.py +692 -0
- rdf_construct/main.py +6 -0
- rdf_construct/puml2rdf/__init__.py +103 -0
- rdf_construct/puml2rdf/config.py +230 -0
- rdf_construct/puml2rdf/converter.py +420 -0
- rdf_construct/puml2rdf/merger.py +200 -0
- rdf_construct/puml2rdf/model.py +202 -0
- rdf_construct/puml2rdf/parser.py +565 -0
- rdf_construct/puml2rdf/validators.py +451 -0
- rdf_construct/shacl/__init__.py +56 -0
- rdf_construct/shacl/config.py +166 -0
- rdf_construct/shacl/converters.py +520 -0
- rdf_construct/shacl/generator.py +364 -0
- rdf_construct/shacl/namespaces.py +93 -0
- rdf_construct/stats/__init__.py +29 -0
- rdf_construct/stats/collector.py +178 -0
- rdf_construct/stats/comparator.py +298 -0
- rdf_construct/stats/formatters/__init__.py +83 -0
- rdf_construct/stats/formatters/json.py +38 -0
- rdf_construct/stats/formatters/markdown.py +153 -0
- rdf_construct/stats/formatters/text.py +186 -0
- rdf_construct/stats/metrics/__init__.py +26 -0
- rdf_construct/stats/metrics/basic.py +147 -0
- rdf_construct/stats/metrics/complexity.py +137 -0
- rdf_construct/stats/metrics/connectivity.py +130 -0
- rdf_construct/stats/metrics/documentation.py +128 -0
- rdf_construct/stats/metrics/hierarchy.py +207 -0
- rdf_construct/stats/metrics/properties.py +88 -0
- rdf_construct/uml/__init__.py +22 -0
- rdf_construct/uml/context.py +194 -0
- rdf_construct/uml/mapper.py +371 -0
- rdf_construct/uml/odm_renderer.py +789 -0
- rdf_construct/uml/renderer.py +684 -0
- rdf_construct/uml/uml_layout.py +393 -0
- rdf_construct/uml/uml_style.py +613 -0
- rdf_construct-0.2.0.dist-info/METADATA +431 -0
- rdf_construct-0.2.0.dist-info/RECORD +88 -0
- rdf_construct-0.2.0.dist-info/WHEEL +4 -0
- rdf_construct-0.2.0.dist-info/entry_points.txt +3 -0
- rdf_construct-0.2.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"""Main orchestrator for documentation generation.
|
|
2
|
+
|
|
3
|
+
This module coordinates entity extraction, template rendering, and output
|
|
4
|
+
file creation for generating ontology documentation.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
12
|
+
from rdflib import Graph
|
|
13
|
+
|
|
14
|
+
from rdf_construct.docs.config import DocsConfig, load_docs_config
|
|
15
|
+
from rdf_construct.docs.extractors import ExtractedEntities, extract_all
|
|
16
|
+
from rdf_construct.docs.search import generate_search_index, write_search_index
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class DocsGenerator:
|
|
23
|
+
"""Main documentation generator class.
|
|
24
|
+
|
|
25
|
+
Coordinates extraction, rendering, and file output for generating
|
|
26
|
+
comprehensive ontology documentation.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, config: DocsConfig | None = None) -> None:
|
|
30
|
+
"""Initialise the documentation generator.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
config: Documentation configuration. Uses defaults if not provided.
|
|
34
|
+
"""
|
|
35
|
+
self.config = config or DocsConfig()
|
|
36
|
+
self._renderer: "BaseRenderer | None" = None
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def renderer(self) -> "BaseRenderer":
|
|
40
|
+
"""Get the appropriate renderer for the configured format.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Renderer instance for the configured output format.
|
|
44
|
+
"""
|
|
45
|
+
if self._renderer is None:
|
|
46
|
+
self._renderer = self._create_renderer()
|
|
47
|
+
return self._renderer
|
|
48
|
+
|
|
49
|
+
def _create_renderer(self) -> "BaseRenderer":
|
|
50
|
+
"""Create the appropriate renderer based on configuration.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
Renderer instance.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ValueError: If the output format is not supported.
|
|
57
|
+
"""
|
|
58
|
+
from .renderers import HTMLRenderer, JSONRenderer, MarkdownRenderer
|
|
59
|
+
|
|
60
|
+
format_lower = self.config.format.lower()
|
|
61
|
+
|
|
62
|
+
if format_lower == "html":
|
|
63
|
+
return HTMLRenderer(self.config)
|
|
64
|
+
elif format_lower in ("markdown", "md"):
|
|
65
|
+
return MarkdownRenderer(self.config)
|
|
66
|
+
elif format_lower == "json":
|
|
67
|
+
return JSONRenderer(self.config)
|
|
68
|
+
else:
|
|
69
|
+
raise ValueError(f"Unsupported output format: {self.config.format}")
|
|
70
|
+
|
|
71
|
+
def generate(self, graph: Graph) -> GenerationResult:
|
|
72
|
+
"""Generate documentation from an RDF graph.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
graph: RDF graph to generate documentation from.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
GenerationResult with details of generated files.
|
|
79
|
+
"""
|
|
80
|
+
# Extract all entities
|
|
81
|
+
entities = extract_all(graph)
|
|
82
|
+
|
|
83
|
+
# Apply configuration overrides
|
|
84
|
+
if self.config.title:
|
|
85
|
+
entities.ontology.title = self.config.title
|
|
86
|
+
if self.config.description:
|
|
87
|
+
entities.ontology.description = self.config.description
|
|
88
|
+
|
|
89
|
+
# Create output directory
|
|
90
|
+
self.config.output_dir.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
|
|
92
|
+
result = GenerationResult(output_dir=self.config.output_dir)
|
|
93
|
+
|
|
94
|
+
# Generate main pages
|
|
95
|
+
if self.config.single_page:
|
|
96
|
+
output_path = self.renderer.render_single_page(entities)
|
|
97
|
+
result.files_created.append(output_path)
|
|
98
|
+
else:
|
|
99
|
+
# Index page
|
|
100
|
+
index_path = self.renderer.render_index(entities)
|
|
101
|
+
result.files_created.append(index_path)
|
|
102
|
+
|
|
103
|
+
# Hierarchy page
|
|
104
|
+
if self.config.include_hierarchy:
|
|
105
|
+
hierarchy_path = self.renderer.render_hierarchy(entities)
|
|
106
|
+
result.files_created.append(hierarchy_path)
|
|
107
|
+
|
|
108
|
+
# Individual entity pages
|
|
109
|
+
if self.config.include_classes:
|
|
110
|
+
for class_info in entities.classes:
|
|
111
|
+
class_path = self.renderer.render_class(class_info, entities)
|
|
112
|
+
result.files_created.append(class_path)
|
|
113
|
+
result.classes_count += 1
|
|
114
|
+
|
|
115
|
+
if self.config.include_object_properties:
|
|
116
|
+
for prop_info in entities.object_properties:
|
|
117
|
+
prop_path = self.renderer.render_property(prop_info, entities)
|
|
118
|
+
result.files_created.append(prop_path)
|
|
119
|
+
result.properties_count += 1
|
|
120
|
+
|
|
121
|
+
if self.config.include_datatype_properties:
|
|
122
|
+
for prop_info in entities.datatype_properties:
|
|
123
|
+
prop_path = self.renderer.render_property(prop_info, entities)
|
|
124
|
+
result.files_created.append(prop_path)
|
|
125
|
+
result.properties_count += 1
|
|
126
|
+
|
|
127
|
+
if self.config.include_annotation_properties:
|
|
128
|
+
for prop_info in entities.annotation_properties:
|
|
129
|
+
prop_path = self.renderer.render_property(prop_info, entities)
|
|
130
|
+
result.files_created.append(prop_path)
|
|
131
|
+
result.properties_count += 1
|
|
132
|
+
|
|
133
|
+
if self.config.include_instances:
|
|
134
|
+
for instance_info in entities.instances:
|
|
135
|
+
instance_path = self.renderer.render_instance(instance_info, entities)
|
|
136
|
+
result.files_created.append(instance_path)
|
|
137
|
+
result.instances_count += 1
|
|
138
|
+
|
|
139
|
+
# Namespace page
|
|
140
|
+
namespace_path = self.renderer.render_namespaces(entities)
|
|
141
|
+
result.files_created.append(namespace_path)
|
|
142
|
+
|
|
143
|
+
# Generate search index
|
|
144
|
+
if self.config.include_search and self.config.format == "html":
|
|
145
|
+
search_entries = generate_search_index(entities, self.config)
|
|
146
|
+
search_path = write_search_index(search_entries, self.config.output_dir)
|
|
147
|
+
result.files_created.append(search_path)
|
|
148
|
+
|
|
149
|
+
# Copy assets
|
|
150
|
+
self.renderer.copy_assets()
|
|
151
|
+
|
|
152
|
+
return result
|
|
153
|
+
|
|
154
|
+
def generate_from_file(self, source: Path) -> GenerationResult:
|
|
155
|
+
"""Generate documentation from an RDF file.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
source: Path to RDF source file.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
GenerationResult with details of generated files.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
FileNotFoundError: If the source file doesn't exist.
|
|
165
|
+
"""
|
|
166
|
+
if not source.exists():
|
|
167
|
+
raise FileNotFoundError(f"Source file not found: {source}")
|
|
168
|
+
|
|
169
|
+
graph = Graph()
|
|
170
|
+
|
|
171
|
+
# Determine format from extension
|
|
172
|
+
suffix = source.suffix.lower()
|
|
173
|
+
format_map = {
|
|
174
|
+
".ttl": "turtle",
|
|
175
|
+
".turtle": "turtle",
|
|
176
|
+
".rdf": "xml",
|
|
177
|
+
".xml": "xml",
|
|
178
|
+
".owl": "xml",
|
|
179
|
+
".nt": "nt",
|
|
180
|
+
".ntriples": "nt",
|
|
181
|
+
".n3": "n3",
|
|
182
|
+
".jsonld": "json-ld",
|
|
183
|
+
".json": "json-ld",
|
|
184
|
+
}
|
|
185
|
+
rdf_format = format_map.get(suffix, "turtle")
|
|
186
|
+
|
|
187
|
+
graph.parse(str(source), format=rdf_format)
|
|
188
|
+
return self.generate(graph)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class GenerationResult:
|
|
192
|
+
"""Result of a documentation generation run."""
|
|
193
|
+
|
|
194
|
+
def __init__(self, output_dir: Path) -> None:
|
|
195
|
+
"""Initialise the result.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
output_dir: Output directory for generated files.
|
|
199
|
+
"""
|
|
200
|
+
self.output_dir = output_dir
|
|
201
|
+
self.files_created: list[Path] = []
|
|
202
|
+
self.classes_count = 0
|
|
203
|
+
self.properties_count = 0
|
|
204
|
+
self.instances_count = 0
|
|
205
|
+
|
|
206
|
+
@property
|
|
207
|
+
def total_pages(self) -> int:
|
|
208
|
+
"""Get the total number of pages generated."""
|
|
209
|
+
return len(self.files_created)
|
|
210
|
+
|
|
211
|
+
def __str__(self) -> str:
|
|
212
|
+
"""Get a summary string."""
|
|
213
|
+
return (
|
|
214
|
+
f"Generated {self.total_pages} files to {self.output_dir}/\n"
|
|
215
|
+
f" Classes: {self.classes_count}\n"
|
|
216
|
+
f" Properties: {self.properties_count}\n"
|
|
217
|
+
f" Instances: {self.instances_count}"
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# Public interface from this module
|
|
222
|
+
class BaseRenderer:
|
|
223
|
+
"""Base class for documentation renderers.
|
|
224
|
+
|
|
225
|
+
Subclasses implement format-specific rendering logic.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
def __init__(self, config: DocsConfig) -> None:
|
|
229
|
+
"""Initialise the renderer.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
config: Documentation configuration.
|
|
233
|
+
"""
|
|
234
|
+
self.config = config
|
|
235
|
+
|
|
236
|
+
def render_index(self, entities: ExtractedEntities) -> Path:
|
|
237
|
+
"""Render the main index page.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
entities: All extracted entities.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
Path to the rendered file.
|
|
244
|
+
"""
|
|
245
|
+
raise NotImplementedError
|
|
246
|
+
|
|
247
|
+
def render_hierarchy(self, entities: ExtractedEntities) -> Path:
|
|
248
|
+
"""Render the class hierarchy page.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
entities: All extracted entities.
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Path to the rendered file.
|
|
255
|
+
"""
|
|
256
|
+
raise NotImplementedError
|
|
257
|
+
|
|
258
|
+
def render_class(
|
|
259
|
+
self,
|
|
260
|
+
class_info: "ClassInfo",
|
|
261
|
+
entities: ExtractedEntities,
|
|
262
|
+
) -> Path:
|
|
263
|
+
"""Render a class documentation page.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
class_info: Class to render.
|
|
267
|
+
entities: All extracted entities (for cross-references).
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
Path to the rendered file.
|
|
271
|
+
"""
|
|
272
|
+
raise NotImplementedError
|
|
273
|
+
|
|
274
|
+
def render_property(
|
|
275
|
+
self,
|
|
276
|
+
prop_info: "PropertyInfo",
|
|
277
|
+
entities: ExtractedEntities,
|
|
278
|
+
) -> Path:
|
|
279
|
+
"""Render a property documentation page.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
prop_info: Property to render.
|
|
283
|
+
entities: All extracted entities.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Path to the rendered file.
|
|
287
|
+
"""
|
|
288
|
+
raise NotImplementedError
|
|
289
|
+
|
|
290
|
+
def render_instance(
|
|
291
|
+
self,
|
|
292
|
+
instance_info: "InstanceInfo",
|
|
293
|
+
entities: ExtractedEntities,
|
|
294
|
+
) -> Path:
|
|
295
|
+
"""Render an instance documentation page.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
instance_info: Instance to render.
|
|
299
|
+
entities: All extracted entities.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Path to the rendered file.
|
|
303
|
+
"""
|
|
304
|
+
raise NotImplementedError
|
|
305
|
+
|
|
306
|
+
def render_namespaces(self, entities: ExtractedEntities) -> Path:
|
|
307
|
+
"""Render the namespace reference page.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
entities: All extracted entities.
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Path to the rendered file.
|
|
314
|
+
"""
|
|
315
|
+
raise NotImplementedError
|
|
316
|
+
|
|
317
|
+
def render_single_page(self, entities: ExtractedEntities) -> Path:
|
|
318
|
+
"""Render all documentation as a single page.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
entities: All extracted entities.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
Path to the rendered file.
|
|
325
|
+
"""
|
|
326
|
+
raise NotImplementedError
|
|
327
|
+
|
|
328
|
+
def copy_assets(self) -> None:
|
|
329
|
+
"""Copy static assets (CSS, JS) to the output directory."""
|
|
330
|
+
pass # Default: no assets to copy
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def generate_docs(
|
|
334
|
+
source: Path,
|
|
335
|
+
output_dir: Path | None = None,
|
|
336
|
+
config_path: Path | None = None,
|
|
337
|
+
output_format: str = "html",
|
|
338
|
+
) -> GenerationResult:
|
|
339
|
+
"""Generate documentation from an RDF file.
|
|
340
|
+
|
|
341
|
+
Convenience function for simple documentation generation.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
source: Path to RDF source file.
|
|
345
|
+
output_dir: Output directory (overrides config).
|
|
346
|
+
config_path: Path to configuration file.
|
|
347
|
+
output_format: Output format (html, markdown, json).
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
GenerationResult with details of generated files.
|
|
351
|
+
"""
|
|
352
|
+
config = load_docs_config(config_path)
|
|
353
|
+
|
|
354
|
+
if output_dir:
|
|
355
|
+
config.output_dir = output_dir
|
|
356
|
+
if output_format:
|
|
357
|
+
config.format = output_format
|
|
358
|
+
|
|
359
|
+
generator = DocsGenerator(config)
|
|
360
|
+
return generator.generate_from_file(source)
|