chainlib

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

commit 14460ed76e2f51289feefe83f467a0fcc082dc58
parent 63df6aa6c4eaca128919c80231edeefff37c4bb8
Author: lash <dev@holbrook.no>
Date:   Wed, 11 May 2022 15:24:59 +0000

Implement cli arg handling on aiee

Diffstat:
Mchainlib/cli/arg.py | 488+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mchainlib/cli/config.py | 3++-
Mtests/test_cli.py | 53+++++++++++++++++++++++++++++++++++++++++------------
3 files changed, 320 insertions(+), 224 deletions(-)

diff --git a/chainlib/cli/arg.py b/chainlib/cli/arg.py @@ -1,227 +1,293 @@ # standard imports import logging import argparse -import enum -import os -import select +#import enum +#import os +#import select import sys -import re +#import re -# local imports -from .base import ( - default_config_dir, - Flag, - argflag_std_target, +# external imports +from aiee.arg import ( + ArgFlag as BaseArgFlag, + Arg as BaseArg, ) -logg = logging.getLogger(__name__) - - -def stdin_arg(): - """Retreive input arguments from stdin if they exist. - - Method does not block, and expects arguments to be ready on stdin before being called. - - :rtype: str - :returns: Input arguments string - """ - h = select.select([sys.stdin], [], [], 0) - if len(h[0]) > 0: - v = h[0][0].read() - return v.rstrip() - return None - -_default_long_args = { - '-a': '--recipient', - '-e': '--executable-address', - '-s': '--send', - '-y': '--key-file', - } +# local imports +#from .base import ( +# default_config_dir, +# Flag, +# argflag_std_target, +# ) -_default_dest = { - '-a': 'recipient', - '-e': 'executable_address', - } +logg = logging.getLogger(__name__) -_default_fmt = 'human' +#def stdin_arg(): +# """Retreive input arguments from stdin if they exist. +# +# Method does not block, and expects arguments to be ready on stdin before being called. +# +# :rtype: str +# :returns: Input arguments string +# """ +# h = select.select([sys.stdin], [], [], 0) +# if len(h[0]) > 0: +# 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): - """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 + if '--dumpconfig' in argv: + argv = [argv[0], '--dumpconfig'] + 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_prefix', 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): + super(ArgFlag, self).__init__() + + self.add('verbose') + self.add('config') + self.add('raw') + self.add('env_prefix') + self.add('provider') + self.add('chain_spec') + self.add('unsafe') + self.add('seq') + self.add('key_file') + self.add('fee') + self.add('nonce') + self.add('sign') + self.add('no_target') + self.add('exec') + self.add('wallet') + self.add('wait') + self.add('wait_all') + self.add('send') + self.add('rpc_auth') + self.add('fmt_human') + self.add('fmt_wire') + self.add('fmt_rpc') + self.add('veryverbose') + + self.alias('std_base', 'verbose', 'config', 'raw', 'env_prefix', 'no_target') + self.alias('std_base_read', 'verbose', 'config', 'raw', 'env_prefix', 'provider', 'chain_spec', 'seq') + self.alias('std_read', 'std_base', 'provider', 'chain_spec', 'unsafe', 'seq', 'key_file', 'fee', 'no_target') + self.alias('std_write', 'provider', 'chain_spec', 'unsafe', 'seq', 'key_file', 'sign', 'no_target', 'wait', 'wait_all', 'send', 'rpc_auth') + self.alias('std_target', 'no_target', 'exec', 'wallet') + + +class Arg(BaseArg): + + def __init__(self, flags): + super(Arg, self).__init__(flags) - 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_prefix', 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)) + self.add_long('no-logs', 'verbose', typ=bool) + self.add('v', 'verbose', typ=bool) + self.add('vv', 'verbose', check=False, typ=bool) + self.add('vvv', 'veryverbose', check=False, typ=bool) + + self.add('n', 'config') + self.set_long('n', 'namespace', dest='namespace') + self.add('c', 'config', dest='config') + self.set_long('c', 'config') + self.add_long('dumpconfig', 'config', typ=bool) diff --git a/chainlib/cli/config.py b/chainlib/cli/config.py @@ -202,7 +202,8 @@ class Config(confini.Config): config = confini.Config(config_dir, env_prefix=env_prefix, override_dirs=override_config_dirs) config.process() - config.add(getattr(args, 'raw'), '_RAW') + if arg_flags & Flag.RAW > 0: + config.add(getattr(args, 'raw'), '_RAW') args_override = {} diff --git a/tests/test_cli.py b/tests/test_cli.py @@ -3,9 +3,17 @@ import unittest import os import logging +# external imports +from aiee.arg import process_args + # local imports import chainlib.cli -from chainlib.cli.base import argflag_std_base +#from chainlib.cli.base import argflag_std_base +from chainlib.cli.arg import ( + ArgFlag, + Arg, + ArgumentParser, + ) script_dir = os.path.dirname(os.path.realpath(__file__)) data_dir = os.path.join(script_dir, 'testdata') @@ -15,28 +23,43 @@ logging.basicConfig(level=logging.DEBUG) class TestCli(unittest.TestCase): - + + def setUp(self): + self.flags = ArgFlag() + self.arg = Arg(self.flags) + + def test_args_process_single(self): - ap = chainlib.cli.arg.ArgumentParser() + ap = ArgumentParser() + flags = self.flags.VERBOSE | self.flags.CONFIG + process_args(ap, self.arg, flags) + argv = [ '-vv', '-n', 'foo', ] args = ap.parse_args(argv) - config = chainlib.cli.config.Config.from_args(args) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags) self.assertEqual(config.get('CONFIG_USER_NAMESPACE'), 'foo') def test_args_process_schema_override(self): ap = chainlib.cli.arg.ArgumentParser() + flags = self.flags.VERBOSE | self.flags.CONFIG + process_args(ap, self.arg, flags) + args = ap.parse_args([]) - config = chainlib.cli.config.Config.from_args(args, base_config_dir=config_dir) + + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, base_config_dir=config_dir) self.assertEqual(config.get('FOO_BAR'), 'baz') def test_args_process_arg_override(self): ap = chainlib.cli.arg.ArgumentParser() + flags = self.flags.VERBOSE | self.flags.CONFIG + process_args(ap, self.arg, flags) + argv = [ '-c', config_dir, @@ -44,36 +67,42 @@ class TestCli(unittest.TestCase): 'foo', ] args = ap.parse_args(argv) - config = chainlib.cli.config.Config.from_args(args, base_config_dir=config_dir) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, base_config_dir=config_dir) self.assertEqual(config.get('FOO_BAR'), 'bazbazbaz') def test_args_process_internal_override(self): ap = chainlib.cli.arg.ArgumentParser() + flags = self.flags.VERBOSE | self.flags.CONFIG + process_args(ap, self.arg, flags) + args = ap.parse_args() default_config_dir = os.path.join(config_dir, 'default') - config = chainlib.cli.config.Config.from_args(args, default_config_dir=default_config_dir) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, default_config_dir=default_config_dir) self.assertEqual(config.get('CHAIN_SPEC'), 'baz:bar:13:foo') user_config_dir = os.path.join(default_config_dir, 'user') - config = chainlib.cli.config.Config.from_args(args, default_config_dir=default_config_dir, user_config_dir=user_config_dir) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, default_config_dir=default_config_dir, user_config_dir=user_config_dir) self.assertEqual(config.get('CHAIN_SPEC'), 'foo:foo:666:foo') - config = chainlib.cli.config.Config.from_args(args, default_config_dir=default_config_dir, user_config_dir=default_config_dir) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, default_config_dir=default_config_dir, user_config_dir=default_config_dir) self.assertEqual(config.get('CHAIN_SPEC'), 'baz:bar:13:foo') ap = chainlib.cli.arg.ArgumentParser() + process_args(ap, self.arg, flags) argv = [ '-n', 'user', ] args = ap.parse_args(argv) - config = chainlib.cli.config.Config.from_args(args, default_config_dir=default_config_dir, user_config_dir=default_config_dir) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, default_config_dir=default_config_dir, user_config_dir=default_config_dir) self.assertEqual(config.get('CHAIN_SPEC'), 'foo:foo:666:foo') def test_args_process_extra(self): ap = chainlib.cli.arg.ArgumentParser() + flags = self.flags.VERBOSE | self.flags.CONFIG + process_args(ap, self.arg, flags) ap.add_argument('--foo', type=str) argv = [ '--foo', @@ -83,13 +112,13 @@ class TestCli(unittest.TestCase): extra_args = { 'foo': None, } - config = chainlib.cli.config.Config.from_args(args, extra_args=extra_args) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, extra_args=extra_args) self.assertEqual(config.get('_FOO'), 'bar') extra_args = { 'foo': 'FOOFOO', } - config = chainlib.cli.config.Config.from_args(args, extra_args=extra_args) + config = chainlib.cli.config.Config.from_args(args, arg_flags=flags, extra_args=extra_args) self.assertEqual(config.get('FOOFOO'), 'bar')