chainlib

Generic blockchain access library and tooling
Log | Files | Refs | README | LICENSE

commit 2ad84fc5aadfd4ce2290343d03f39b5d5f0af4e3
parent 98ecf91adcd0c3e53e607b0ae9f1905480e25d9e
Author: lash <dev@holbrook.no>
Date:   Wed, 11 May 2022 18:51:37 +0000

Fix config process ordering, all args test

Diffstat:
Mchainlib/cli/arg.py | 202-------------------------------------------------------------------------------
Mchainlib/cli/config.py | 345++++++++-----------------------------------------------------------------------
Mtests/test_cli.py | 15+++++++++++++++
3 files changed, 47 insertions(+), 515 deletions(-)

diff --git a/chainlib/cli/arg.py b/chainlib/cli/arg.py @@ -13,13 +13,6 @@ from aiee.arg import ( Arg as BaseArg, ) -# local imports -#from .base import ( -# default_config_dir, -# Flag, -# argflag_std_target, -# ) - logg = logging.getLogger(__name__) @@ -36,22 +29,6 @@ logg = logging.getLogger(__name__) # v = h[0][0].read() # return v.rstrip() # return None -# -#_default_long_args = { -# '-a': '--recipient', -# '-e': '--executable-address', -# '-s': '--send', -# '-y': '--key-file', -# } -# -#_default_dest = { -# '-a': 'recipient', -# '-e': 'executable_address', -# } -# -# -#_default_fmt = 'human' - class ArgumentParser(argparse.ArgumentParser): @@ -61,185 +38,6 @@ class ArgumentParser(argparse.ArgumentParser): return super(ArgumentParser, self).parse_args(args=argv) -#class ArgumentParser(argparse.ArgumentParser): -# """Extends the standard library argument parser to construct arguments based on configuration flags. -# -# The extended class is set up to facilitate piping of single positional arguments via stdin. For this reason, positional arguments should be added using the locally defined add_positional method instead of add_argument. -# -# Long flag aliases for short flags are editable using the arg_long argument. Editing a non-existent short flag will produce no error and have no effect. Adding a long flag for a short flag that does not have an alias will also not have effect. -# -# Calls chainlib.cli.args.ArgumentParser.process_flags with arg_flags and env arguments, see the method's documentation for further details. -# -# :param arg_flags: Argument flag bit vector to generate configuration values for. -# :type arg_flags: chainlib.cli.Flag -# :param arg_long: Change long flag alias for given short flags. Example value: {'-a': '--addr', '-e': '--contract'} -# :type arg_long: dict -# :param env: Environment variables -# :type env: dict -# :param usage: Usage string, passed to parent -# :type usage: str -# :param description: Description string, passed to parent -# :type description: str -# :param epilog: Epilog string, passed to parent -# :type epilog: str -# """ -# -# def __init__(self, arg_flags=0x0f, arg_long={}, env=os.environ, usage=None, description=None, epilog=None, default_format=_default_fmt, *args, **kwargs): -# super(ArgumentParser, self).__init__(usage=usage, description=description, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter, *args, **kwargs) -# -# self.pos_args = [] -# self.long_args = _default_long_args -# self.arg_dest = _default_dest -# self.default_format = default_format -# -# re_long = r'^--[a-z\-]+$' -# for k in arg_long.keys(): -# if re.match(re_long, arg_long[k]) == None: -# raise ValueError('invalid long arg {}'.format(arg_long[k])) -# self.long_args[k] = arg_long[k] -# dest = arg_long[k][2:] -# dest = dest.replace('-', '_') -# self.arg_dest[k] = dest -# -# self.process_flags(arg_flags, env) -# -# -# def add_positional(self, name, type=str, help=None, append=False, required=True): -# """Add a positional argument. -# -# Stdin piping will only be possible in the event a single positional argument is defined. -# -# If the "required" is set, the resulting parsed arguments must have provided a value either from stdin or excplicitly on the command line. -# -# :param name: Attribute name of argument -# :type name: str -# :param type: Argument type -# :type type: str -# :param help: Help string -# :type help: str -# :param required: If true, argument will be set to required -# :type required: bool -# """ -# self.pos_args.append((name, type, help, required, append,)) -# -# -# def parse_args(self, argv=sys.argv[1:]): -# """Overrides the argparse.ArgumentParser.parse_args method. -# -# Implements reading arguments from stdin if a single positional argument is defined (and not set to required). -# -# If the "required" was set for the single positional argument, the resulting parsed arguments must have provided a value either from stdin or excplicitly on the command line. -# -# :param argv: Argument vector to process -# :type argv: list -# """ -# if len(self.pos_args) == 1: -# arg = self.pos_args[0] -# if arg[4]: -# self.add_argument(arg[0], nargs='*', type=arg[1], default=stdin_arg(), help=arg[2]) -# else: -# self.add_argument(arg[0], nargs='?', type=arg[1], default=stdin_arg(), help=arg[2]) -# else: -# for arg in self.pos_args: -# if arg[3]: -# if arg[4]: -# self.add_argument(arg[0], nargs='+', type=arg[1], help=arg[2]) -# else: -# self.add_argument(arg[0], type=arg[1], help=arg[2]) -# else: -# if arg[4]: -# self.add_argument(arg[0], nargs='*', type=arg[1], help=arg[2]) -# else: -# self.add_argument(arg[0], type=arg[1], help=arg[2]) -# args = super(ArgumentParser, self).parse_args(args=argv) -# -# if getattr(args, 'dumpconfig', None) != None: -# return args -# -# if len(self.pos_args) == 1: -# arg = self.pos_args[0] -# argname = arg[0] -# required = arg[3] -# if getattr(args, arg[0], None) == None: -# argp = stdin_arg() -# if argp == None and required: -# self.error('need first positional argument or value from stdin') -# setattr(args, arg[0], argp) -# -# return args -# -# -# def process_flags(self, arg_flags, env): -# """Configures the arguments of the parser using the provided flags. -# -# Environment variables are used for default values for: -# -# CONFINI_DIR: -c, --config -# CONFINI_ENV_PREFIX: --env-prefix -# -# This method is called by the constructor, and is not intended to be called directly. -# -# :param arg_flags: Argument flag bit vector to generate configuration values for. -# :type arg_flags: chainlib.cli.Flag -# :param env: Environment variables -# :type env: dict -# """ -# if arg_flags & Flag.VERBOSE: -# self.add_argument('--no-logs', dest='no_logs',action='store_true', help='Turn off all logging') -# self.add_argument('-v', action='store_true', help='Be verbose') -# self.add_argument('-vv', action='store_true', help='Be more verbose') -# if arg_flags & Flag.CONFIG: -# self.add_argument('-c', '--config', type=str, default=env.get('CONFINI_DIR'), help='Configuration directory') -# self.add_argument('-n', '--namespace', type=str, help='Configuration namespace') -# self.add_argument('--dumpconfig', type=str, choices=['env', 'ini'], help='Output configuration and quit. Use with --raw to omit values and output schema only.') -# if arg_flags & Flag.WAIT: -# self.add_argument('-w', action='store_true', help='Wait for the last transaction to be confirmed') -# self.add_argument('-ww', action='store_true', help='Wait for every transaction to be confirmed') -# if arg_flags & Flag.ENV_PREFIX: -# self.add_argument('--env-prefix', default=env.get('CONFINI_ENV_PREFIX'), dest='env', type=str, help='environment prefix for variables to overwrite configuration') -# if arg_flags & Flag.PROVIDER: -# self.add_argument('-p', '--rpc-provider', dest='p', type=str, help='RPC HTTP(S) provider url') -# self.add_argument('--rpc-dialect', dest='rpc_dialect', type=str, help='RPC HTTP(S) backend dialect') -# if arg_flags & Flag.NO_TARGET == 0: -# self.add_argument('--height', default='latest', help='Block height to execute against') -# if arg_flags & Flag.RPC_AUTH: -# self.add_argument('--rpc-auth', dest='rpc_auth', type=str, help='RPC autentication scheme') -# self.add_argument('--rpc-credentials', dest='rpc_credentials', type=str, help='RPC autentication credential values') -# if arg_flags & Flag.CHAIN_SPEC: -# self.add_argument('-i', '--chain-spec', dest='i', type=str, help='Chain specification string') -# if arg_flags & Flag.UNSAFE: -# self.add_argument('-u', '--unsafe', dest='u', action='store_true', help='Do not verify address checksums') -# if arg_flags & Flag.SEQ: -# self.add_argument('--seq', action='store_true', help='Use sequential rpc ids') -# if arg_flags & Flag.KEY_FILE: -# self.add_argument('-y', self.long_args['-y'], dest='y', type=str, help='Keystore file to use for signing or address') -# self.add_argument('--passphrase-file', dest='passphrase_file', type=str, help='File containing passphrase for keystore') -# if arg_flags & Flag.SEND: -# self.add_argument('-s', self.long_args['-s'], dest='s', action='store_true', help='Send to network') -# if arg_flags & Flag.RAW: -# self.add_argument('--raw', action='store_true', help='Do not decode output') -# if arg_flags & (Flag.SIGN | Flag.NONCE): -# self.add_argument('--nonce', type=int, help='override nonce') -# if arg_flags & (Flag.SIGN | Flag.FEE): -# self.add_argument('--fee-price', dest='fee_price', type=int, help='override fee price') -# self.add_argument('--fee-limit', dest='fee_limit', type=int, help='override fee limit') -# # wtf? -# #if arg_flags & argflag_std_target == 0: -# # arg_flags |= Flag.WALLET -# if arg_flags & Flag.EXEC: -# self.add_argument('-e', self.long_args['-e'], dest=self.arg_dest['-e'], type=str, help='contract address') -# if arg_flags & Flag.WALLET: -# self.add_argument('-a', self.long_args['-a'], dest=self.arg_dest['-a'], type=str, help='recipient address') -# if arg_flags & (Flag.FMT_HUMAN | Flag.FMT_WIRE | Flag.FMT_RPC): -# format_choices = [] -# if arg_flags & Flag.FMT_HUMAN: -# format_choices.append('human') -# if arg_flags & Flag.FMT_WIRE: -# format_choices.append('bin') -# if arg_flags & Flag.FMT_RPC: -# format_choices.append('rpc') -# self.add_argument('-f', '--format', type=str, choices=format_choices, help='output formatting (default: {})'.format(self.default_format)) - class ArgFlag(BaseArgFlag): def __init__(self): diff --git a/chainlib/cli/config.py b/chainlib/cli/config.py @@ -50,287 +50,14 @@ class Config(confini.Config): v = os.path.join(v, self.namespace) return super(Config, self).add_override_dir(v) -# @staticmethod -# def override_defaults(base_dir=None, default_fee_limit=None): -# if base_dir != None: -# Config.default_base_config_dir = os.path.realpath(base_dir) -# if default_fee_limit != None: -# Config.default_fee_limit = int(default_fee_limit) -# -# -# @classmethod -# def from_args(cls, args, arg_flags=0x0f, env=os.environ, extra_args={}, base_config_dir=None, default_config_dir=None, user_config_dir=None, default_fee_limit=None, logger=None, load_callback=None, dump_writer=sys.stdout): -# """Parses arguments in argparse.ArgumentParser instance, then match and override configuration values that match them. -# -# The method processes all known argument flags from chainlib.cli.Flag passed in the "args" argument. -# -# All entries in extra_args may be used to associate arguments not defined in the argument flags with configuration variables, in the following manner: -# -# - The value of argparser.ArgumentParser instance attribute with the dictionary key string is looked up. -# - If the value is None (defined but empty), any existing value for the configuration directive will be kept. -# - If the value of the extra_args dictionary entry is None, then the value will be stored in the configuration under the upper-case value of the key string, prefixed with "_" ("foo_bar" becomes "_FOO_BAR") -# - If the value of the extra_args dictionary entries is a string, then the value will be stored in the configuration under that literal string. -# -# Missing attributes defined by both the "args" and "extra_args" arguments will both raise an AttributeError. -# -# The python package "confini" is used to process and render the configuration. -# -# The confini config schema is determined in the following manner: -# -# - If nothing is set, only the config folder in chainlib.data.config will be used as schema. -# - If base_config_dir is a string or list, the config directives from the path(s) will be added to the schema. -# -# The global override config directories are determined in the following manner: -# -# - If no default_config_dir is defined, the environment variable CONFINI_DIR will be used. -# - If default_config_dir is a string or list, values from the config directives from the path(s) will override those defined in the schema(s). -# -# The user override config directories work the same way as the global ones, but the namespace - if defined - are dependent on them. They are only applied if the CONFIG arg flag is set. User override config directories are determined in the following manner: -# -# - If --config argument is not defined and the pyxdg module is present, the first available xdg basedir is used. -# - If --config argument is defined, the directory defined by its value will be used. -# -# The namespace, if defined, will be stored under the CONFIG_USER_NAMESPACE configuration key. -# -# :param args: Argument parser object -# :type args: argparse.ArgumentParser -# :param arg_flags: Argument flags defining which arguments to process into configuration. -# :type arg_flags: confini.cli.args.ArgumentParser -# :param env: Environment variables selection -# :type env: dict -# :param extra_args: Extra arguments to process and override. -# :type extra_args: dict -# :param base_config_dir: Path(s) to one or more directories extending the base chainlib config schema. -# :type base_config_dir: list or str -# :param default_config_dir: Path(s) to one or more directories overriding the defaults defined in the schema config directories. -# :type default_config_dir: list or str -# :param user_config_dir: User xdg config basedir, with namespace -# :type user_config_dir: str -# :param default_fee_limit: Default value for fee limit argument -# :type default_fee_limit: int -# :param logger: Logger instance to use during argument processing (will use package namespace logger if None) -# :type logger: logging.Logger -# :param load_callback: Callback receiving config instance as argument after config processing and load completes. -# :type load_callback: function -# :raises AttributeError: Attribute defined in flag not found in parsed arguments -# :rtype: confini.Config -# :return: Processed configuation -# """ -# env_prefix = getattr(args, 'env_prefix', None) -# env_prefix_str = env_prefix -# if env_prefix_str == None: -# env_prefix_str = '' -# else: -# env_prefix_str += '_' -# -# env_loglevel_key_str = env_prefix_str + 'LOGLEVEL' -# env_loglevel = os.environ.get(env_loglevel_key_str) -# -# if logger == None: -# logger = logging.getLogger() -# -# if env_loglevel != None: -# env_loglevel = env_loglevel.lower() -# if env_loglevel == '0' or env_loglevel == 'no' or env_loglevel == 'none' or env_loglevel == 'disable' or env_loglevel == 'disabled' or env_loglevel == 'off': -# logging.disable() -# elif env_loglevel == '1' or env_loglevel == 'err' or env_loglevel == 'error': -# logger.setLevel(logging.ERROR) -# elif env_loglevel == '2' or env_loglevel == 'warning' or env_loglevel == 'warn': -# logger.setLevel(logging.WARNING) -# elif env_loglevel == '3' or env_loglevel == 'info': -# logger.setLevel(logging.INFO) -# else: -# valid_level = False -# try: -# num_loglevel = int(env_loglevel) -# valid_level = True -# except: -# if env_loglevel == 'debug': -# valid_level = True -# -# if not valid_level: -# raise ValueError('unknown loglevel {} set in environment variable {}'.format(env_loglevel, env_loglevel_key_str)) -# -# logger.setLevel(logging.DEBUG) -# -# -# if arg_flags & Flag.VERBOSE: -# if args.vv: -# logger.setLevel(logging.DEBUG) -# elif args.v: -# logger.setLevel(logging.INFO) -# if args.no_logs: -# logging.disable() -# -# override_config_dirs = [] -# config_dir = [cls.default_base_config_dir] -# -# if user_config_dir == None: -# try: -# import xdg.BaseDirectory -# user_config_dir = xdg.BaseDirectory.load_first_config('chainlib/eth') -# except ModuleNotFoundError: -# pass -# -# # if one or more additional base dirs are defined, add these after the default base dir -# # the consecutive dirs cannot include duplicate sections -# if base_config_dir != None: -# logg.debug('have explicit base config addition {}'.format(base_config_dir)) -# if isinstance(base_config_dir, str): -# base_config_dir = [base_config_dir] -# for d in base_config_dir: -# config_dir.append(d) -# logg.debug('processing config dir {}'.format(config_dir)) -# -# # confini dir env var will be used for override configs only in this case -# if default_config_dir == None: -# default_config_dir = env.get('CONFINI_DIR') -# if default_config_dir != None: -# if isinstance(default_config_dir, str): -# default_config_dir = [default_config_dir] -# for d in default_config_dir: -# override_config_dirs.append(d) -# -# # process config command line arguments -# if arg_flags & Flag.CONFIG: -# effective_user_config_dir = getattr(args, 'config', None) -# if effective_user_config_dir == None: -# effective_user_config_dir = user_config_dir -# if effective_user_config_dir != None: -# if getattr(args, 'namespace', None) != None: -# effective_user_config_dir = os.path.join(effective_user_config_dir, args.namespace) -# #if config_dir == None: -# # config_dir = [cls.default_base_config_dir, effective_user_config_dir] -# # logg.debug('using config arg as base config addition {}'.format(effective_user_config_dir)) -# #else: -# override_config_dirs.append(effective_user_config_dir) -# logg.debug('using config arg as config override {}'.format(effective_user_config_dir)) -# -# #if config_dir == None: -# # if default_config_dir == None: -# # default_config_dir = default_parent_config_dir -# # config_dir = default_config_dir -# # override_config_dirs = [] -# -# config = confini.Config(config_dir, env_prefix=env_prefix, override_dirs=override_config_dirs) -# config.process() -# -# if arg_flags & Flag.RAW > 0: -# config.add(getattr(args, 'raw'), '_RAW') -# -# args_override = {} -# -# if arg_flags & Flag.PROVIDER: -# args_override['RPC_PROVIDER'] = getattr(args, 'p') -# args_override['RPC_DIALECT'] = getattr(args, 'rpc_dialect') -# if arg_flags & Flag.CHAIN_SPEC: -# args_override['CHAIN_SPEC'] = getattr(args, 'i') -# if arg_flags & Flag.KEY_FILE: -# args_override['WALLET_KEY_FILE'] = getattr(args, 'y') -# fp = getattr(args, 'passphrase_file') -# if fp != None: -# st = os.stat(fp) -# if stat.S_IMODE(st.st_mode) & (stat.S_IRWXO | stat.S_IRWXG) > 0: -# logg.warning('others than owner have access on password file') -# f = open(fp, 'r') -# args_override['WALLET_PASSPHRASE'] = f.read() -# f.close() -# config.censor('PASSPHRASE', 'WALLET') -# config.dict_override(args_override, 'cli args', allow_empty=True) -# -# if arg_flags & (Flag.PROVIDER | Flag.NO_TARGET) == Flag.PROVIDER: -# config.add(getattr(args, 'height'), '_HEIGHT') -# if arg_flags & Flag.UNSAFE: -# config.add(getattr(args, 'u'), '_UNSAFE') -# if arg_flags & (Flag.SIGN | Flag.FEE): -# config.add(getattr(args, 'fee_price'), '_FEE_PRICE') -# fee_limit = getattr(args, 'fee_limit') -# if fee_limit == None: -# fee_limit = default_fee_limit -# if fee_limit == None: -# fee_limit = cls.default_fee_limit -# config.add(fee_limit, '_FEE_LIMIT') -# if arg_flags & (Flag.SIGN | Flag.NONCE): -# config.add(getattr(args, 'nonce'), '_NONCE') -# -# if arg_flags & Flag.SIGN: -# config.add(getattr(args, 's'), '_RPC_SEND') -# -# # handle wait -# wait = 0 -# if args.w: -# wait |= Flag.WAIT -# if args.ww: -# wait |= Flag.WAIT_ALL -# wait_last = wait & (Flag.WAIT | Flag.WAIT_ALL) -# config.add(bool(wait_last), '_WAIT') -# wait_all = wait & Flag.WAIT_ALL -# config.add(bool(wait_all), '_WAIT_ALL') -# -# -# if arg_flags & Flag.SEQ: -# config.add(getattr(args, 'seq'), '_SEQ') -# if arg_flags & Flag.WALLET: -# config.add(getattr(args, 'recipient'), '_RECIPIENT') -# if arg_flags & Flag.EXEC: -# config.add(getattr(args, 'executable_address'), '_EXEC_ADDRESS') -# -# if arg_flags & Flag.CONFIG: -# config.add(getattr(args, 'namespace'), 'CONFIG_USER_NAMESPACE') -# -# if arg_flags & Flag.RPC_AUTH: -# config.add(getattr(args, 'rpc_auth'), 'RPC_AUTH') -# config.add(getattr(args, 'rpc_credentials'), 'RPC_CREDENTIALS') -# -# for k in extra_args.keys(): -# logg.debug('extra_agrs {}'.format(k)) -# v = extra_args[k] -# if v == None: -# v = '_' + k.upper() -# r = getattr(args, k) -# existing_r = None -# try: -# existing_r = config.get(v) -# except KeyError: -# pass -# if existing_r == None or r != None: -# config.add(r, v, exists_ok=True) -# logg.debug('added {} to {}'.format(r, v)) -# -# if getattr(args, 'dumpconfig', None): -# if args.dumpconfig == 'ini': -# from confini.export import ConfigExporter -# exporter = ConfigExporter(config, target=sys.stdout, doc=False) -# exporter.export(exclude_sections=['config']) -# elif args.dumpconfig == 'env': -# from confini.env import export_env -# export_env(config) -# -## config_keys = config.all() -## with_values = not config.get('_RAW') -## for k in config_keys: -## if k[0] == '_': -## continue -## s = k + '=' -## if with_values: -## v = config.get(k) -## if v != None: -## s += str(v) -## s += '\n' -## dump_writer.write(s) -# sys.exit(0) -# -# if load_callback != None: -# load_callback(config) -# -# return config -# -# + def process_config(config, arg, args, flags): if arg.match('env', flags): config.set_env_prefix(getattr(args, 'env_prefix')) + config.process() + args_override = {} if arg.match('raw', flags): @@ -357,57 +84,49 @@ def process_config(config, arg, args, flags): args_override['WALLET_PASSPHRASE'] = f.read() f.close() config.censor('PASSPHRASE', 'WALLET') + config.dict_override(args_override, 'cli args', allow_empty=True) if arg.match('provider', flags): - - config.add(getattr(args, 'height'), '_HEIGHT') - #if flags & (Flag.PROVIDER | Flag.NO_TARGET) == Flag.PROVIDER: - # config.add(getattr(args, 'height'), '_HEIGHT') + if arg.match('no_target', flags, negate=True): + config.add(getattr(args, 'height'), '_HEIGHT') + + if arg.match('unsafe', flags): + config.add(getattr(args, 'u'), '_UNSAFE') - config.process() + if arg.match('sign', flags): - return config + if arg.match('fee', flags): + config.add(getattr(args, 'fee_price'), '_FEE_PRICE') + fee_limit = getattr(args, 'fee_limit') + if fee_limit == None: + fee_limit = default_fee_limit + if fee_limit == None: + fee_limit = cls.default_fee_limit + config.add(fee_limit, '_FEE_LIMIT') + if arg.match('nonce', flags): + config.add(getattr(args, 'nonce'), '_NONCE') - if flags & (Flag.PROVIDER | Flag.NO_TARGET) == Flag.PROVIDER: - config.add(getattr(args, 'height'), '_HEIGHT') - if flags & Flag.UNSAFE: - config.add(getattr(args, 'u'), '_UNSAFE') - if flags & (Flag.SIGN | Flag.FEE): - config.add(getattr(args, 'fee_price'), '_FEE_PRICE') - fee_limit = getattr(args, 'fee_limit') - if fee_limit == None: - fee_limit = default_fee_limit - if fee_limit == None: - fee_limit = cls.default_fee_limit - config.add(fee_limit, '_FEE_LIMIT') - if flags & (Flag.SIGN | Flag.NONCE): - config.add(getattr(args, 'nonce'), '_NONCE') - - if flags & Flag.SIGN: config.add(getattr(args, 's'), '_RPC_SEND') - # handle wait - wait = 0 - if args.w: - wait |= Flag.WAIT if args.ww: - wait |= Flag.WAIT_ALL - wait_last = wait & (Flag.WAIT | Flag.WAIT_ALL) - config.add(bool(wait_last), '_WAIT') - wait_all = wait & Flag.WAIT_ALL - config.add(bool(wait_all), '_WAIT_ALL') - + config.add(True, '_WAIT_ALL') + config.add(True, '_WAIT') + elif args.w: + config.add(True, '_WAIT') - if flags & Flag.SEQ: + if arg.match('seq', flags): config.add(getattr(args, 'seq'), '_SEQ') - if flags & Flag.WALLET: + + if arg.match('wallet', flags): config.add(getattr(args, 'recipient'), '_RECIPIENT') - if flags & Flag.EXEC: + + if arg.match('exec', flags): config.add(getattr(args, 'executable_address'), '_EXEC_ADDRESS') - if flags & Flag.RPC_AUTH: + + if arg.match('rpc_auth', flags): config.add(getattr(args, 'rpc_auth'), 'RPC_AUTH') config.add(getattr(args, 'rpc_credentials'), 'RPC_CREDENTIALS') - + return config diff --git a/tests/test_cli.py b/tests/test_cli.py @@ -110,6 +110,21 @@ class TestCli(unittest.TestCase): self.assertEqual(config.get('CHAIN_SPEC'), 'foo:foo:666:foo') + def test_all_args(self): + ap = ArgumentParser() + flags = self.flags.all + process_args(ap, self.arg, flags) + + args = ap.parse_args([ + '-y', 'foo', + '-i', 'foo:bar:42:baz', + ]) + + config = Config() + config = process_config(config, self.arg, args, flags) + print(config) + + # def test_args_process_extra(self): # ap = ArgumentParser() # flags = self.flags.VERBOSE | self.flags.CONFIG