@@ -66,26 +66,69 @@ def config_logger():
6666 )
6767
6868
69+ def _deep_merge (base : dict , override : dict ) -> dict :
70+ """Return a new dict with override merged on top of base, recursively."""
71+ result = base .copy ()
72+ for key , val in override .items ():
73+ if (
74+ key in result
75+ and isinstance (result [key ], dict )
76+ and isinstance (val , dict )
77+ ):
78+ result [key ] = _deep_merge (result [key ], val )
79+ else :
80+ result [key ] = val
81+ return result
82+
83+
84+ def _site_config_path () -> Path :
85+ """Return the platform-appropriate site-wide config path."""
86+ if sys .platform == "win32" :
87+ base = Path (os .environ .get ("ProgramData" , r"C:\ProgramData" ))
88+ else :
89+ base = Path ("/etc" )
90+ return base / "picasso_workflow" / "config.yaml"
91+
92+
93+ def _load_yaml (path ) -> dict :
94+ with open (path , "r" ) as f :
95+ return yaml .safe_load (f ) or {}
96+
97+
6998def load_config ():
70- """Load the picasso-workflow configuration yaml file"""
71- # 1. User config path
72- user_config = Path .home () / ".config" / "picasso_workflow" / "config.yaml"
73- if user_config .exists ():
74- with open (user_config , "r" ) as f :
75- return yaml .safe_load (f )
76- # 2. Fallback to package default
99+ """Load the picasso-workflow configuration yaml file.
100+
101+ Configs are deep-merged in increasing priority order so that
102+ higher-priority files only need to specify the keys they override:
103+
104+ 1. Bundled package default (config.yaml / config_template.yaml)
105+ 2. Site-wide admin config (C:\\ ProgramData\\ picasso_workflow\\ config.yaml
106+ or /etc/picasso_workflow/config.yaml)
107+ 3. Per-user config (~/.config/picasso_workflow/config.yaml)
108+ """
109+ # 1. Package default
77110 try :
78- default_config = importlib .resources .files ("picasso_workflow" ).joinpath (
111+ pkg_config = importlib .resources .files ("picasso_workflow" ).joinpath (
79112 "config.yaml"
80113 )
81- with open (default_config , "r" ) as f :
82- return yaml .safe_load (f )
83- except FileNotFoundError :
84- template_config = importlib .resources .files ("picasso_workflow" ).joinpath (
114+ config = _load_yaml (pkg_config )
115+ except (FileNotFoundError , TypeError ):
116+ template = importlib .resources .files ("picasso_workflow" ).joinpath (
85117 "config_template.yaml"
86118 )
87- with open (template_config , "r" ) as f :
88- return yaml .safe_load (f )
119+ config = _load_yaml (template )
120+
121+ # 2. Site-wide admin config (optional)
122+ site_config = _site_config_path ()
123+ if site_config .exists ():
124+ config = _deep_merge (config , _load_yaml (site_config ))
125+
126+ # 3. Per-user config (optional)
127+ user_config = Path .home () / ".config" / "picasso_workflow" / "config.yaml"
128+ if user_config .exists ():
129+ config = _deep_merge (config , _load_yaml (user_config ))
130+
131+ return config
89132
90133
91134config_logger ()
0 commit comments