Bases: SpecStore
Model store class for DICOM specification models storage in JSON format.
Provides methods to load and save DICOM specification models to and from JSON files.
Inherits logging from SpecStore.
Source code in src/dcmspec/json_spec_store.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 | class JSONSpecStore(SpecStore):
"""Model store class for DICOM specification models storage in JSON format.
Provides methods to load and save DICOM specification models to and from JSON files.
Inherits logging from SpecStore.
"""
def load(self, path: str) -> SpecModel:
"""Load a specification model from a JSON file.
Args:
path (str): The path to the JSON file to load.
Returns:
SpecModel: The specification model containing both metadata and content nodes.
Raises:
RuntimeError: If the file cannot be read, parsed, or has an invalid structure.
"""
try:
importer = JsonImporter()
with open(path, "r", encoding="utf-8") as json_file:
root = importer.read(json_file)
# Check that the root node is named "dcmspec"
if root.name != "dcmspec":
raise RuntimeError(f"Invalid model structure in JSON file {path}: root node must be 'dcmspec'.")
# Search for metadata and content nodes directly under the root
metadata = next((node for node in root.children if node.name == "metadata"), None)
content = next((node for node in root.children if node.name == "content"), None)
if metadata is None or content is None:
raise RuntimeError(
f"Invalid model structure in JSON file {path}: "
f"Both 'metadata' and 'content' nodes must be present as children of 'dcmspec'."
)
# Detach the model nodes from the file root node
metadata.parent = None
content.parent = None
# Convert keys of column_to_attr back to integers if present in metadata
if "column_to_attr" in metadata.__dict__:
metadata.column_to_attr = {int(k): v for k, v in metadata.column_to_attr.items()}
return SpecModel(metadata=metadata, content=content)
except OSError as e:
raise RuntimeError(f"Failed to read model data from JSON file {path}: {e}") from e
except json.JSONDecodeError as e:
raise RuntimeError(f"Failed to parse JSON file {path}: {e}") from e
def save(self, model: SpecModel, path: str) -> None:
"""Save a specification model to a JSON file.
Args:
model (SpecModel): The model object (an instance of SpecModel or a derived class)
containing metadata and content nodes to save.
path (str): The path to the JSON file to write.
Returns:
None
Raises:
RuntimeError: If the file cannot be written.
"""
# Create the destination folder if it does not exist
dir_name = os.path.dirname(path)
if dir_name:
os.makedirs(dir_name, exist_ok=True)
# Create a new root node "dcmspec"
root_node = Node("dcmspec")
# Temporarily add the model's metadata and content as children of the new root node
model.metadata.parent = root_node
model.content.parent = root_node
try:
exporter = JsonExporter(indent=4, sort_keys=False)
with open(path, "w", encoding="utf-8") as json_file:
exporter.write(root_node, json_file)
self.logger.info(f"Attribute model saved as JSON to {path}")
except OSError as e:
raise RuntimeError(f"Failed to write JSON file {path}: {e}") from e
# Detach the temporary children to leave the model unchanged
model.metadata.parent = None
model.content.parent = None
|
load(path)
Load a specification model from a JSON file.
PARAMETER |
DESCRIPTION |
path
|
The path to the JSON file to load.
TYPE:
str
|
RETURNS |
DESCRIPTION |
SpecModel
|
The specification model containing both metadata and content nodes.
TYPE:
SpecModel
|
RAISES |
DESCRIPTION |
RuntimeError
|
If the file cannot be read, parsed, or has an invalid structure.
|
Source code in src/dcmspec/json_spec_store.py
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 | def load(self, path: str) -> SpecModel:
"""Load a specification model from a JSON file.
Args:
path (str): The path to the JSON file to load.
Returns:
SpecModel: The specification model containing both metadata and content nodes.
Raises:
RuntimeError: If the file cannot be read, parsed, or has an invalid structure.
"""
try:
importer = JsonImporter()
with open(path, "r", encoding="utf-8") as json_file:
root = importer.read(json_file)
# Check that the root node is named "dcmspec"
if root.name != "dcmspec":
raise RuntimeError(f"Invalid model structure in JSON file {path}: root node must be 'dcmspec'.")
# Search for metadata and content nodes directly under the root
metadata = next((node for node in root.children if node.name == "metadata"), None)
content = next((node for node in root.children if node.name == "content"), None)
if metadata is None or content is None:
raise RuntimeError(
f"Invalid model structure in JSON file {path}: "
f"Both 'metadata' and 'content' nodes must be present as children of 'dcmspec'."
)
# Detach the model nodes from the file root node
metadata.parent = None
content.parent = None
# Convert keys of column_to_attr back to integers if present in metadata
if "column_to_attr" in metadata.__dict__:
metadata.column_to_attr = {int(k): v for k, v in metadata.column_to_attr.items()}
return SpecModel(metadata=metadata, content=content)
except OSError as e:
raise RuntimeError(f"Failed to read model data from JSON file {path}: {e}") from e
except json.JSONDecodeError as e:
raise RuntimeError(f"Failed to parse JSON file {path}: {e}") from e
|
save(model, path)
Save a specification model to a JSON file.
PARAMETER |
DESCRIPTION |
model
|
The model object (an instance of SpecModel or a derived class)
containing metadata and content nodes to save.
TYPE:
SpecModel
|
path
|
The path to the JSON file to write.
TYPE:
str
|
RAISES |
DESCRIPTION |
RuntimeError
|
If the file cannot be written.
|
Source code in src/dcmspec/json_spec_store.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 | def save(self, model: SpecModel, path: str) -> None:
"""Save a specification model to a JSON file.
Args:
model (SpecModel): The model object (an instance of SpecModel or a derived class)
containing metadata and content nodes to save.
path (str): The path to the JSON file to write.
Returns:
None
Raises:
RuntimeError: If the file cannot be written.
"""
# Create the destination folder if it does not exist
dir_name = os.path.dirname(path)
if dir_name:
os.makedirs(dir_name, exist_ok=True)
# Create a new root node "dcmspec"
root_node = Node("dcmspec")
# Temporarily add the model's metadata and content as children of the new root node
model.metadata.parent = root_node
model.content.parent = root_node
try:
exporter = JsonExporter(indent=4, sort_keys=False)
with open(path, "w", encoding="utf-8") as json_file:
exporter.write(root_node, json_file)
self.logger.info(f"Attribute model saved as JSON to {path}")
except OSError as e:
raise RuntimeError(f"Failed to write JSON file {path}: {e}") from e
# Detach the temporary children to leave the model unchanged
model.metadata.parent = None
model.content.parent = None
|