@@ -31,28 +31,31 @@ def bool_representer(dumper, value):
31
31
text = "False"
32
32
return dumper .represent_scalar ('tag:yaml.org,2002:bool' , text )
33
33
34
+
34
35
class UpgradeAction (Enum ):
35
36
"""Upgrade action"""
36
37
37
38
ADD_KEY = "add"
38
39
REMOVE_KEY = "remove"
40
+ FORMAT_ONLY = "format_only"
39
41
40
42
class ConfigurationDumper (yaml .Dumper ):
41
43
"""Custom dumper to add indent before list items hyphens."""
42
44
43
45
def increase_indent (self , flow = False , indentless = False ):
44
46
return super (ConfigurationDumper , self ).increase_indent (flow , False )
45
47
48
+
49
+ ConfigurationDumper .add_representer (bool , bool_representer )
50
+
51
+
46
52
class ConfigurationUpgrader :
47
53
"""This class enables to bulk upgrade configuration files by adding or removing keys."""
48
54
49
- __dumper : ConfigurationDumper
50
55
__logger : Logger
51
56
__sections : dict
52
57
53
58
def __init__ (self , logger : Logger ):
54
- self .__dumper = ConfigurationDumper
55
- self .__dumper .add_representer (bool , bool_representer )
56
59
self .__logger = logger
57
60
self .__sections = cast (dict , ConfigurationValidator .allowed_keys (group = True ))
58
61
@@ -68,42 +71,52 @@ def write_node(self, k: str, value: Any, yaml_file: IO, indent_size: int = 2):
68
71
indent = indent_size ,
69
72
line_break = '\n ' ,
70
73
sort_keys = False ,
71
- Dumper = self . __dumper
74
+ Dumper = ConfigurationDumper
72
75
).replace (
73
76
'\n ' ,
74
77
'\n ' + indent_str
75
78
)
76
79
if yaml_node .endswith ('\n ' + indent_str ):
77
80
yaml_node = yaml_node [:- (indent_size + 1 )]
78
81
else :
79
- yaml_node = " " + yaml .representer .BaseRepresenter ().represent_data (value ).value
82
+ yaml_node = yaml .dump (
83
+ value ,
84
+ indent = 0 ,
85
+ Dumper = ConfigurationDumper ,
86
+ explicit_start = None ,
87
+ explicit_end = None
88
+ )
89
+ if yaml_node .endswith ('...\n ' ):
90
+ yaml_node = yaml_node [:- 4 ]
91
+ yaml_node = ' ' + yaml_node .strip ()
80
92
yaml_file .write (yaml_node )
81
93
yaml_file .write ('\n ' )
82
94
83
95
def upgrade (
84
96
self ,
85
97
file_path : Path ,
86
98
action : UpgradeAction ,
87
- key : str ,
99
+ key : str = None ,
88
100
value : str = None ,
89
101
value_type : str = "str"
90
102
) -> None :
91
103
"""Apply an upgrade to the given configuration file."""
92
104
self .__logger .debug ("Upgrading file %s ..." , file_path )
93
105
key_path = None
94
- if action == UpgradeAction .ADD_KEY :
95
- self .__logger .debug ("Add key `%s` with value `%s`" , key , value )
96
- elif action == UpgradeAction .REMOVE_KEY :
97
- print (f"Remove key `{ key } `" )
98
- key_path = key .split ('.' )
99
- parsed_value = value
100
- if value_type is not None :
101
- type_v = locate (value_type )
102
- if callable (type_v ):
103
- parsed_value = type_v (value )
104
-
105
- if key_path is None :
106
- raise ValueError ("The `key` must be a valid string" )
106
+ if action != UpgradeAction .FORMAT_ONLY :
107
+ if action == UpgradeAction .ADD_KEY :
108
+ self .__logger .debug ("Add key `%s` with value `%s`" , key , value )
109
+ elif action == UpgradeAction .REMOVE_KEY :
110
+ print (f"Remove key `{ key } `" )
111
+ key_path = key .split ('.' )
112
+ parsed_value = value
113
+ if value_type is not None :
114
+ type_v = locate (value_type )
115
+ if callable (type_v ):
116
+ parsed_value = type_v (value )
117
+
118
+ if key_path is None and action != UpgradeAction .FORMAT_ONLY :
119
+ raise ValueError ("The `key` must be a valid string" )
107
120
108
121
conf = None
109
122
file_comment = None
@@ -126,36 +139,36 @@ def upgrade(
126
139
file_comment = file_comment .strip () # removes potential eol at the end
127
140
128
141
yaml_file .seek (0 )
129
-
130
142
yaml_content = yaml_file .read ()
131
143
conf = yaml .safe_load (yaml_content )
132
144
node = conf
133
- for i , key in enumerate (key_path ):
134
- is_leaf = i == len (key_path )- 1
135
- # if node does not exist create it
136
- if not key in node .keys ():
137
- if action == UpgradeAction .ADD_KEY :
138
- if is_leaf :
145
+ if action != UpgradeAction .FORMAT_ONLY :
146
+ for i , key in enumerate (key_path ):
147
+ is_leaf = i == len (key_path )- 1
148
+ # if node does not exist create it
149
+ if not key in node .keys ():
150
+ if action == UpgradeAction .ADD_KEY :
151
+ if is_leaf :
152
+ node [key ] = parsed_value
153
+ else :
154
+ new_branch = {}
155
+ new_node = new_branch
156
+ new_key_path = key_path [i + 1 :]
157
+ for j , new_key in enumerate (new_key_path ):
158
+ is_leaf = j == len (new_key_path ) - 1
159
+ new_node [new_key ] = parsed_value if is_leaf else {}
160
+ new_node = new_node [new_key ]
161
+ node [key ] = new_branch
162
+ elif is_leaf :
163
+ if action == UpgradeAction .REMOVE_KEY :
164
+ del node [key ]
165
+ elif action == UpgradeAction .ADD_KEY :
139
166
node [key ] = parsed_value
140
- else :
141
- new_branch = {}
142
- new_node = new_branch
143
- new_key_path = key_path [i + 1 :]
144
- for j , new_key in enumerate (new_key_path ):
145
- is_leaf = j == len (new_key_path ) - 1
146
- new_node [new_key ] = parsed_value if is_leaf else {}
147
- new_node = new_node [new_key ]
148
- node [key ] = new_branch
149
- elif is_leaf :
150
- if action == UpgradeAction .REMOVE_KEY :
151
- del node [key ]
152
- else :
153
- node [key ] = parsed_value
154
- # go next node in child tree
155
- if is_leaf :
156
- break
167
+ # go next node in child tree
168
+ if is_leaf :
169
+ break
157
170
158
- node = node [key ]
171
+ node = node [key ]
159
172
160
173
with open (file_path , 'w' , encoding = "utf-8" ) as yaml_file :
161
174
if file_comment is not None :
0 commit comments