diff options
Diffstat (limited to 'config.py')
| -rw-r--r-- | config.py | 84 |
1 files changed, 79 insertions, 5 deletions
@@ -55,17 +55,23 @@ different modules). Usage: --dry_run Should we really do the thing? - Arguments themselves should be accessed via config.config['arg_name']. e.g. + Arguments themselves should be accessed via + config.config['arg_name']. e.g. if not config.config['dry_run']: module.do_the_thing() + """ import argparse +import logging +import os import pprint import re import sys -from typing import Dict, Any +from typing import Any, Dict, List + +import string_utils # Note: at this point in time, logging hasn't been configured and # anything we log will come out the root logger. @@ -96,7 +102,7 @@ class LoadFromFile(argparse.Action): args = argparse.ArgumentParser( description=f"This program uses config.py ({__file__}) for global, cross-module configuration.", formatter_class=argparse.ArgumentDefaultsHelpFormatter, - fromfile_prefix_chars="@" + fromfile_prefix_chars="@", ) config_parse_called = False @@ -104,6 +110,9 @@ config_parse_called = False # It is also this variable that modules use to access parsed arguments config: Dict[str, Any] = {} +# Defer logging messages until later when logging has been initialized. +saved_messages: List[str] = [] + def add_commandline_args(title: str, description: str = ""): """Create a new context for arguments and return a handle.""" @@ -137,11 +146,68 @@ group.add_argument( ) +def is_flag_already_in_argv(var: str): + """Is a particular flag passed on the commandline?""" + for _ in sys.argv: + if var in _: + return True + return False + + def parse() -> Dict[str, Any]: """Main program should call this early in main()""" global config_parse_called + if config_parse_called: + return config_parse_called = True - config.update(vars(args.parse_args())) + global saved_messages + + # Examine the environment variables to settings that match + # known flags. + usage_message = args.format_usage() + optional = False + var = '' + for x in usage_message.split(): + if x[0] == '[': + optional = True + if optional: + var += f'{x} ' + if x[-1] == ']': + optional = False + var = var.strip() + var = var.strip('[') + var = var.strip(']') + chunks = var.split() + if len(chunks) > 1: + var = var.split()[0] + + # Environment vars the same as flag names without + # the initial -'s and in UPPERCASE. + env = var.strip('-').upper() + if env in os.environ: + if not is_flag_already_in_argv(var): + value = os.environ[env] + saved_messages.append( + f'Initialized from environment: {var} = {value}' + ) + if len(chunks) == 1 and string_utils.to_bool(value): + sys.argv.append(var) + elif len(chunks) > 1: + sys.argv.append(var) + sys.argv.append(value) + var = '' + env = '' + else: + 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. + sys.argv = sys.argv[:1] + unknown if config['config_savefile']: with open(config['config_savefile'], 'w') as wf: @@ -149,11 +215,11 @@ def parse() -> Dict[str, Any]: if config['config_dump']: dump_config() - return config def has_been_parsed() -> bool: + """Has the global config been parsed yet?""" global config_parse_called return config_parse_called @@ -162,3 +228,11 @@ def dump_config(): """Print the current config to stdout.""" print("Global Configuration:", file=sys.stderr) pprint.pprint(config, stream=sys.stderr) + + +def late_logging(): + """Log messages saved earlier now that logging has been initialized.""" + logger = logging.getLogger(__name__) + global saved_messages + for _ in saved_messages: + logger.debug(_) |
