4
4
import os
5
5
import argparse
6
6
import sys
7
- from typing import NamedTuple , Dict , Any
8
- from types import SimpleNamespace
7
+ from typing import NamedTuple
9
8
10
9
# Temporary logging configuration
11
10
coloredlogs .install (level = "WARN" )
@@ -69,29 +68,6 @@ class Config(NamedTuple):
69
68
logLevel : LogLevelConfig
70
69
traefik : TraefikConfig
71
70
72
- def dict_to_simplenamespace (dict_obj ):
73
- """
74
- Recursively converts a nested dictionary into a SimpleNamespace object.
75
-
76
- Args:
77
- dict_obj (dict): The input dictionary to be converted.
78
-
79
- Returns:
80
- SimpleNamespace: The resulting SimpleNamespace object.
81
- """
82
- logging .info ("Converting dictionary to SimpleNamespace" )
83
- logging .debug (f"Input dictionary: { dict_obj } " )
84
- if isinstance (dict_obj , dict ):
85
- for key , value in dict_obj .items ():
86
- logging .debug (f"Processing key: { key } " )
87
- dict_obj [key ] = dict_to_simplenamespace (value )
88
- elif isinstance (dict_obj , list ):
89
- logging .debug (f"Processing list with { len (dict_obj )} items" )
90
- return [dict_to_simplenamespace (item ) for item in dict_obj ]
91
- result = SimpleNamespace (** dict_obj ) if isinstance (dict_obj , dict ) else dict_obj
92
- logging .debug (f"Resulting SimpleNamespace or value: { result } " )
93
- return result
94
-
95
71
def flatten_keys (d , parent_key = '' , sep = '.' ):
96
72
"""
97
73
Flattens a nested dictionary into a flat dictionary with concatenated keys.
@@ -113,6 +89,28 @@ def flatten_keys(d, parent_key='', sep='.'):
113
89
items .append ((new_key , v ))
114
90
return dict (items )
115
91
92
+ def merge_dicts (lhs , rhs ):
93
+ """
94
+ Recursively merges two dictionaries.
95
+ If there's a conflict, values from rhs will overwrite those from lhs.
96
+
97
+ Args:
98
+ lhs (dict): Left hand side dictionary to merge.
99
+ rhs (dict): Right hand side dictionary to merge.
100
+
101
+ Returns:
102
+ merged: The merged dictionary.
103
+ """
104
+ merged = lhs .copy ()
105
+
106
+ for key , value in rhs .items ():
107
+ if key in merged and isinstance (merged [key ], dict ) and isinstance (value , dict ):
108
+ merged [key ] = merge_dicts (merged [key ], value )
109
+ else :
110
+ merged [key ] = value
111
+
112
+ return merged
113
+
116
114
def parse_args (config ):
117
115
"""
118
116
Parses command line arguments based on the configuration.
@@ -132,7 +130,6 @@ def parse_args(config):
132
130
cli_key = key .replace ('..' , '.' ).lower () # Ensure CLI arguments are lowercase
133
131
parser .add_argument (f'--{ cli_key } ' ,
134
132
type = type (value ),
135
- default = value ,
136
133
help = f'Specify the { cli_key } value' )
137
134
args , unknown = parser .parse_known_args ()
138
135
@@ -150,14 +147,15 @@ def load_config() -> Config:
150
147
"""
151
148
logging .info ("Loading configuration from file" )
152
149
with open ('config.yaml' , "r" ) as file :
153
- config_data = yaml .safe_load (file )
154
- logging .debug ("Loaded initial configuration: %s" , config_data )
150
+ default_config = yaml .safe_load (file )
151
+ logging .debug ("Loaded default configuration: %s" , default_config )
155
152
156
- args = parse_args (config_data )
153
+ args = parse_args (default_config )
157
154
158
155
if args .config :
159
156
with open (args .config , "r" ) as file :
160
157
config_data = yaml .safe_load (file )
158
+ config_data = merge_dicts (default_config , config_data )
161
159
logging .info ("Loaded configuration from file: %s" , config_data )
162
160
163
161
apply_overrides_from_env_and_cli (config_data , args )
0 commit comments