@@ -259,7 +259,6 @@ def _parse_common(
259259 skip_required : bool = False ,
260260 skip_subcommands : bool = False ,
261261 fail_no_subcommand : bool = True ,
262- cfg_base : Optional [Namespace ] = None ,
263262 log_message : Optional [str ] = None ,
264263 ) -> Namespace :
265264 """Common parsing code used by other parse methods.
@@ -273,7 +272,6 @@ def _parse_common(
273272 skip_required: Whether to skip check of required arguments.
274273 skip_subcommands: Whether to skip subcommand processing.
275274 fail_no_subcommand: Whether to fail if no subcommand given.
276- cfg_base: A base configuration object.
277275 log_message: Message to log at INFO level after parsing.
278276
279277 Returns:
@@ -285,18 +283,7 @@ def _parse_common(
285283 if not skip_subcommands :
286284 _ActionSubCommands .handle_subcommands (self , cfg , env = env , defaults = defaults , fail_no_subcommand = fail_no_subcommand )
287285
288- if cfg_base is not None :
289- cfg = self .merge_config (cfg , cfg_base )
290-
291- if env :
292- with _ActionPrintConfig .skip_print_config ():
293- cfg_env = self .parse_env (defaults = defaults , _skip_check = True , _skip_subcommands = True )
294- cfg = self .merge_config (cfg , cfg_env )
295-
296- elif defaults :
297- cfg = self .merge_config (cfg , self .get_defaults (skip_check = True ))
298- with load_value_context (self .parser_mode ):
299- ActionTypeHint .apply_appends (self , cfg )
286+ if defaults :
300287 with lenient_check_context ():
301288 ActionTypeHint .add_sub_defaults (self , cfg )
302289
@@ -317,6 +304,26 @@ def _parse_common(
317304 return cfg
318305
319306
307+ def _parse_defaults_and_environ (
308+ self ,
309+ defaults : bool = True ,
310+ env : Optional [bool ] = None ,
311+ environ : Union [Dict [str , str ], os ._Environ ] = None ,
312+ ):
313+ cfg = Namespace ()
314+ if defaults :
315+ cfg = self .get_defaults (skip_check = True )
316+
317+ if env or (env is None and self ._default_env ):
318+ if environ is None :
319+ environ = os .environ
320+ with load_value_context (self .parser_mode ):
321+ cfg_env = self ._load_env_vars (env = environ , defaults = defaults )
322+ cfg = self .merge_config (cfg_env , cfg )
323+
324+ return cfg
325+
326+
320327 def parse_args ( # type: ignore[override]
321328 self ,
322329 args : Optional [Sequence [str ]] = None ,
@@ -348,7 +355,11 @@ def parse_args( # type: ignore[override]
348355 argcomplete_autocomplete (self )
349356
350357 try :
351- cfg , unk = self .parse_known_args (args = args , namespace = namespace )
358+ cfg = self ._parse_defaults_and_environ (defaults , env )
359+ if namespace :
360+ cfg = self .merge_config (namespace , cfg )
361+
362+ cfg , unk = self .parse_known_args (args = args , namespace = cfg )
352363 if unk :
353364 self .error (f'Unrecognized arguments: { " " .join (unk )} ' )
354365
@@ -392,7 +403,12 @@ def parse_object(
392403 ParserError: If there is a parsing error and error_handler=None.
393404 """
394405 try :
395- cfg = self ._apply_actions (cfg_obj )
406+ cfg = self ._parse_defaults_and_environ (defaults , env )
407+ if cfg_base :
408+ cfg = self .merge_config (cfg_base , cfg )
409+
410+ cfg_obj = self ._apply_actions (cfg_obj )
411+ cfg = self .merge_config (cfg_obj , cfg )
396412
397413 parsed_cfg = self ._parse_common (
398414 cfg = cfg ,
@@ -401,7 +417,6 @@ def parse_object(
401417 with_meta = with_meta ,
402418 skip_check = _skip_check ,
403419 skip_required = _skip_required ,
404- cfg_base = cfg_base ,
405420 log_message = 'Parsed object.' ,
406421 )
407422
@@ -411,7 +426,7 @@ def parse_object(
411426 return parsed_cfg
412427
413428
414- def _load_env_vars (self , env : Dict [str , str ], defaults : bool ) -> Namespace :
429+ def _load_env_vars (self , env : Union [ Dict [str , str ], os . _Environ ], defaults : bool ) -> Namespace :
415430 cfg = Namespace ()
416431 actions = filter_default_actions (self ._actions )
417432 for action in actions :
@@ -436,10 +451,11 @@ def _load_env_vars(self, env: Dict[str, str], defaults: bool) -> Namespace:
436451 try :
437452 env_val = load_value (env_val )
438453 except get_loader_exceptions ():
439- env_val = [env_val ] # type: ignore
454+ env_val = [env_val ]
440455 else :
441- env_val = [env_val ] # type: ignore
456+ env_val = [env_val ]
442457 cfg [action .dest ] = self ._check_value_key (action , env_val , action .dest , cfg )
458+ self ._apply_actions (cfg )
443459 return cfg
444460
445461
@@ -465,16 +481,11 @@ def parse_env(
465481 ParserError: If there is a parsing error and error_handler=None.
466482 """
467483 try :
468- if env is None :
469- env = dict (os .environ )
470- with load_value_context (self .parser_mode ):
471- cfg = self ._load_env_vars (env = env , defaults = defaults )
472-
473- self ._apply_actions (cfg )
484+ cfg = self ._parse_defaults_and_environ (defaults , env = True , environ = env )
474485
475486 parsed_cfg = self ._parse_common (
476487 cfg = cfg ,
477- env = False ,
488+ env = True ,
478489 defaults = defaults ,
479490 with_meta = with_meta ,
480491 skip_check = _skip_check ,
@@ -562,6 +573,10 @@ def parse_string(
562573 with load_value_context (self .parser_mode ):
563574 cfg = self ._load_config_parser_mode (cfg_str , cfg_path , ext_vars , previous_config .get ())
564575
576+ if defaults or env :
577+ cfg_base = self ._parse_defaults_and_environ (defaults , env )
578+ cfg = self .merge_config (cfg , cfg_base )
579+
565580 parsed_cfg = self ._parse_common (
566581 cfg = cfg ,
567582 env = env ,
@@ -920,19 +935,19 @@ def get_defaults(self, skip_check: bool = False) -> Namespace:
920935 cfg_file = self ._load_config_parser_mode (default_config_file .get_content ())
921936 if key is not None :
922937 cfg_file = cfg_file .get (key )
938+ cfg = self .merge_config (cfg_file , cfg )
923939 try :
924940 with _ActionPrintConfig .skip_print_config ():
925- cfg_file = self ._parse_common (
926- cfg = cfg_file ,
927- env = None ,
941+ cfg = self ._parse_common (
942+ cfg = cfg ,
943+ env = False ,
928944 defaults = False ,
929945 with_meta = None ,
930946 skip_check = skip_check ,
931947 skip_required = True ,
932948 )
933949 except (TypeError , KeyError , ParserError ) as ex :
934950 raise ParserError (f'Problem in default config file "{ default_config_file } " :: { ex .args [0 ]} ' ) from ex
935- cfg = self .merge_config (cfg_file , cfg )
936951 meta = cfg .get ('__default_config__' )
937952 if isinstance (meta , list ):
938953 meta .append (default_config_file )
@@ -1217,6 +1232,7 @@ def merge_config(self, cfg_from: Namespace, cfg_to: Namespace) -> Namespace:
12171232 cfg = cfg_to .clone ()
12181233 ActionTypeHint .discard_init_args_on_class_path_change (self , cfg , cfg_from )
12191234 cfg .update (cfg_from )
1235+ ActionTypeHint .apply_appends (self , cfg )
12201236 return cfg
12211237
12221238
0 commit comments