edq.config.argparser
1import argparse 2import os 3import typing 4 5import edq.config.constants 6import edq.config.load 7import edq.config.settings 8import edq.util.serial 9 10def set_cli_args( 11 parser: argparse.ArgumentParser, 12 extra_state: typing.Dict[str, typing.Any], 13 **kwargs: typing.Any, 14 ) -> None: 15 """ 16 Set common CLI arguments for configuration. 17 """ 18 19 group = parser.add_argument_group('config options') 20 21 group.add_argument('--config', dest = edq.config.constants.CONFIG_OPTIONS_KEY, metavar = "<KEY>=<VALUE>", 22 action = 'append', type = str, default = [], 23 help = ('Set a configuration option from the command-line.' 24 + ' Specify options as <key>=<value> pairs.' 25 + ' This flag can be specified multiple times.' 26 + ' The options are applied in the order provided and later options override earlier ones.' 27 + ' Will override options form all config files.') 28 ) 29 30 group.add_argument('--config-file', dest = edq.config.constants.CONFIG_PATHS_KEY, 31 action = 'append', type = str, default = [], 32 help = ('Load config options from a JSON file.' 33 + ' This flag can be specified multiple times.' 34 + ' Files are applied in the order provided and later files override earlier ones.' 35 + ' Will override options form both global and local config files.') 36 ) 37 38 group.add_argument('--config-global', dest = edq.config.constants.GLOBAL_CONFIG_KEY, 39 action = 'store', type = str, default = os.path.join(edq.config.settings.get_global_dir(), edq.config.settings.get_config_filename()), 40 help = 'Set the default global config file path (default: %(default)s).', 41 ) 42 43 group.add_argument('--encryption-key', dest = edq.config.constants.CONFIG_ENCRYPTION_KEY, 44 action = 'store', type = str, default = None, 45 help = 'Encryption key to use for configuration secrets (e.g., passwords and tokens).', 46 ) 47 48 _attach_epilogue(parser) 49 50def _attach_epilogue(parser: argparse.ArgumentParser) -> None: 51 """ 52 Construct an epilogue detailing configuration information and attach it to the parser's epilogue. 53 The epilogue will be created from the current config load order. 54 Each source spec will be asked to create their portion of the epilogue. 55 """ 56 57 load_order = edq.config.settings.get_load_order() 58 if (len(load_order) == 0): 59 return 60 61 lines = [ 62 'Configuration is loaded into this program using a "tiered" system.', 63 'This means that configuration options will be loaded from various sources in a pre-defined order.', 64 'If the same value is read from multiple sources, then the **last** read value overrides any previous values.', 65 'If you want to see where your configuration values are being loaded from, see the config list command with the `--show-origin` flag.', 66 '', 67 'Below is the order that configurations are read for this program:' 68 ] 69 70 indent = ' ' * edq.config.constants.DEFAULT_INDENT 71 72 for (step_index, spec) in enumerate(load_order): 73 spec_lines = spec.get_help_lines() 74 if ((spec_lines is None) or (len(spec_lines) == 0)): 75 continue 76 77 for i in range(len(spec_lines)): # pylint: disable=consider-using-enumerate 78 # Add in a step number for this first line, and an indentation for all other lines.. 79 if (i == 0): 80 spec_lines[i] = f"{step_index + 1}) {spec_lines[i]}" 81 else: 82 spec_lines[i] = indent + spec_lines[i] 83 84 # Add another indentation level (for all lines). 85 spec_lines = [indent + line for line in spec_lines] 86 87 if (step_index != 0): 88 lines.append('') 89 90 lines += spec_lines 91 92 # Prepare any existing epilogue. 93 if (parser.epilog is None): 94 parser.epilog = '' 95 elif (len(parser.epilog) > 0): 96 parser.epilog += "\n\n" 97 98 lines = [indent + line for line in lines] 99 parser.epilog += "CONFIGURATION\n\n" + "\n".join(lines) 100 101def add_config_location_argument_group(parser: argparse.ArgumentParser) -> None: 102 """ Add the configuration location argument group to the parser. """ 103 104 group = parser.add_argument_group("config location options").add_mutually_exclusive_group() 105 106 group.add_argument('--local', 107 action = 'store_true', dest = 'scope_local', 108 help = ("Target config option(s) in a local config file.") 109 ) 110 111 group.add_argument('--project', 112 action = 'store_true', dest = 'scope_project', 113 help = ("Target config option(s) in a project config file.") 114 ) 115 116 group.add_argument('--global', 117 action = 'store_true', dest = 'scope_global', 118 help = ("Target config option(s) in the global config file."), 119 ) 120 121 group.add_argument('--file', metavar = "<FILE>", 122 action = 'store', type = str, default = None, dest = 'scope_file', 123 help = ("Target config option(s) in a specified config file.") 124 ) 125 126def load_config_into_args( 127 parser: argparse.ArgumentParser, 128 args: argparse.Namespace, 129 extra_state: typing.Dict[str, typing.Any], 130 cli_arg_config_map: typing.Union[typing.Dict[str, str], None] = None, 131 serialization_context: typing.Union[edq.util.serial.SerializationContext, None] = None, 132 **kwargs: typing.Any, 133 ) -> None: 134 """ 135 Take in args from a parser that was passed to set_cli_args(), 136 and get the tired configuration with the appropriate parameters, and attache it to args. 137 138 Arguments that appear on the CLI as flags (e.g. `--foo bar`) can be copied over to the config options via `cli_arg_config_map`. 139 The keys of `cli_arg_config_map` represent attributes in the CLI arguments (`args`), 140 while the values represent the desired config name this argument should be set as. 141 For example, a `cli_arg_config_map` of `{'foo': 'baz'}` will make the CLI argument `--foo bar` 142 be equivalent to `--config baz=bar`. 143 """ 144 145 if (cli_arg_config_map is None): 146 cli_arg_config_map = {} 147 148 for (cli_key, config_key) in cli_arg_config_map.items(): 149 value = getattr(args, cli_key, None) 150 if (value is not None): 151 getattr(args, edq.config.constants.CONFIG_OPTIONS_KEY).append(f"{config_key}={value}") 152 153 default_values = {} 154 for action in parser._actions: 155 key = getattr(action, 'dest', None) 156 if (key is None): 157 continue 158 159 default_values[str(key)] = getattr(action, 'default', None) 160 161 config_info = edq.config.load.get_tiered_config( 162 cli_arguments = args, 163 cli_default_values = default_values, 164 serialization_context = serialization_context, 165 ) 166 setattr(args, "_config_info", config_info)
def
set_cli_args( parser: argparse.ArgumentParser, extra_state: Dict[str, Any], **kwargs: Any) -> None:
11def set_cli_args( 12 parser: argparse.ArgumentParser, 13 extra_state: typing.Dict[str, typing.Any], 14 **kwargs: typing.Any, 15 ) -> None: 16 """ 17 Set common CLI arguments for configuration. 18 """ 19 20 group = parser.add_argument_group('config options') 21 22 group.add_argument('--config', dest = edq.config.constants.CONFIG_OPTIONS_KEY, metavar = "<KEY>=<VALUE>", 23 action = 'append', type = str, default = [], 24 help = ('Set a configuration option from the command-line.' 25 + ' Specify options as <key>=<value> pairs.' 26 + ' This flag can be specified multiple times.' 27 + ' The options are applied in the order provided and later options override earlier ones.' 28 + ' Will override options form all config files.') 29 ) 30 31 group.add_argument('--config-file', dest = edq.config.constants.CONFIG_PATHS_KEY, 32 action = 'append', type = str, default = [], 33 help = ('Load config options from a JSON file.' 34 + ' This flag can be specified multiple times.' 35 + ' Files are applied in the order provided and later files override earlier ones.' 36 + ' Will override options form both global and local config files.') 37 ) 38 39 group.add_argument('--config-global', dest = edq.config.constants.GLOBAL_CONFIG_KEY, 40 action = 'store', type = str, default = os.path.join(edq.config.settings.get_global_dir(), edq.config.settings.get_config_filename()), 41 help = 'Set the default global config file path (default: %(default)s).', 42 ) 43 44 group.add_argument('--encryption-key', dest = edq.config.constants.CONFIG_ENCRYPTION_KEY, 45 action = 'store', type = str, default = None, 46 help = 'Encryption key to use for configuration secrets (e.g., passwords and tokens).', 47 ) 48 49 _attach_epilogue(parser)
Set common CLI arguments for configuration.
def
add_config_location_argument_group(parser: argparse.ArgumentParser) -> None:
102def add_config_location_argument_group(parser: argparse.ArgumentParser) -> None: 103 """ Add the configuration location argument group to the parser. """ 104 105 group = parser.add_argument_group("config location options").add_mutually_exclusive_group() 106 107 group.add_argument('--local', 108 action = 'store_true', dest = 'scope_local', 109 help = ("Target config option(s) in a local config file.") 110 ) 111 112 group.add_argument('--project', 113 action = 'store_true', dest = 'scope_project', 114 help = ("Target config option(s) in a project config file.") 115 ) 116 117 group.add_argument('--global', 118 action = 'store_true', dest = 'scope_global', 119 help = ("Target config option(s) in the global config file."), 120 ) 121 122 group.add_argument('--file', metavar = "<FILE>", 123 action = 'store', type = str, default = None, dest = 'scope_file', 124 help = ("Target config option(s) in a specified config file.") 125 )
Add the configuration location argument group to the parser.
def
load_config_into_args( parser: argparse.ArgumentParser, args: argparse.Namespace, extra_state: Dict[str, Any], cli_arg_config_map: Optional[Dict[str, str]] = None, serialization_context: Optional[edq.util.common.SerializationContext] = None, **kwargs: Any) -> None:
127def load_config_into_args( 128 parser: argparse.ArgumentParser, 129 args: argparse.Namespace, 130 extra_state: typing.Dict[str, typing.Any], 131 cli_arg_config_map: typing.Union[typing.Dict[str, str], None] = None, 132 serialization_context: typing.Union[edq.util.serial.SerializationContext, None] = None, 133 **kwargs: typing.Any, 134 ) -> None: 135 """ 136 Take in args from a parser that was passed to set_cli_args(), 137 and get the tired configuration with the appropriate parameters, and attache it to args. 138 139 Arguments that appear on the CLI as flags (e.g. `--foo bar`) can be copied over to the config options via `cli_arg_config_map`. 140 The keys of `cli_arg_config_map` represent attributes in the CLI arguments (`args`), 141 while the values represent the desired config name this argument should be set as. 142 For example, a `cli_arg_config_map` of `{'foo': 'baz'}` will make the CLI argument `--foo bar` 143 be equivalent to `--config baz=bar`. 144 """ 145 146 if (cli_arg_config_map is None): 147 cli_arg_config_map = {} 148 149 for (cli_key, config_key) in cli_arg_config_map.items(): 150 value = getattr(args, cli_key, None) 151 if (value is not None): 152 getattr(args, edq.config.constants.CONFIG_OPTIONS_KEY).append(f"{config_key}={value}") 153 154 default_values = {} 155 for action in parser._actions: 156 key = getattr(action, 'dest', None) 157 if (key is None): 158 continue 159 160 default_values[str(key)] = getattr(action, 'default', None) 161 162 config_info = edq.config.load.get_tiered_config( 163 cli_arguments = args, 164 cli_default_values = default_values, 165 serialization_context = serialization_context, 166 ) 167 setattr(args, "_config_info", config_info)
Take in args from a parser that was passed to set_cli_args(), and get the tired configuration with the appropriate parameters, and attache it to args.
Arguments that appear on the CLI as flags (e.g. --foo bar) can be copied over to the config options via cli_arg_config_map.
The keys of cli_arg_config_map represent attributes in the CLI arguments (args),
while the values represent the desired config name this argument should be set as.
For example, a cli_arg_config_map of {'foo': 'baz'} will make the CLI argument --foo bar
be equivalent to --config baz=bar.