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

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/>. 

26 

27""" 

28Defines methods to save and load 

29:class:`~physioblocks.configuration.base.Configuration` objects to a json file 

30 

31.. note:: 

32 

33 It is possible to save and load ``.jsonc`` files and use ``//`` characters to 

34 comment the file. 

35 

36 The comments are discarded when the file is loaded: there are only here to increase 

37 the json readability. 

38 

39""" 

40 

41import json 

42import os 

43from pathlib import Path 

44from typing import Any 

45 

46from physioblocks.configuration.base import Configuration 

47 

48# Key giving the type of the configured object 

49_ITEM_TYPE_LABEL = "type" 

50 

51# Character delimiting a comment 

52_COMMENT_CHAR = "//" 

53 

54 

55class _JSONConfigEncoder(json.JSONEncoder): 

56 """ 

57 Derive from the base JSONEncoder class to redefine the 

58 encoding of Configuration and Configuration objects 

59 """ 

60 

61 def default(self, obj: Any) -> Any: 

62 """ 

63 Overwrite the default encoder method. 

64 

65 :param obj: the object to encode 

66 :type obj: Any 

67 

68 :return: the encoded object 

69 :rtype: dict[str, obj] 

70 """ 

71 

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) 

77 

78 return item_dict 

79 

80 return super().default(obj) 

81 

82 

83def write_json(file_path: str, config: Configuration) -> None: 

84 """ 

85 Write the :class:`~physioblocks.configuration.base.Configuration` object 

86 to a json file 

87 

88 :param file_path: the path of the file to read 

89 :type file_path: str 

90 

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) 

96 

97 

98def read_json(file_path: str) -> Any: 

99 """ 

100 Read a :class:`~physioblocks.configuration.base.Configuration` from a json file 

101 

102 :param file_path: the path of the file to read 

103 :type file_path: str 

104 

105 :return: the loaded configuration 

106 :rtype: Configuration 

107 """ 

108 json_txt = Path(file_path).read_text() 

109 

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) 

115 

116 

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 

124 

125 return dict_obj