@@ -150,7 +150,7 @@ def run_tyro_parser(env_or_list: Type[EnvClass] | list[Type[EnvClass]],
150150 if ask_for_missing and getattr (e , "code" , None ) == 2 and eavesdrop :
151151 # Some required arguments are missing. Determine which.
152152 wf = {}
153- for arg in eavesdrop . partition ( ":" )[ 2 ]. strip (). split ( ", " ):
153+ for arg in _fetch_eavesdrop_args ( ):
154154 treat_missing (type_form , kwargs , parser , wf , arg )
155155
156156 # Second attempt to parse CLI
@@ -195,7 +195,6 @@ def treat_missing(env_class, kwargs: dict, parser: ArgumentParser, wf: dict, arg
195195 # However, the UI then is not able to use ex. the number filtering capabilities.
196196 # Putting there None is not a good idea as dataclass_to_tagdict fails if None is not allowed by the annotation.
197197 tag = wf [field_name ] = tag_factory (MissingTagValue (),
198- # tag = wf[field_name] = tag_factory(MISSING,
199198 argument .help .replace ("(required)" , "" ),
200199 validation = not_empty ,
201200 _src_class = env_class ,
@@ -205,9 +204,17 @@ def treat_missing(env_class, kwargs: dict, parser: ArgumentParser, wf: dict, arg
205204 # A None would be enough because Mininterface will ask for the missing values
206205 # promply, however, Pydantic model would fail.
207206 # As it serves only for tyro parsing and the field is marked wrong, the made up value is never used or seen.
208- if "default" not in kwargs :
209- kwargs ["default" ] = SimpleNamespace ()
210- setattr (kwargs ["default" ], field_name , tag ._make_default_value ())
207+ set_default (kwargs , field_name , tag ._make_default_value ())
208+
209+
210+ def _fetch_eavesdrop_args ():
211+ return eavesdrop .partition (":" )[2 ].strip ().split (", " )
212+
213+
214+ def set_default (kwargs , field_name , val ):
215+ if "default" not in kwargs :
216+ kwargs ["default" ] = SimpleNamespace ()
217+ setattr (kwargs ["default" ], field_name , val )
211218
212219
213220def _parse_cli (env_or_list : Type [EnvClass ] | list [Type [EnvClass ]],
@@ -228,45 +235,49 @@ def _parse_cli(env_or_list: Type[EnvClass] | list[Type[EnvClass]],
228235 Returns:
229236 Configuration namespace.
230237 """
238+ if isinstance (env_or_list , list ):
239+ subcommands , env = env_or_list , None
240+ else :
241+ subcommands , env = None , env_or_list
242+
231243 # Load config file
232- if config_file and isinstance ( env_or_list , list ) :
233- # NOTE. Reading config files when using subcommands is not implemented.
244+ if config_file and subcommands :
245+ # Reading config files when using subcommands is not implemented.
234246 static = {}
235247 kwargs ["default" ] = None
236248 warnings .warn (f"Config file { config_file } is ignored because subcommands are used."
237- "It is not easy to set who this should work. "
238- "Describe the developer your usecase so that they might implement this." )
239- if "default" not in kwargs and not isinstance ( env_or_list , list ) :
249+ " It is not easy to set how this should work."
250+ " Describe the developer your usecase so that they might implement this." )
251+ if "default" not in kwargs and not subcommands :
240252 # Undocumented feature. User put a namespace into kwargs["default"]
241253 # that already serves for defaults. We do not fetch defaults yet from a config file.
242254 disk = {}
243255 if config_file :
244256 disk = yaml .safe_load (config_file .read_text ()) or {} # empty file is ok
245257 # Nested dataclasses have to be properly initialized. YAML gave them as dicts only.
246258 for key in (key for key , val in disk .items () if isinstance (val , dict )):
247- disk [key ] = env_or_list .__annotations__ [key ](** disk [key ])
259+ disk [key ] = env .__annotations__ [key ](** disk [key ])
248260
249261 # Fill default fields
250- if pydantic and issubclass (env_or_list , BaseModel ):
262+ if pydantic and issubclass (env , BaseModel ):
251263 # Unfortunately, pydantic needs to fill the default with the actual values,
252264 # the default value takes the precedence over the hard coded one, even if missing.
253- static = {key : env_or_list .model_fields .get (key ).default
254- for ann in yield_annotations (env_or_list ) for key in ann if not key .startswith ("__" ) and not key in disk }
255- # static = {key: env_or_list .model_fields.get(key).default
256- # for key, _ in iterate_attributes(env_or_list ) if not key in disk}
257- elif attr and attr .has (env_or_list ):
265+ static = {key : env .model_fields .get (key ).default
266+ for ann in yield_annotations (env ) for key in ann if not key .startswith ("__" ) and not key in disk }
267+ # static = {key: env_ .model_fields.get(key).default
268+ # for key, _ in iterate_attributes(env_ ) if not key in disk}
269+ elif attr and attr .has (env ):
258270 # Unfortunately, attrs needs to fill the default with the actual values,
259271 # the default value takes the precedence over the hard coded one, even if missing.
260272 # NOTE Might not work for inherited models.
261273 static = {key : field .default
262- for key , field in attr .fields_dict (env_or_list ).items () if not key .startswith ("__" ) and not key in disk }
274+ for key , field in attr .fields_dict (env ).items () if not key .startswith ("__" ) and not key in disk }
263275 else :
264276 # To ensure the configuration file does not need to contain all keys, we have to fill in the missing ones.
265277 # Otherwise, tyro will spawn warnings about missing fields.
266278 static = {key : val
267- for key , val in yield_defaults (env_or_list ) if not key .startswith ("__" ) and not key in disk }
268- kwargs ["default" ] = SimpleNamespace (** (disk | static ))
279+ for key , val in yield_defaults (env ) if not key .startswith ("__" ) and not key in disk }
280+ kwargs ["default" ] = SimpleNamespace (** (static | disk ))
269281
270282 # Load configuration from CLI
271- env , wrong_fields = run_tyro_parser (env_or_list , kwargs , add_verbosity , ask_for_missing , args )
272- return env , wrong_fields
283+ return run_tyro_parser (subcommands or env , kwargs , add_verbosity , ask_for_missing , args )
0 commit comments