11import os
22import logging
3+ from typing import Any , Dict , Union
34from configparser import ConfigParser
45
6+ from deprecation import deprecated
7+ import tomlkit
8+
59from aw_core import dirs
10+ from aw_core .__about__ import __version__
611
712logger = logging .getLogger (__name__ )
813
914
15+ def _merge (a : dict , b : dict , path = None ):
16+ """
17+ Recursively merges b into a, with b taking precedence.
18+
19+ From: https://stackoverflow.com/a/7205107/965332
20+ """
21+ if path is None :
22+ path = []
23+ for key in b :
24+ if key in a :
25+ if isinstance (a [key ], dict ) and isinstance (b [key ], dict ):
26+ _merge (a [key ], b [key ], path + [str (key )])
27+ elif a [key ] == b [key ]:
28+ pass # same leaf value
29+ else :
30+ a [key ] = b [key ]
31+ else :
32+ a [key ] = b [key ]
33+ return a
34+
35+
36+ def _comment_out_toml (s : str ):
37+ return "\n " .join (["#" + line for line in s .split ("\n " )])
38+
39+
40+ def load_config_toml (
41+ appname : str , default_config : str
42+ ) -> Union [dict , tomlkit .container .Container ]:
43+ config_dir = dirs .get_config_dir (appname )
44+ config_file_path = os .path .join (config_dir , "{}.toml" .format (appname ))
45+
46+ # Run early to ensure input is valid toml before writing
47+ default_config_toml = tomlkit .parse (default_config )
48+
49+ # Override defaults from existing config file
50+ if os .path .isfile (config_file_path ):
51+ with open (config_file_path , "r" ) as f :
52+ config = f .read ()
53+ config_toml = tomlkit .parse (config )
54+ else :
55+ # TODO: If file doesn't exist, write with commented-out default config
56+ with open (config_file_path , "w" ) as f :
57+ f .write (_comment_out_toml (default_config ))
58+ config_toml = dict ()
59+
60+ config = _merge (default_config_toml , config_toml )
61+
62+ return config
63+
64+
65+ def save_config_toml (appname : str , config : str ) -> None :
66+ # Check that passed config string is valid toml
67+ assert tomlkit .parse (config )
68+
69+ config_dir = dirs .get_config_dir (appname )
70+ config_file_path = os .path .join (config_dir , "{}.toml" .format (appname ))
71+
72+ with open (config_file_path , "w" ) as f :
73+ f .write (config )
74+
75+
76+ @deprecated (
77+ details = "Use the load_config_toml function instead" ,
78+ deprecated_in = "0.4.2" ,
79+ current_version = __version__ ,
80+ )
1081def load_config (appname , default_config ):
1182 """
1283 Take the defaults, and if a config file exists, use the settings specified
@@ -15,11 +86,11 @@ def load_config(appname, default_config):
1586 config = default_config
1687
1788 config_dir = dirs .get_config_dir (appname )
18- config_file_path = os .path .join (config_dir , "{}.ini " .format (appname ))
89+ config_file_path = os .path .join (config_dir , "{}.toml " .format (appname ))
1990
2091 # Override defaults from existing config file
2192 if os .path .isfile (config_file_path ):
22- with open (config_file_path , 'r' ) as f :
93+ with open (config_file_path , "r" ) as f :
2394 config .read_file (f )
2495
2596 # Overwrite current config file (necessary in case new default would be added)
@@ -28,8 +99,13 @@ def load_config(appname, default_config):
2899 return config
29100
30101
102+ @deprecated (
103+ details = "Use the save_config_toml function instead" ,
104+ deprecated_in = "0.4.2" ,
105+ current_version = __version__ ,
106+ )
31107def save_config (appname , config ):
32108 config_dir = dirs .get_config_dir (appname )
33109 config_file_path = os .path .join (config_dir , "{}.ini" .format (appname ))
34- with open (config_file_path , 'w' ) as f :
110+ with open (config_file_path , "w" ) as f :
35111 config .write (f )
0 commit comments