Logging + documentation.
[python_utils.git] / config.py
index b3580ceed0663bdb34b946d465ea3c2fca3b05f6..1e690bcba70b258f04f84eefd1fca7ff07ea8ab5 100644 (file)
--- a/config.py
+++ b/config.py
@@ -1,7 +1,9 @@
 #!/usr/bin/env python3
 
-"""Global configuration driven by commandline arguments (even across
-different modules).  Usage:
+"""Global configuration driven by commandline arguments, environment variables
+and saved configuration files.  This works across several modules.
+
+Usage:
 
     module.py:
     ----------
@@ -36,7 +38,8 @@ different modules).  Usage:
         config.parse()   # Very important, this must be invoked!
 
     If you set this up and remember to invoke config.parse(), all commandline
-    arguments will play nicely together:
+    arguments will play nicely together.  This is done automatically for you
+    if you're using the bootstrap module's initialize wrapper.
 
     % main.py -h
     usage: main.py [-h]
@@ -73,10 +76,6 @@ from typing import Any, Dict, List, Optional
 # 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.
-logger = logging.getLogger(__name__)
-
 # Defer logging messages until later when logging has been initialized.
 saved_messages: List[str] = []
 
@@ -84,12 +83,13 @@ saved_messages: List[str] = []
 program_name = os.path.basename(sys.argv[0])
 original_argv = [arg for arg in sys.argv]
 
+
 # A global parser that we will collect arguments into.
 args = argparse.ArgumentParser(
     description=None,
     formatter_class=argparse.ArgumentDefaultsHelpFormatter,
     fromfile_prefix_chars="@",
-    epilog=f'-----------------------------------------------------------------------------\n{program_name} uses config.py ({__file__}) for global, cross-module configuration setup and parsing.\n-----------------------------------------------------------------------------'
+    epilog=f'------------------------------------------------------------------------------\n{program_name} uses config.py ({__file__}) for global, cross-module configuration setup and parsing.\n------------------------------------------------------------------------------'
 )
 
 # Keep track of if we've been called and prevent being called more
@@ -116,7 +116,7 @@ group.add_argument(
     '--config_loadfile',
     metavar='FILENAME',
     default=None,
-    help='Config file from which to read args in lieu or in addition to commandline.',
+    help='Config file (populated via --config_savefile) from which to read args in lieu or in addition to commandline.',
 )
 group.add_argument(
     '--config_dump',
@@ -129,7 +129,7 @@ group.add_argument(
     type=str,
     metavar='FILENAME',
     default=None,
-    help='Populate config file compatible --config_loadfile to save config for later use.',
+    help='Populate config file compatible with --config_loadfile to save config for later use.',
 )
 
 
@@ -145,7 +145,6 @@ 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:
-        logger.warning('config.parse has already been called; ignoring spurious invocation')
         return config
 
     global saved_messages
@@ -224,18 +223,17 @@ def parse(entry_module: Optional[str]) -> Dict[str, Any]:
 
     if loadfile is not None:
         if saw_other_args:
-            print(
-                'WARNING: ignoring some commandline arguments; only args in --config_loadfile be parsed.',
-                file=sys.stderr
-            )
+            msg = f'Augmenting commandline arguments with those from {loadfile}.'
+            print(msg, file=sys.stderr)
+            saved_messages.append(msg)
         if not os.path.exists(loadfile):
-            print(f'--config_loadfile argument must be a file, {loadfile} not found.',
+            print(f'ERROR: --config_loadfile argument must be a file, {loadfile} not found.',
                   file=sys.stderr)
             sys.exit(-1)
         with open(loadfile, 'r') as rf:
             newargs = rf.readlines()
         newargs = [arg.strip('\n') for arg in newargs if 'config_savefile' not in arg]
-        sys.argv = sys.argv[:1] + newargs
+        sys.argv += newargs
 
     # Parse (possibly augmented, possibly completely overwritten)
     # commandline args with argparse normally and populate config.
@@ -274,6 +272,7 @@ def dump_config():
     """Print the current config to stdout."""
     print("Global Configuration:", file=sys.stderr)
     pprint.pprint(config, stream=sys.stderr)
+    print()
 
 
 def late_logging():