rdf-construct 0.3.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 +3429 -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/localise/__init__.py +114 -0
- rdf_construct/localise/config.py +508 -0
- rdf_construct/localise/extractor.py +427 -0
- rdf_construct/localise/formatters/__init__.py +36 -0
- rdf_construct/localise/formatters/markdown.py +229 -0
- rdf_construct/localise/formatters/text.py +224 -0
- rdf_construct/localise/merger.py +346 -0
- rdf_construct/localise/reporter.py +356 -0
- rdf_construct/main.py +6 -0
- rdf_construct/merge/__init__.py +165 -0
- rdf_construct/merge/config.py +354 -0
- rdf_construct/merge/conflicts.py +281 -0
- rdf_construct/merge/formatters.py +426 -0
- rdf_construct/merge/merger.py +425 -0
- rdf_construct/merge/migrator.py +339 -0
- rdf_construct/merge/rules.py +377 -0
- rdf_construct/merge/splitter.py +1102 -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/refactor/__init__.py +72 -0
- rdf_construct/refactor/config.py +362 -0
- rdf_construct/refactor/deprecator.py +328 -0
- rdf_construct/refactor/formatters/__init__.py +8 -0
- rdf_construct/refactor/formatters/text.py +311 -0
- rdf_construct/refactor/renamer.py +294 -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.3.0.dist-info/METADATA +496 -0
- rdf_construct-0.3.0.dist-info/RECORD +110 -0
- rdf_construct-0.3.0.dist-info/WHEEL +4 -0
- rdf_construct-0.3.0.dist-info/entry_points.txt +3 -0
- rdf_construct-0.3.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"""PlantUML layout configuration for RDF class diagrams.
|
|
2
|
+
|
|
3
|
+
Provides control over diagram direction, spacing, grouping,
|
|
4
|
+
and other layout-related aspects.
|
|
5
|
+
|
|
6
|
+
Enhanced features:
|
|
7
|
+
- together: Group classes to be placed adjacent
|
|
8
|
+
- linetype: Orthogonal or polyline routing
|
|
9
|
+
- group_inheritance: Merge arrow heads for multiple subclasses
|
|
10
|
+
- layout_hints: Hidden links to influence positioning
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any, Literal, Optional
|
|
16
|
+
|
|
17
|
+
import yaml
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
LayoutDirection = Literal[
|
|
21
|
+
"top_to_bottom",
|
|
22
|
+
"bottom_to_top",
|
|
23
|
+
"left_to_right",
|
|
24
|
+
"right_to_left",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
LineType = Literal["ortho", "polyline", "spline"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class LayoutHint:
|
|
32
|
+
"""A hidden link hint to influence layout positioning.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
from_entity: Source entity CURIE (e.g., 'ies:Entity')
|
|
36
|
+
to_entity: Target entity CURIE (e.g., 'building:Building')
|
|
37
|
+
direction: Optional direction hint ('up', 'down', 'left', 'right')
|
|
38
|
+
weight: Number of hidden links (higher = stronger influence)
|
|
39
|
+
"""
|
|
40
|
+
from_entity: str
|
|
41
|
+
to_entity: str
|
|
42
|
+
direction: Optional[str] = None
|
|
43
|
+
weight: int = 1
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class LayoutConfig:
|
|
47
|
+
"""Layout configuration for PlantUML diagrams.
|
|
48
|
+
|
|
49
|
+
Attributes:
|
|
50
|
+
name: Layout identifier
|
|
51
|
+
description: Human-readable description
|
|
52
|
+
direction: Primary layout direction
|
|
53
|
+
hide_empty_members: Whether to hide classes with no attributes/methods
|
|
54
|
+
spacing: Spacing configuration dict
|
|
55
|
+
group_by_namespace: Whether to group classes by namespace
|
|
56
|
+
arrow_direction: Direction hint for arrows ('up', 'down', 'left', 'right')
|
|
57
|
+
linetype: Line routing style ('ortho', 'polyline', 'spline')
|
|
58
|
+
group_inheritance: Threshold for merging inheritance arrows (0 = disabled)
|
|
59
|
+
together_groups: List of class groups to place adjacent
|
|
60
|
+
layout_hints: List of hidden link hints for positioning
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(self, name: str, config: dict[str, Any]):
|
|
64
|
+
"""Initialize layout configuration.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
name: Layout identifier
|
|
68
|
+
config: Layout configuration dictionary from YAML
|
|
69
|
+
"""
|
|
70
|
+
self.name = name
|
|
71
|
+
self.description = config.get("description", "")
|
|
72
|
+
|
|
73
|
+
# Layout direction
|
|
74
|
+
direction_str = config.get("direction", "top_to_bottom")
|
|
75
|
+
self.direction: LayoutDirection = self._validate_direction(direction_str)
|
|
76
|
+
|
|
77
|
+
# Display options
|
|
78
|
+
self.hide_empty_members = config.get("hide_empty_members", False)
|
|
79
|
+
self.show_arrows = config.get("show_arrows", True)
|
|
80
|
+
|
|
81
|
+
# Arrow direction hints for hierarchy
|
|
82
|
+
arrow_dir = config.get("arrow_direction", "up")
|
|
83
|
+
self.arrow_direction = self._validate_arrow_direction(arrow_dir)
|
|
84
|
+
|
|
85
|
+
# Grouping
|
|
86
|
+
self.group_by_namespace = config.get("group_by_namespace", False)
|
|
87
|
+
|
|
88
|
+
# Spacing (PlantUML skinparam settings)
|
|
89
|
+
self.spacing = config.get("spacing", {})
|
|
90
|
+
|
|
91
|
+
# NEW: Line type for edge routing
|
|
92
|
+
linetype = config.get("linetype")
|
|
93
|
+
self.linetype: Optional[LineType] = self._validate_linetype(linetype)
|
|
94
|
+
|
|
95
|
+
# NEW: Group inheritance threshold
|
|
96
|
+
self.group_inheritance = config.get("group_inheritance", 0)
|
|
97
|
+
|
|
98
|
+
# NEW: Together groups - classes to place adjacent
|
|
99
|
+
self.together_groups: list[list[str]] = config.get("together", [])
|
|
100
|
+
|
|
101
|
+
# NEW: Layout hints - hidden links to influence positioning
|
|
102
|
+
self.layout_hints: list[LayoutHint] = []
|
|
103
|
+
for hint in config.get("layout_hints", []):
|
|
104
|
+
if isinstance(hint, dict) and "from" in hint and "to" in hint:
|
|
105
|
+
self.layout_hints.append(LayoutHint(
|
|
106
|
+
from_entity=hint["from"],
|
|
107
|
+
to_entity=hint["to"],
|
|
108
|
+
direction=hint.get("direction"),
|
|
109
|
+
weight=hint.get("weight", 1),
|
|
110
|
+
))
|
|
111
|
+
|
|
112
|
+
def _validate_direction(self, direction: str) -> LayoutDirection:
|
|
113
|
+
"""Validate and normalize layout direction.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
direction: Direction string from config
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Validated LayoutDirection
|
|
120
|
+
"""
|
|
121
|
+
direction_map = {
|
|
122
|
+
"top_to_bottom": "top_to_bottom",
|
|
123
|
+
"ttb": "top_to_bottom",
|
|
124
|
+
"tb": "top_to_bottom",
|
|
125
|
+
"bottom_to_top": "bottom_to_top",
|
|
126
|
+
"btt": "bottom_to_top",
|
|
127
|
+
"bt": "bottom_to_top",
|
|
128
|
+
"left_to_right": "left_to_right",
|
|
129
|
+
"ltr": "left_to_right",
|
|
130
|
+
"lr": "left_to_right",
|
|
131
|
+
"right_to_left": "right_to_left",
|
|
132
|
+
"rtl": "right_to_left",
|
|
133
|
+
"rl": "right_to_left",
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
normalized = direction_map.get(direction.lower(), "top_to_bottom")
|
|
137
|
+
return normalized # type: ignore
|
|
138
|
+
|
|
139
|
+
def _validate_arrow_direction(self, arrow_dir: str) -> str:
|
|
140
|
+
"""Validate arrow direction hint.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
arrow_dir: Arrow direction from config
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Validated arrow direction ('up', 'down', 'left', 'right')
|
|
147
|
+
"""
|
|
148
|
+
valid_directions = {"up", "down", "left", "right"}
|
|
149
|
+
if arrow_dir.lower() in valid_directions:
|
|
150
|
+
return arrow_dir.lower()
|
|
151
|
+
return "up" # Default: parents above children
|
|
152
|
+
|
|
153
|
+
def _validate_linetype(self, linetype: Optional[str]) -> Optional[LineType]:
|
|
154
|
+
"""Validate line type setting.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
linetype: Line type from config
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Validated LineType or None
|
|
161
|
+
"""
|
|
162
|
+
if linetype is None:
|
|
163
|
+
return None
|
|
164
|
+
valid_types = {"ortho", "polyline", "spline"}
|
|
165
|
+
if linetype.lower() in valid_types:
|
|
166
|
+
return linetype.lower() # type: ignore
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
def get_arrow_syntax(self, relationship_type: str) -> str:
|
|
170
|
+
"""Get PlantUML arrow syntax with direction hint.
|
|
171
|
+
|
|
172
|
+
For subclass relationships (inheritance), we can specify arrow
|
|
173
|
+
direction to influence layout. For example:
|
|
174
|
+
- '-up->' : child points up to parent
|
|
175
|
+
- '-down->' : parent points down to child
|
|
176
|
+
- '-->' : no direction hint
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
relationship_type: Type of relationship ('subclass', 'instance',
|
|
180
|
+
'object_property', etc.)
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
PlantUML arrow syntax with optional direction hint
|
|
184
|
+
"""
|
|
185
|
+
if not self.show_arrows:
|
|
186
|
+
return "--"
|
|
187
|
+
|
|
188
|
+
# Map relationship types to arrow styles
|
|
189
|
+
arrow_map = {
|
|
190
|
+
"subclass": "|>", # Inheritance (triangle)
|
|
191
|
+
"instance": "|>", # Instance-of (typically dotted)
|
|
192
|
+
"object_property": ">", # Association
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
arrow_glyph = arrow_map.get(relationship_type, ">")
|
|
196
|
+
|
|
197
|
+
# Add direction hint for hierarchical relationships
|
|
198
|
+
if relationship_type in ("subclass", "instance"):
|
|
199
|
+
if self.arrow_direction in ("up", "down", "left", "right"):
|
|
200
|
+
return f"-{self.arrow_direction}-{arrow_glyph}"
|
|
201
|
+
|
|
202
|
+
# Default: no direction hint
|
|
203
|
+
return f"-{arrow_glyph}"
|
|
204
|
+
|
|
205
|
+
def get_plantuml_directives(self) -> list[str]:
|
|
206
|
+
"""Generate PlantUML directives for layout control.
|
|
207
|
+
|
|
208
|
+
Note: PlantUML only reliably supports 'top to bottom direction' and
|
|
209
|
+
'left to right direction'. Other directions may not work as expected.
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
List of PlantUML directive strings (skinparam, etc.)
|
|
213
|
+
"""
|
|
214
|
+
directives = []
|
|
215
|
+
|
|
216
|
+
# Layout direction
|
|
217
|
+
# Note: Only top_to_bottom and left_to_right are reliably supported
|
|
218
|
+
direction_map = {
|
|
219
|
+
"top_to_bottom": "top to bottom direction",
|
|
220
|
+
"left_to_right": "left to right direction",
|
|
221
|
+
# These are not reliably supported by PlantUML:
|
|
222
|
+
# "bottom_to_top": "bottom to top direction",
|
|
223
|
+
# "right_to_left": "right to left direction",
|
|
224
|
+
}
|
|
225
|
+
if self.direction in direction_map:
|
|
226
|
+
directives.append(direction_map[self.direction])
|
|
227
|
+
|
|
228
|
+
# Hide empty members
|
|
229
|
+
if self.hide_empty_members:
|
|
230
|
+
directives.append("hide empty members")
|
|
231
|
+
|
|
232
|
+
# Line type (edge routing)
|
|
233
|
+
if self.linetype:
|
|
234
|
+
directives.append(f"skinparam linetype {self.linetype}")
|
|
235
|
+
|
|
236
|
+
# Group inheritance (merge arrow heads)
|
|
237
|
+
if self.group_inheritance and self.group_inheritance > 0:
|
|
238
|
+
directives.append(f"skinparam groupInheritance {self.group_inheritance}")
|
|
239
|
+
|
|
240
|
+
# Spacing settings
|
|
241
|
+
if self.spacing:
|
|
242
|
+
for key, value in self.spacing.items():
|
|
243
|
+
directives.append(f"skinparam {key} {value}")
|
|
244
|
+
|
|
245
|
+
return directives
|
|
246
|
+
|
|
247
|
+
def get_together_blocks(self, id_resolver: Optional[callable] = None) -> list[str]:
|
|
248
|
+
"""Generate PlantUML 'together' blocks for class grouping.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
id_resolver: Optional function to convert CURIEs to PlantUML identifiers.
|
|
252
|
+
If None, CURIEs are used as-is with colons replaced.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
List of PlantUML 'together' block strings
|
|
256
|
+
"""
|
|
257
|
+
if not self.together_groups:
|
|
258
|
+
return []
|
|
259
|
+
|
|
260
|
+
lines = []
|
|
261
|
+
for group in self.together_groups:
|
|
262
|
+
if not group:
|
|
263
|
+
continue
|
|
264
|
+
|
|
265
|
+
lines.append("together {")
|
|
266
|
+
for curie in group:
|
|
267
|
+
if id_resolver:
|
|
268
|
+
class_id = id_resolver(curie)
|
|
269
|
+
else:
|
|
270
|
+
# Simple conversion: replace : with . for PlantUML
|
|
271
|
+
class_id = curie.replace(":", ".")
|
|
272
|
+
lines.append(f" class {class_id}")
|
|
273
|
+
lines.append("}")
|
|
274
|
+
lines.append("")
|
|
275
|
+
|
|
276
|
+
return lines
|
|
277
|
+
|
|
278
|
+
def get_hidden_links(self, id_resolver: Optional[callable] = None) -> list[str]:
|
|
279
|
+
"""Generate PlantUML hidden links for layout hints.
|
|
280
|
+
|
|
281
|
+
Args:
|
|
282
|
+
id_resolver: Optional function to convert CURIEs to PlantUML identifiers.
|
|
283
|
+
If None, CURIEs are used as-is with colons replaced.
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
List of PlantUML hidden link strings
|
|
287
|
+
"""
|
|
288
|
+
if not self.layout_hints:
|
|
289
|
+
return []
|
|
290
|
+
|
|
291
|
+
lines = []
|
|
292
|
+
for hint in self.layout_hints:
|
|
293
|
+
if id_resolver:
|
|
294
|
+
from_id = id_resolver(hint.from_entity)
|
|
295
|
+
to_id = id_resolver(hint.to_entity)
|
|
296
|
+
else:
|
|
297
|
+
from_id = hint.from_entity.replace(":", ".")
|
|
298
|
+
to_id = hint.to_entity.replace(":", ".")
|
|
299
|
+
|
|
300
|
+
# Build arrow syntax
|
|
301
|
+
if hint.direction:
|
|
302
|
+
arrow = f"-[hidden,{hint.direction}]->"
|
|
303
|
+
else:
|
|
304
|
+
arrow = "-[hidden]->"
|
|
305
|
+
|
|
306
|
+
# Repeat for weight (more links = stronger influence)
|
|
307
|
+
for _ in range(hint.weight):
|
|
308
|
+
lines.append(f"{from_id} {arrow} {to_id}")
|
|
309
|
+
|
|
310
|
+
return lines
|
|
311
|
+
|
|
312
|
+
def __repr__(self) -> str:
|
|
313
|
+
return (
|
|
314
|
+
f"LayoutConfig(name={self.name!r}, "
|
|
315
|
+
f"direction={self.direction}, "
|
|
316
|
+
f"arrow_dir={self.arrow_direction}, "
|
|
317
|
+
f"linetype={self.linetype}, "
|
|
318
|
+
f"group_inheritance={self.group_inheritance}, "
|
|
319
|
+
f"together_groups={len(self.together_groups)}, "
|
|
320
|
+
f"layout_hints={len(self.layout_hints)})"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class LayoutConfigManager:
|
|
325
|
+
"""Manager for layout configurations.
|
|
326
|
+
|
|
327
|
+
Loads and manages YAML-based layout specifications with support
|
|
328
|
+
for multiple layouts and shared configuration via YAML anchors.
|
|
329
|
+
|
|
330
|
+
Attributes:
|
|
331
|
+
defaults: Default layout settings
|
|
332
|
+
layouts: Dictionary of available layout configurations
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
def __init__(self, yaml_path: Path | str):
|
|
336
|
+
"""Load layout configuration from a YAML file.
|
|
337
|
+
|
|
338
|
+
Args:
|
|
339
|
+
yaml_path: Path to YAML layout configuration file
|
|
340
|
+
"""
|
|
341
|
+
yaml_path = Path(yaml_path)
|
|
342
|
+
self.config = yaml.safe_load(yaml_path.read_text(encoding="utf-8"))
|
|
343
|
+
|
|
344
|
+
self.defaults = self.config.get("defaults", {}) or {}
|
|
345
|
+
|
|
346
|
+
# Load layouts
|
|
347
|
+
self.layouts = {}
|
|
348
|
+
for layout_name, layout_config in (
|
|
349
|
+
self.config.get("layouts", {}) or {}
|
|
350
|
+
).items():
|
|
351
|
+
self.layouts[layout_name] = LayoutConfig(layout_name, layout_config)
|
|
352
|
+
|
|
353
|
+
def get_layout(self, name: str) -> LayoutConfig:
|
|
354
|
+
"""Get a layout configuration by name.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
name: Layout identifier
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
LayoutConfig instance
|
|
361
|
+
|
|
362
|
+
Raises:
|
|
363
|
+
KeyError: If layout name not found
|
|
364
|
+
"""
|
|
365
|
+
if name not in self.layouts:
|
|
366
|
+
raise KeyError(
|
|
367
|
+
f"Layout '{name}' not found. Available layouts: "
|
|
368
|
+
f"{', '.join(self.layouts.keys())}"
|
|
369
|
+
)
|
|
370
|
+
return self.layouts[name]
|
|
371
|
+
|
|
372
|
+
def list_layouts(self) -> list[str]:
|
|
373
|
+
"""Get list of available layout names.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
List of layout identifier strings
|
|
377
|
+
"""
|
|
378
|
+
return list(self.layouts.keys())
|
|
379
|
+
|
|
380
|
+
def __repr__(self) -> str:
|
|
381
|
+
return f"LayoutConfigManager(layouts={list(self.layouts.keys())})"
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def load_layout_config(path: Path | str) -> LayoutConfigManager:
|
|
385
|
+
"""Load layout configuration from a YAML file.
|
|
386
|
+
|
|
387
|
+
Args:
|
|
388
|
+
path: Path to YAML layout configuration file
|
|
389
|
+
|
|
390
|
+
Returns:
|
|
391
|
+
LayoutConfigManager instance
|
|
392
|
+
"""
|
|
393
|
+
return LayoutConfigManager(path)
|