X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=config.py;h=81351cff145587adb80cfccf0f245aa7134ef3d6;hb=a08ca309cb5bd7971210a9247a38c9bbe376a6e6;hp=9b4a53d120f8c4c5ee73f393f8080bb1f456e137;hpb=3bc4daf1edc121cd633429187392227f2fa61885;p=python_utils.git diff --git a/config.py b/config.py index 9b4a53d..81351cf 100644 --- a/config.py +++ b/config.py @@ -69,9 +69,10 @@ import os import pprint import re import sys -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional -import string_utils +# This module is commonly used by others in here and should avoid +# taking any unnecessary dependencies back on them. # Note: at this point in time, logging hasn't been configured and # anything we log will come out the root logger. @@ -99,10 +100,12 @@ class LoadFromFile(argparse.Action): # A global parser that we will collect arguments into. +prog = os.path.basename(sys.argv[0]) args = argparse.ArgumentParser( - description=f"This program uses config.py ({__file__}) for global, cross-module configuration.", + description=None, formatter_class=argparse.ArgumentDefaultsHelpFormatter, fromfile_prefix_chars="@", + epilog=f'-----------------------------------------------------------------------------\n{prog} uses config.py ({__file__}) for global, cross-module configuration setup and parsing.\n-----------------------------------------------------------------------------' ) config_parse_called = False @@ -154,16 +157,33 @@ def is_flag_already_in_argv(var: str): return False -def parse() -> Dict[str, Any]: +def parse(entry_module: Optional[str]) -> Dict[str, Any]: """Main program should call this early in main()""" global config_parse_called if config_parse_called: - return + return config config_parse_called = True global saved_messages + # If we're about to do the usage message dump, put the main module's + # argument group first in the list (if possible), please. + reordered_action_groups = [] + prog = sys.argv[0] + + for arg in sys.argv: + if arg == '--help' or arg == '-h': + for group in args._action_groups: + if entry_module is not None and entry_module in group.title: + reordered_action_groups.insert(0, group) # prepend + elif prog in group.title: + reordered_action_groups.insert(0, group) # prepend + else: + reordered_action_groups.append(group) # append + args._action_groups = reordered_action_groups + # Examine the environment variables to settings that match - # known flags. + # known flags. For a flag called --example_flag the corresponding + # environment variable would be called EXAMPLE_FLAG. usage_message = args.format_usage() optional = False var = '' @@ -190,7 +210,8 @@ def parse() -> Dict[str, Any]: saved_messages.append( f'Initialized from environment: {var} = {value}' ) - if len(chunks) == 1 and string_utils.to_bool(value): + from string_utils import to_bool + if len(chunks) == 1 and to_bool(value): sys.argv.append(var) elif len(chunks) > 1: sys.argv.append(var) @@ -201,12 +222,13 @@ def parse() -> Dict[str, Any]: next # Parse (possibly augmented) commandline args with argparse normally. - #config.update(vars(args.parse_args())) known, unknown = args.parse_known_args() config.update(vars(known)) # Reconstruct the argv with unrecognized flags for the benefit of - # future argument parsers. + # future argument parsers. For example, unittest_main in python + # has some of its own flags. If we didn't recognize it, maybe + # someone else will. sys.argv = sys.argv[:1] + unknown if config['config_savefile']: