5
5
6
6
import os
7
7
8
- from typing import Union
8
+ from typing import Iterable , Union
9
9
from pathlib import Path
10
10
11
11
from yaml import dump , Dumper , load , Loader
@@ -54,6 +54,7 @@ def __init__(self, config_file: Union[str, os.PathLike] = None):
54
54
if self ._config_file .exists ():
55
55
with self ._config_file .open (encoding = 'utf-8' ) as in_stream :
56
56
self ._doc = load (in_stream , Loader )
57
+ self ._validate ()
57
58
self ._file_exists = True
58
59
else :
59
60
self ._doc = dict (self ._defaults )
@@ -193,3 +194,37 @@ def _transition_config_file(self, config_file: Union[str, os.PathLike] = None):
193
194
config_path .unlink (missing_ok = True )
194
195
195
196
self .write ()
197
+
198
+ def _validate (self , keys : Iterable = None ) -> Union [list , None ]:
199
+
200
+ """Validates the current configuration by checking the dictionary
201
+ keys to make sure they match the keys in the default configuration.
202
+ This is a recursive method, initially called without arguments.
203
+
204
+ :return: list of bad key names or None if configuration keys are
205
+ correct.
206
+ """
207
+
208
+ bad_keys = []
209
+
210
+ if not keys :
211
+ for key in self ._doc :
212
+ bad_keys += self ._validate ((key ,))
213
+ if bad_keys :
214
+ raise KeyError (f'? { ", " .join (bad_keys )} key(s) not '
215
+ 'recognized' )
216
+ return None
217
+
218
+ current_defaults = self ._defaults
219
+
220
+ current_doc = self ._doc
221
+
222
+ for key in keys :
223
+ current_defaults = current_defaults [key ]
224
+ current_doc = current_doc [key ]
225
+
226
+ if isinstance (current_doc , dict ):
227
+ for key in current_doc :
228
+ bad_keys += self ._validate ([* keys , key ])
229
+
230
+ return bad_keys
0 commit comments