pyegeria 5.4.0.14__py3-none-any.whl → 5.4.0.15__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.
- commands/cat/debug_log +540 -0
- commands/cat/list_format_set.py +9 -3
- pyegeria/_output_format_models.py +373 -0
- pyegeria/_output_formats.py +478 -190
- pyegeria/collection_manager_omvs.py +1 -1
- pyegeria/governance_officer_omvs.py +2 -2
- pyegeria/load_config.py +38 -13
- pyegeria/logging_configuration.py +2 -2
- {pyegeria-5.4.0.14.dist-info → pyegeria-5.4.0.15.dist-info}/METADATA +1 -1
- {pyegeria-5.4.0.14.dist-info → pyegeria-5.4.0.15.dist-info}/RECORD +13 -14
- md_processing/dr-egeria-outbox/DataStruct-2025-07-29-20-49-16.py +0 -8
- md_processing/dr-egeria-outbox/Mandy-DataStruct-2025-07-29-15-54-45.md +0 -19
- pyegeria/dr.egeria spec.md +0 -9
- {pyegeria-5.4.0.14.dist-info → pyegeria-5.4.0.15.dist-info}/LICENSE +0 -0
- {pyegeria-5.4.0.14.dist-info → pyegeria-5.4.0.15.dist-info}/WHEEL +0 -0
- {pyegeria-5.4.0.14.dist-info → pyegeria-5.4.0.15.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,373 @@
|
|
1
|
+
"""
|
2
|
+
SPDX-License-Identifier: Apache-2.0
|
3
|
+
Copyright Contributors to the ODPi Egeria project.
|
4
|
+
|
5
|
+
This module defines Pydantic models for output format sets used in pyegeria.
|
6
|
+
|
7
|
+
These models provide a structured way to define and validate output formats
|
8
|
+
for different types of data, supporting composition and reuse of formats.
|
9
|
+
|
10
|
+
The module defines the following models:
|
11
|
+
- Column: Represents a column in an output format with name, key, and format attributes.
|
12
|
+
- Format: Represents a format configuration with types and columns.
|
13
|
+
- ActionParameter: Represents a parameter for an action with function, user_params, and spec_params.
|
14
|
+
- FormatSet: Represents a complete format set with heading, description, aliases, annotations, formats, and actions.
|
15
|
+
- FormatSetDict: A dictionary of format sets with methods for backward compatibility.
|
16
|
+
|
17
|
+
These models are used in the `_output_formats.py` module to replace the dictionary-based
|
18
|
+
implementation of output format sets. The models provide several advantages:
|
19
|
+
- Type validation: The models ensure that the data has the correct types and structure.
|
20
|
+
- Composition: The models support composition of formats, allowing formats to be reused and combined.
|
21
|
+
- Documentation: The models provide clear documentation of the data structure.
|
22
|
+
- IDE support: The models provide better IDE support, including autocompletion and type hints.
|
23
|
+
|
24
|
+
Example usage:
|
25
|
+
```python
|
26
|
+
from pyegeria._output_format_models import Column, Format, FormatSet
|
27
|
+
|
28
|
+
# Create columns
|
29
|
+
columns = [
|
30
|
+
Column(name="Display Name", key="display_name"),
|
31
|
+
Column(name="Description", key="description", format=True),
|
32
|
+
]
|
33
|
+
|
34
|
+
# Create a format
|
35
|
+
format = Format(
|
36
|
+
types=["TABLE", "DICT"],
|
37
|
+
columns=columns,
|
38
|
+
)
|
39
|
+
|
40
|
+
# Create a format set
|
41
|
+
format_set = FormatSet(
|
42
|
+
heading="Example Format Set",
|
43
|
+
description="An example format set",
|
44
|
+
formats=[format],
|
45
|
+
)
|
46
|
+
|
47
|
+
# Convert to dictionary for backward compatibility
|
48
|
+
format_set_dict = format_set.dict()
|
49
|
+
```
|
50
|
+
|
51
|
+
The models are designed to be backward compatible with the existing dictionary-based
|
52
|
+
implementation. The `FormatSet` class has a `get` method that mimics the behavior of a
|
53
|
+
dictionary, and the `FormatSetDict` class provides dictionary-like access to the format sets.
|
54
|
+
"""
|
55
|
+
|
56
|
+
import json
|
57
|
+
import os
|
58
|
+
from pathlib import Path
|
59
|
+
from typing import Dict, List, Optional, Union, Any
|
60
|
+
from pydantic import BaseModel, Field, validator
|
61
|
+
from loguru import logger
|
62
|
+
|
63
|
+
def save_format_sets_to_json(format_sets: Dict[str, 'FormatSet'], file_path: str) -> None:
|
64
|
+
"""
|
65
|
+
Save format sets to a JSON file.
|
66
|
+
|
67
|
+
Args:
|
68
|
+
format_sets: The format sets to save
|
69
|
+
file_path: The path to save the file to
|
70
|
+
"""
|
71
|
+
# Convert FormatSet objects to dictionaries
|
72
|
+
serializable_dict = {key: value.dict() for key, value in format_sets.items()}
|
73
|
+
|
74
|
+
# Create directory if it doesn't exist
|
75
|
+
os.makedirs(os.path.dirname(os.path.abspath(file_path)), exist_ok=True)
|
76
|
+
|
77
|
+
# Write to file
|
78
|
+
try:
|
79
|
+
with open(file_path, 'w') as f:
|
80
|
+
json.dump(serializable_dict, f, indent=2)
|
81
|
+
logger.info(f"Format sets saved to {file_path}")
|
82
|
+
except Exception as e:
|
83
|
+
logger.error(f"Error saving format sets to {file_path}: {e}")
|
84
|
+
raise
|
85
|
+
|
86
|
+
def load_format_sets_from_json(file_path: str) -> Dict[str, 'FormatSet']:
|
87
|
+
"""
|
88
|
+
Load format sets from a JSON file.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
file_path: The path to load the file from
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
Dict[str, FormatSet]: The loaded format sets
|
95
|
+
"""
|
96
|
+
try:
|
97
|
+
with open(file_path, 'r') as f:
|
98
|
+
data = json.load(f)
|
99
|
+
|
100
|
+
# Convert dictionaries to FormatSet objects
|
101
|
+
format_sets = {}
|
102
|
+
for key, value in data.items():
|
103
|
+
format_sets[key] = FormatSet(**value)
|
104
|
+
|
105
|
+
logger.info(f"Format sets loaded from {file_path}")
|
106
|
+
return format_sets
|
107
|
+
except Exception as e:
|
108
|
+
logger.error(f"Error loading format sets from {file_path}: {e}")
|
109
|
+
raise
|
110
|
+
|
111
|
+
class Column(BaseModel):
|
112
|
+
"""
|
113
|
+
Represents a column in an output format.
|
114
|
+
|
115
|
+
Attributes:
|
116
|
+
name: The display name of the column
|
117
|
+
key: The key used to access the column's value in the data
|
118
|
+
format: Whether the column's value should be formatted
|
119
|
+
"""
|
120
|
+
name: str
|
121
|
+
key: str
|
122
|
+
format: bool = False
|
123
|
+
|
124
|
+
class Format(BaseModel):
|
125
|
+
"""
|
126
|
+
Represents a format configuration with types and columns.
|
127
|
+
|
128
|
+
Attributes:
|
129
|
+
types: The output types this format supports (e.g., "DICT", "TABLE", "ALL")
|
130
|
+
columns: The columns to include in the output
|
131
|
+
"""
|
132
|
+
types: List[str]
|
133
|
+
columns: List[Union[Column, Dict[str, Any]]]
|
134
|
+
|
135
|
+
@validator('columns', pre=True)
|
136
|
+
def validate_columns(cls, v):
|
137
|
+
"""Convert dictionary columns to Column objects."""
|
138
|
+
result = []
|
139
|
+
for item in v:
|
140
|
+
if isinstance(item, dict):
|
141
|
+
result.append(Column(**item))
|
142
|
+
else:
|
143
|
+
result.append(item)
|
144
|
+
return result
|
145
|
+
|
146
|
+
def dict(self, *args, **kwargs):
|
147
|
+
"""Override dict method to convert Column objects back to dictionaries."""
|
148
|
+
result = super().dict(*args, **kwargs)
|
149
|
+
result['columns'] = [
|
150
|
+
column if isinstance(column, dict) else column.dict()
|
151
|
+
for column in self.columns
|
152
|
+
]
|
153
|
+
return result
|
154
|
+
|
155
|
+
class ActionParameter(BaseModel):
|
156
|
+
"""
|
157
|
+
Represents a parameter for an action.
|
158
|
+
|
159
|
+
Attributes:
|
160
|
+
function: The function to call
|
161
|
+
user_params: Parameters that can be provided by the user
|
162
|
+
spec_params: Parameters that are fixed for this action
|
163
|
+
"""
|
164
|
+
function: str
|
165
|
+
user_params: List[str] = Field(default_factory=list)
|
166
|
+
spec_params: Dict[str, Any] = Field(default_factory=dict)
|
167
|
+
|
168
|
+
class FormatSet(BaseModel):
|
169
|
+
"""
|
170
|
+
Represents a complete format set with heading, description, aliases, annotations, formats, and actions.
|
171
|
+
|
172
|
+
Attributes:
|
173
|
+
heading: A title for the format set
|
174
|
+
description: A description of what the format set is for
|
175
|
+
aliases: Alternative names that can be used to reference this format set
|
176
|
+
annotations: Additional metadata, like wiki links
|
177
|
+
formats: A list of format configurations
|
178
|
+
action: Optional actions associated with the format set
|
179
|
+
"""
|
180
|
+
heading: str
|
181
|
+
description: str
|
182
|
+
aliases: List[str] = Field(default_factory=list)
|
183
|
+
annotations: Dict[str, List[str]] = Field(default_factory=dict)
|
184
|
+
formats: List[Union[Format, Dict[str, Any]]]
|
185
|
+
action: Optional[List[Union[ActionParameter, Dict[str, Any]]]] = None
|
186
|
+
|
187
|
+
@validator('formats', pre=True)
|
188
|
+
def validate_formats(cls, v):
|
189
|
+
"""Convert dictionary formats to Format objects."""
|
190
|
+
result = []
|
191
|
+
for item in v:
|
192
|
+
if isinstance(item, dict):
|
193
|
+
result.append(Format(**item))
|
194
|
+
else:
|
195
|
+
result.append(item)
|
196
|
+
return result
|
197
|
+
|
198
|
+
@validator('action', pre=True)
|
199
|
+
def validate_action(cls, v):
|
200
|
+
"""Convert dictionary actions to ActionParameter objects."""
|
201
|
+
if v is None:
|
202
|
+
return None
|
203
|
+
result = []
|
204
|
+
for item in v:
|
205
|
+
if isinstance(item, dict):
|
206
|
+
result.append(ActionParameter(**item))
|
207
|
+
else:
|
208
|
+
result.append(item)
|
209
|
+
return result
|
210
|
+
|
211
|
+
def dict(self, *args, **kwargs):
|
212
|
+
"""Override dict method to convert nested objects back to dictionaries."""
|
213
|
+
result = super().dict(*args, **kwargs)
|
214
|
+
result['formats'] = [
|
215
|
+
format if isinstance(format, dict) else format.dict()
|
216
|
+
for format in self.formats
|
217
|
+
]
|
218
|
+
if self.action:
|
219
|
+
result['action'] = [
|
220
|
+
action if isinstance(action, dict) else action.dict()
|
221
|
+
for action in self.action
|
222
|
+
]
|
223
|
+
return result
|
224
|
+
|
225
|
+
def get(self, key, default=None):
|
226
|
+
"""
|
227
|
+
Dictionary-like get method for backward compatibility.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
key: The key to look up
|
231
|
+
default: The default value to return if the key is not found
|
232
|
+
|
233
|
+
Returns:
|
234
|
+
The value for the key if found, otherwise the default value
|
235
|
+
"""
|
236
|
+
if hasattr(self, key):
|
237
|
+
return getattr(self, key)
|
238
|
+
return default
|
239
|
+
|
240
|
+
class FormatSetDict(Dict[str, FormatSet]):
|
241
|
+
"""
|
242
|
+
A dictionary of format sets, with methods for backward compatibility.
|
243
|
+
|
244
|
+
This class allows the format sets to be accessed like a dictionary,
|
245
|
+
while providing the validation and structure of Pydantic models.
|
246
|
+
|
247
|
+
It also provides the ability to find format sets by either name or alias,
|
248
|
+
making it easier to work with format sets without knowing their exact name.
|
249
|
+
"""
|
250
|
+
def __init__(self, *args, **kwargs):
|
251
|
+
super().__init__(*args, **kwargs)
|
252
|
+
|
253
|
+
def find_by_name_or_alias(self, key, default=None):
|
254
|
+
"""
|
255
|
+
Find a format set by either name or alias.
|
256
|
+
|
257
|
+
This method first checks if the key exists directly in the dictionary.
|
258
|
+
If not found, it searches through all format sets to find one with a matching alias.
|
259
|
+
|
260
|
+
Args:
|
261
|
+
key: The name or alias to look up
|
262
|
+
default: The default value to return if the key is not found
|
263
|
+
|
264
|
+
Returns:
|
265
|
+
FormatSet: The format set if found, otherwise the default value
|
266
|
+
"""
|
267
|
+
# First try to find by name (key)
|
268
|
+
format_set = super().get(key, None)
|
269
|
+
|
270
|
+
# If not found by name, try to find by alias
|
271
|
+
if format_set is None:
|
272
|
+
for value in self.values():
|
273
|
+
if key in value.aliases:
|
274
|
+
format_set = value
|
275
|
+
break
|
276
|
+
|
277
|
+
# Return the format set if found, otherwise the default value
|
278
|
+
return format_set if format_set is not None else default
|
279
|
+
|
280
|
+
def get(self, key, default=None):
|
281
|
+
"""
|
282
|
+
Get a format set by name or alias.
|
283
|
+
|
284
|
+
This method first checks if the key exists directly in the dictionary.
|
285
|
+
If not found, it searches through all format sets to find one with a matching alias.
|
286
|
+
|
287
|
+
Args:
|
288
|
+
key: The name or alias to look up
|
289
|
+
default: The default value to return if the key is not found
|
290
|
+
|
291
|
+
Returns:
|
292
|
+
FormatSet: The format set if found, otherwise the default value
|
293
|
+
"""
|
294
|
+
return self.find_by_name_or_alias(key, default)
|
295
|
+
|
296
|
+
def values(self):
|
297
|
+
"""Get all format sets."""
|
298
|
+
return super().values()
|
299
|
+
|
300
|
+
def keys(self):
|
301
|
+
"""Get all format set names."""
|
302
|
+
return super().keys()
|
303
|
+
|
304
|
+
def items(self):
|
305
|
+
"""Get all format set items."""
|
306
|
+
return super().items()
|
307
|
+
|
308
|
+
def __getitem__(self, key):
|
309
|
+
"""
|
310
|
+
Get a format set by name or alias.
|
311
|
+
|
312
|
+
This method first checks if the key exists directly in the dictionary.
|
313
|
+
If not found, it searches through all format sets to find one with a matching alias.
|
314
|
+
If still not found, it raises a KeyError.
|
315
|
+
|
316
|
+
Args:
|
317
|
+
key: The name or alias to look up
|
318
|
+
|
319
|
+
Returns:
|
320
|
+
FormatSet: The format set if found
|
321
|
+
|
322
|
+
Raises:
|
323
|
+
KeyError: If the format set is not found by name or alias
|
324
|
+
"""
|
325
|
+
format_set = self.find_by_name_or_alias(key, None)
|
326
|
+
if format_set is None:
|
327
|
+
raise KeyError(key)
|
328
|
+
return format_set
|
329
|
+
|
330
|
+
def __setitem__(self, key, value):
|
331
|
+
"""Set a format set by name."""
|
332
|
+
if isinstance(value, dict):
|
333
|
+
value = FormatSet(**value)
|
334
|
+
super().__setitem__(key, value)
|
335
|
+
|
336
|
+
def __contains__(self, key):
|
337
|
+
"""
|
338
|
+
Check if a format set exists by name or alias.
|
339
|
+
|
340
|
+
Args:
|
341
|
+
key: The name or alias to check
|
342
|
+
|
343
|
+
Returns:
|
344
|
+
bool: True if the format set exists, False otherwise
|
345
|
+
"""
|
346
|
+
return self.find_by_name_or_alias(key, None) is not None
|
347
|
+
|
348
|
+
def to_dict(self):
|
349
|
+
"""Convert all format sets to dictionaries."""
|
350
|
+
return {key: value.dict() for key, value in self.items()}
|
351
|
+
|
352
|
+
def save_to_json(self, file_path: str) -> None:
|
353
|
+
"""
|
354
|
+
Save format sets to a JSON file.
|
355
|
+
|
356
|
+
Args:
|
357
|
+
file_path: The path to save the file to
|
358
|
+
"""
|
359
|
+
save_format_sets_to_json(self, file_path)
|
360
|
+
|
361
|
+
@classmethod
|
362
|
+
def load_from_json(cls, file_path: str) -> 'FormatSetDict':
|
363
|
+
"""
|
364
|
+
Load format sets from a JSON file.
|
365
|
+
|
366
|
+
Args:
|
367
|
+
file_path: The path to load the file from
|
368
|
+
|
369
|
+
Returns:
|
370
|
+
FormatSetDict: A new FormatSetDict instance with the loaded format sets
|
371
|
+
"""
|
372
|
+
format_sets = load_format_sets_from_json(file_path)
|
373
|
+
return cls(format_sets)
|