Coverage for physioblocks / io / configuration.py: 100%
28 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
« prev ^ index » next coverage.py v7.13.1, created at 2026-01-09 16:40 +0100
1# SPDX-FileCopyrightText: Copyright INRIA
2#
3# SPDX-License-Identifier: LGPL-3.0-only
4#
5# Copyright INRIA
6#
7# This file is part of PhysioBlocks, a library mostly developed by the
8# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
9#
10# Authors:
11# - Colin Drieu
12# - Dominique Chapelle
13# - François Kimmig
14# - Philippe Moireau
15#
16# PhysioBlocks is free software: you can redistribute it and/or modify it under the
17# terms of the GNU Lesser General Public License as published by the Free Software
18# Foundation, version 3 of the License.
19#
20# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
21# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
23#
24# You should have received a copy of the GNU Lesser General Public License along with
25# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
27"""
28Defines methods to save and load
29:class:`~physioblocks.configuration.base.Configuration` objects to a json file
31.. note::
33 It is possible to save and load ``.jsonc`` files and use ``//`` characters to
34 comment the file.
36 The comments are discarded when the file is loaded: there are only here to increase
37 the json readability.
39"""
41import json
42import os
43from pathlib import Path
44from typing import Any
46from physioblocks.configuration.base import Configuration
48# Key giving the type of the configured object
49_ITEM_TYPE_LABEL = "type"
51# Character delimiting a comment
52_COMMENT_CHAR = "//"
55class _JSONConfigEncoder(json.JSONEncoder):
56 """
57 Derive from the base JSONEncoder class to redefine the
58 encoding of Configuration and Configuration objects
59 """
61 def default(self, obj: Any) -> Any:
62 """
63 Overwrite the default encoder method.
65 :param obj: the object to encode
66 :type obj: Any
68 :return: the encoded object
69 :rtype: dict[str, obj]
70 """
72 if isinstance(obj, Configuration):
73 item_dict: dict[str, Any]
74 item_dict = {}
75 item_dict[_ITEM_TYPE_LABEL] = obj.label
76 item_dict.update(obj.configuration_items)
78 return item_dict
80 return super().default(obj)
83def write_json(file_path: str, config: Configuration) -> None:
84 """
85 Write the :class:`~physioblocks.configuration.base.Configuration` object
86 to a json file
88 :param file_path: the path of the file to read
89 :type file_path: str
91 :param config: the configuration to write
92 :type config: Configuration
93 """
94 config_json = json.dumps(config, cls=_JSONConfigEncoder, indent=4)
95 Path(file_path).write_text(config_json)
98def read_json(file_path: str) -> Any:
99 """
100 Read a :class:`~physioblocks.configuration.base.Configuration` from a json file
102 :param file_path: the path of the file to read
103 :type file_path: str
105 :return: the loaded configuration
106 :rtype: Configuration
107 """
108 json_txt = Path(file_path).read_text()
110 uncommented_lines = [
111 line.split(_COMMENT_CHAR, 1)[0] for line in json_txt.splitlines()
112 ]
113 uncommented_json_txt = os.linesep.join(uncommented_lines)
114 return json.loads(uncommented_json_txt, object_hook=_as_config)
117def _as_config(dict_obj: dict[Any, Any]) -> Any:
118 if _ITEM_TYPE_LABEL in dict_obj:
119 config_item = Configuration(
120 dict_obj[_ITEM_TYPE_LABEL],
121 {key: value for key, value in dict_obj.items() if key != _ITEM_TYPE_LABEL},
122 )
123 return config_item
125 return dict_obj