Source code for utool.util_arg

# -*- coding: utf-8 -*-
"""
Handles command line parsing
"""
from __future__ import absolute_import, division, print_function, unicode_literals
import sys
import six
import os
import itertools
#import six
import argparse
from utool import util_inject
from utool import util_type
from utool._internal import meta_util_six, meta_util_arg, meta_util_iter
print, print_, printDBG, rrr, profile = util_inject.inject(__name__, '[arg]')

#STRICT = '--nostrict' not in sys.argv
DEBUG2       = meta_util_arg.DEBUG2
NO_ASSERTS   = meta_util_arg.NO_ASSERTS
SAFE         = meta_util_arg.SAFE
STRICT       = meta_util_arg.STRICT
REPORT       = meta_util_arg.REPORT
SUPER_STRICT = meta_util_arg.SUPER_STRICT
TRACE        = meta_util_arg.TRACE
USE_ASSERT   = meta_util_arg.USE_ASSERT
SILENT       = meta_util_arg.SILENT
VERBOSE      = meta_util_arg.VERBOSE
VERYVERBOSE  = meta_util_arg.VERYVERBOSE
NOT_QUIET    = meta_util_arg.NOT_QUIET
QUIET        = meta_util_arg.QUIET


#(switch, type, default, help)
# TODO: make a static help file available via printing
__REGISTERED_ARGS__ = []


[docs]def get_module_verbosity_flags(*labels): """ checks for standard flags for enableing module specific verbosity """ verbose_prefix_list = ['--verbose-', '--verb', '--verb-'] veryverbose_prefix_list = ['--veryverbose-', '--veryverb', '--veryverb-'] verbose_flags = tuple( [prefix + lbl for prefix, lbl in itertools.product(verbose_prefix_list, labels)]) veryverbose_flags = tuple( [prefix + lbl for prefix, lbl in itertools.product(veryverbose_prefix_list, labels)]) veryverbose_module = get_argflag(veryverbose_flags) or VERYVERBOSE verbose_module = (get_argflag(verbose_flags) or veryverbose_module or VERBOSE) if veryverbose_module: verbose_module = 2 return verbose_module, veryverbose_module
get_verbflag = get_module_verbosity_flags
[docs]def reset_argrecord(): """ forgets about the args already parsed """ global __REGISTERED_ARGS__ __REGISTERED_ARGS__ = []
def _register_arg(argstr_list, type_, default, help_): # TODO REGISTER PARENTS global __REGISTERED_ARGS__ __REGISTERED_ARGS__.append((argstr_list, type_, default, help_))
[docs]def autogen_argparse_block(extra_args=[]): """ SHOULD TURN ANY REGISTERED ARGS INTO A A NEW PARSING CONFIG FILE FOR BETTER --help COMMANDS import utool as ut __REGISTERED_ARGS__ = ut.util_arg.__REGISTERED_ARGS__ Args: extra_args (list): (default = []) CommandLine: python -m utool.util_arg --test-autogen_argparse_block Example: >>> # DISABLE_DOCTEST >>> import utool as ut >>> extra_args = [] >>> result = ut.autogen_argparse_block(extra_args) >>> print(result) """ #import utool as ut # NOQA #__REGISTERED_ARGS__ # TODO FINISHME grouped_args = [] # Group similar a args for argtup in __REGISTERED_ARGS__: argstr_list, type_, default, help_ = argtup argstr_set = set(argstr_list) # <MULTIKEY_SETATTR> # hack in multikey setattr n**2 yuck found = False for index, (keyset, vals) in enumerate(grouped_args): if len(keyset.intersection(argstr_set)) > 0: # update keyset.update(argstr_set) vals.append(argtup) found = True break if not found: new_keyset = argstr_set new_vals = [argtup] grouped_args.append((new_keyset, new_vals)) # </MULTIKEY_SETATTR> # DEBUG multi_groups = [] for keyset, vals in grouped_args: if len(vals) > 1: multi_groups.append(vals) if len(multi_groups) > 0: import utool as ut print('Following arg was specified multiple times') print(ut.list_str(multi_groups, newlines=2)) #@profile
[docs]def get_argflag(argstr_, default=False, help_='', return_specified=None, need_prefix=True, return_was_specified=False, argv=sys.argv, **kwargs): """ Checks if the commandline has a flag or a corresponding noflag Args: argstr_ (str, list, or tuple): the flag to look for default (bool): dont use this (default = False) help_ (str): a help string (default = '') return_specified (bool): returns if flag was specified or not (default = False) Returns: tuple: (parsed_val, was_specified) TODO: depricate return_was_specified CommandLine: python -m utool.util_arg --exec-get_argflag --noface --exec-mode python -m utool.util_arg --exec-get_argflag --foo --exec-mode python -m utool.util_arg --exec-get_argflag --no-foo --exec-mode python -m utool.util_arg --exec-get_argflag --foo=True --exec-mode python -m utool.util_arg --exec-get_argflag --foo=False --exec-mode Example: >>> # DISABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> argstr_ = '--foo' >>> default = False >>> help_ = '' >>> return_specified = True >>> (parsed_val, was_specified) = get_argflag(argstr_, default, help_, return_specified) >>> result = ('(parsed_val, was_specified) = %s' % (str((parsed_val, was_specified)),)) >>> print(result) """ assert isinstance(default, bool), 'default must be boolean' argstr_list = meta_util_iter.ensure_iterable(argstr_) #if VERYVERBOSE: # print('[util_arg] checking argstr_list=%r' % (argstr_list,)) # arg registration _register_arg(argstr_list, bool, default, help_) parsed_val = default was_specified = False debug = False # Check environment variables for default as well as argv import os #""" #set UTOOL_NOCNN=True #export UTOOL_NOCNN True #""" #argv_orig = argv[:] # HACK: make this not happen very time you loop for key, val in os.environ.items(): key = key.upper() sentinal = 'UTOOL_' if key.startswith(sentinal): flag = '--' + key[len(sentinal):].lower().replace('_', '-') if val.upper() in ['TRUE', 'ON']: pass elif val.upper() in ['FALSE', 'OFF']: continue #flag += '=False' new_argv = [flag] argv = argv[:] + new_argv if debug: print('argv.extend(new_argv=%r)' % (new_argv,)) for argstr in argstr_list: #if VERYVERBOSE: # print('[util_arg] * checking argstr=%r' % (argstr,)) if not (argstr.find('--') == 0 or (argstr.find('-') == 0 and len(argstr) == 2)): raise AssertionError('Invalid argstr: %r' % (argstr,)) if not need_prefix: noprefix = argstr.replace('--', '') if noprefix in argv: parsed_val = True was_specified = True break #if argstr.find('--no') == 0: #argstr = argstr.replace('--no', '--') noarg = argstr.replace('--', '--no') if argstr in argv: parsed_val = True was_specified = True #if VERYVERBOSE: # print('[util_arg] * ...WAS_SPECIFIED. AND PARSED') break elif noarg in argv: parsed_val = False was_specified = True #if VERYVERBOSE: # print('[util_arg] * ...WAS_SPECIFIED. AND NOT PARSED') break elif argstr + '=True' in argv: parsed_val = True was_specified = True break elif argstr + '=False' in argv: parsed_val = False was_specified = True break if return_specified is None: return_specified = return_was_specified if return_specified: return parsed_val, was_specified else: return parsed_val # TODO: rectify with meta_util_arg # This has diverged and is now better #from utool._internal.meta_util_arg import get_argval #@profile
[docs]def get_argval(argstr_, type_=None, default=None, help_=None, smartcast=True, return_specified=None, argv=None, verbose=None, debug=None, return_was_specified=False): r""" Returns a value of an argument specified on the command line after some flag Args: argstr_ (str or tuple): string or tuple of strings denoting the command line values to parse type_ (None): type of the variable to parse (default = None) default (None): (default = None) help_ (None): help for this argument (not fully integrated) (default = None) smartcast (bool): tries to be smart about casting the parsed strings (default = True) return_specified (bool): (default = False) argv (None): override sys.argv with custom command line vector (default = None) TODO: depricate return_was_specified CommandLine: python -m utool.util_arg --test-get_argval python -m utool.util_arg --exec-get_argval:0 python -m utool.util_arg --exec-get_argval:1 python -c "import utool; print([(type(x), x) for x in [utool.get_argval('--quest')]])" --quest="holy grail" python -c "import utool; print([(type(x), x) for x in [utool.get_argval('--quest')]])" --quest="42" python -c "import utool; print([(type(x), x) for x in [utool.get_argval('--quest')]])" --quest=42 python -c "import utool; print([(type(x), x) for x in [utool.get_argval('--quest')]])" --quest 42 python -c "import utool; print([(type(x), x) for x in [utool.get_argval('--quest', float)]])" --quest 42 python -c "import utool; print([(type(x), x) for x in [utool.get_argval(('--nAssign'), int)]])" --nAssign 42 python -c "import utool; print([(type(x), x) for x in [utool.get_argval(('--test'), str)]])" --test python -c "import utool; print([(type(x), x) for x in [utool.get_argval(('--test'), str)]])" --test "foobar is good" --youbar ok Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> import sys >>> argv = ['--spam', 'eggs', '--quest=holy grail', '--ans=42', '--the-val=1,2,3'] >>> # specify a list of args and kwargs to get_argval >>> argstr_kwargs_list = [ >>> ('--spam', dict(type_=str, default=None, argv=argv)), >>> ('--quest', dict(type_=str, default=None, argv=argv)), >>> (('--ans', '--foo'), dict(type_=int, default=None, argv=argv)), >>> (('--not-there', '--absent'), dict(argv=argv)), >>> ('--the_val', dict(type_=list, argv=argv)), >>> ('--the-val', dict(type_=list, argv=argv)), >>> ] >>> # Execute the command with for each of the test cases >>> res_list = [] >>> argstr_list = ut.get_list_column(argstr_kwargs_list, 0) >>> for argstr_, kwargs in argstr_kwargs_list: >>> res = get_argval(argstr_, **kwargs) >>> res_list.append(res) >>> result = ut.dict_str(ut.odict(zip(argstr_list, res_list))) >>> result = result.replace('u\'', '\'') # hack >>> print(result) { '--spam': 'eggs', '--quest': 'holy grail', ('--ans', '--foo'): 42, ('--not-there', '--absent'): None, '--the_val': [1, 2, 3], '--the-val': [1, 2, 3], } Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> import sys >>> argv = ['--slice1', '::', '--slice2=4:', '--slice3=::4', '--slice4', '[1,2,3,4]', '--slice5=3'] >>> # specify a list of args and kwargs to get_argval >>> argstr_kwargs_list = [ >>> ('--slice1', dict(type_='fuzzy_subset', default=None, argv=argv)), >>> ('--slice2', dict(type_='fuzzy_subset', default=None, argv=argv)), >>> ('--slice3', dict(type_='fuzzy_subset', default=None, argv=argv)), >>> ('--slice4', dict(type_='fuzzy_subset', default=None, argv=argv)), >>> ('--slice5', dict(type_='fuzzy_subset', default=None, argv=argv)), >>> ] >>> # Execute the command with for each of the test cases >>> res_list = [] >>> argstr_list = ut.get_list_column(argstr_kwargs_list, 0) >>> list1 = [1,3,5,7,9] >>> import numpy as np >>> list2 = np.array([[1, 2],[3,4],[5,6],[7,8],[9,1]]) >>> for argstr_, kwargs in argstr_kwargs_list: >>> res = get_argval(argstr_, **kwargs) >>> print('---') >>> print('res = %r' % (res,)) >>> print('list1[%r=%r] = %r' % (argstr_, res, ut.take(list1, res),)) >>> print('list2[%r=%r] = %r' % (argstr_, res, list2[res].tolist(),)) >>> res_list.append(res) >>> result = ut.dict_str(ut.odict(zip(argstr_list, res_list))) >>> result = result.replace('u\'', '\'') # hack >>> print(result) """ if verbose is None: pass # verbose = VERYVERBOSE if debug is None: # debug = VERYVERBOSE pass if argv is None: argv = sys.argv if verbose: print('[get_argval] Searching Commandline for argstr_=%r' % (argstr_,)) #print('[get_argval] * type_ = %r' % (type_,)) #print('[get_argval] * default = %r' % (default,)) #print('[get_argval] * help_ = %r' % (help_,)) #print('[get_argval] * smartcast = %r' % (smartcast,)) if return_specified is None: return_specified = return_was_specified #print(argstr_) was_specified = False arg_after = default if type_ is bool: arg_after = False if default is None else default try: # New for loop way (accounts for =) argstr_list = meta_util_iter.ensure_iterable(argstr_) # arg registration _register_arg(argstr_list, type_, default, help_) # expand out hypens EXPAND_HYPENS = True if EXPAND_HYPENS: argstr_list2 = [] seen_ = set([]) for argstr in argstr_list: if argstr not in seen_: argstr_list2.append(argstr) seen_.add(argstr) if argstr.startswith('--'): num = 2 elif argstr.startswith('-'): num = 1 else: continue argstr2_0 = argstr[0:num] + argstr[num:].replace('_', '-') argstr2_1 = argstr[0:num] + argstr[num:].replace('-', '_') if argstr2_0 not in seen_: argstr_list2.append(argstr2_0) seen_.add(argstr2_0) if argstr2_1 not in seen_: argstr_list2.append(argstr2_1) seen_.add(argstr2_1) argstr_list = argstr_list2 # Check environment variables for default as well as argv import os """ set UTOOL_NOCNN=True export UTOOL_NOCNN True """ #argv_orig = argv[:] for key, val in os.environ.items(): key = key.upper() sentinal = 'UTOOL_' if key.startswith(sentinal): key = '--' + key[len(sentinal):] new_argv = [key, val] argv = argv[:] + new_argv if debug: print('argv.extend(new_argv=%r)' % (new_argv,)) for argx, item in enumerate(argv): for argstr in argstr_list: if item == argstr: if type_ is bool: if debug: print('[get_argval] ... argstr=%r' % (argstr,)) print('[get_argval] ... Found bool argx=%r' % (argx,)) arg_after = True was_specified = True break if argx < len(argv): if type_ is list: # HACK FOR LIST. TODO INTEGRATE if debug: print('[get_argval] ... argstr=%r' % (argstr,)) print('[get_argval] ... Found noequal list argx=%r' % (argx,)) arg_after = parse_arglist_hack(argx, argv=argv) if debug: print('[get_argval] ... arg_after=%r' % (arg_after,)) print('argv=%r' % (argv,)) if smartcast: arg_after = list(map(util_type.smart_cast2, arg_after)) if debug: print('[get_argval] ... smartcast arg_after=%r' % (arg_after,)) else: if debug: print('[get_argval] ... argstr=%r' % (argstr,)) print('[get_argval] ... Found type_=%r argx=%r' % (type_, argx,)) if type_ is None: #arg_after = util_type.try_cast(argv[argx + 1], type_) arg_after = util_type.smart_cast2(argv[argx + 1]) else: arg_after = util_type.try_cast(argv[argx + 1], type_) if was_specified: print('WARNING: argstr=%r already specified' % (argstr,)) was_specified = True break elif item.startswith(argstr + '='): val_after = ''.join(item.split('=')[1:]) if type_ is list: # HACK FOR LIST. TODO INTEGRATE if verbose: print('[get_argval] ... Found equal list') val_after_ = val_after.rstrip(']').lstrip('[') arg_after = val_after_.split(',') if smartcast: arg_after = list(map(util_type.smart_cast2, arg_after)) else: if type_ is None: arg_after = util_type.smart_cast2(val_after) else: arg_after = util_type.try_cast(val_after, type_) if not isinstance(type_, six.string_types) and issubclass(type_, six.string_types): if arg_after == 'None': # hack arg_after = None if was_specified: print('WARNING: argstr=%r already specified' % (argstr,)) was_specified = True break except Exception as ex: import utool as ut ut.printex(ex, 'problem in arg_val', keys=['type_']) if ut.SUPER_STRICT: raise pass if verbose: print('[get_argval] ... Parsed arg_after=%r, was_specified=%r' % (arg_after, was_specified)) if return_specified: return arg_after, was_specified else: return arg_after
@profile
[docs]def parse_cfgstr_list(cfgstr_list, smartcast=True, oldmode=True): r""" Parses a list of items in the format ['var1:val1', 'var2:val2', 'var3:val3'] the '=' character can be used instead of the ':' character if desired Args: cfgstr_list (list): Returns: dict: cfgdict Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> cfgstr_list = ['var1=val1', 'var2=1', 'var3=1.0', 'var4=None', 'var5=[1,2,3]', 'var6=(a,b,c)'] >>> smartcast = True >>> cfgdict = parse_cfgstr_list(cfgstr_list, smartcast, oldmode=False) >>> result = ut.repr2(cfgdict, sorted_=True, newlines=False) >>> print(result) {'var1': 'val1', 'var2': 1, 'var3': 1.0, 'var4': None, 'var5': [1, 2, 3], 'var6': ('a', 'b', 'c')} {'var1': 'val1', 'var2': 1, 'var3': 1.0, 'var4': None} {'var4': None, 'var1': 'val1', 'var3': 1.0, 'var2': 1} """ cfgdict = {} for item in cfgstr_list: if item == '': continue if oldmode: keyval_tup = item.replace('=', ':').split(':') assert len(keyval_tup) == 2, '[!] Invalid cfgitem=%r' % (item,) key, val = keyval_tup else: keyval_tup = item.split('=') if len(keyval_tup) == 1: # single specifications are interpeted as booleans key = keyval_tup[0] val = True else: assert len(keyval_tup) >= 2, '[!] Invalid cfgitem=%r' % (item,) key, val = keyval_tup[0], '='.join(keyval_tup[1:]) if smartcast: val = util_type.smart_cast2(val) cfgdict[key] = val return cfgdict
[docs]def parse_arglist_hack(argx, argv=None): if argv is None: argv = sys.argv arglist = [] #import utool as ut #ut.embed() for argx2 in range(argx + 1, len(argv)): listarg = argv[argx2] if listarg.startswith('-'): break else: arglist.append(listarg) return arglist
[docs]def get_arg_dict(argv=None, prefix_list=['--'], type_hints={}): r""" Yet another way for parsing args CommandLine: python -m utool.util_arg --exec-get_arg_dict python -m utool.util_arg --test-get_arg_dict Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> import shlex >>> argv = shlex.split('--test-show_name --name=IBEIS_PZ_0303 --db testdb3 --save "~/latex/crall-candidacy-2015/figures/IBEIS_PZ_0303.jpg" --dpath figures --caption="Shadowed" --figsize=11,3 --no-figtitle -t foo bar baz biz --notitle') >>> arg_dict = ut.get_arg_dict(argv, prefix_list=['--', '-'], type_hints={'t': list}) >>> result = ut.dict_str(arg_dict) >>> # verify results >>> print(result) { 'caption': 'Shadowed', 'db': 'testdb3', 'dpath': 'figures', 'figsize': '11,3', 'name': 'IBEIS_PZ_0303', 'no-figtitle': True, 'notitle': True, 'save': '~/latex/crall-candidacy-2015/figures/IBEIS_PZ_0303.jpg', 't': ['foo', 'bar', 'baz', 'biz'], 'test-show_name': True, } """ if argv is None: argv = sys.argv arg_dict = {} def startswith_prefix(arg): return any([arg.startswith(prefix) for prefix in prefix_list]) def argx_has_value(argv, argx): # Check if has a value if argv[argx].find('=') > -1: return True if argx + 1 < len(argv) and not startswith_prefix(argv[argx + 1]): return True return False def get_arg_value(argv, argx, argname): if argv[argx].find('=') > -1: return '='.join(argv[argx].split('=')[1:]) else: type_ = type_hints.get(argname, None) if type_ is None: return argv[argx + 1] else: return parse_arglist_hack(argx, argv=argv) for argx in range(len(argv)): arg = argv[argx] for prefix in prefix_list: if arg.startswith(prefix): argname = arg[len(prefix):] if argx_has_value(argv, argx): if arg.find('=') > -1: argname = arg[len(prefix):arg.find('=')] argvalue = get_arg_value(argv, argx, argname) arg_dict[argname] = argvalue else: arg_dict[argname] = True break return arg_dict # Backwards Compatibility Aliases
get_arg = get_argval get_flag = get_argflag #def argv_flag(name, default, **kwargs): # if name.find('--') == 0: # name = name[2:] # if '--' + name in sys.argv and default is False: # return True # if '--no' + name in sys.argv and default is True: # return False # return default # ---- OnTheFly argparse ^^^^ # ---- Documented argparse VVVV
[docs]def switch_sanataize(switch): if isinstance(switch, six.string_types): dest = switch.strip('-').replace('-', '_') else: if isinstance(switch, tuple): switch = switch elif isinstance(switch, list): switch = tuple(switch) dest = switch[0].strip('-').replace('-', '_') return dest, switch
[docs]class ArgumentParser2(object): """ Wrapper around argparse.ArgumentParser with convinence functions """ def __init__(self, parser): self.parser = parser
[docs] def add_arg(self, switch, *args, **kwargs): #print('[argparse2] add_arg(%r) ' % (switch,)) if isinstance(switch, tuple): args = tuple(list(switch) + list(args)) return self.parser.add_argument(*args, **kwargs) else: return self.parser.add_argument(switch, *args, **kwargs)
[docs] def add_meta(self, switch, type, default=None, help='', **kwargs): #print('[argparse2] add_meta()') dest, switch = switch_sanataize(switch) self.add_arg(switch, metavar=dest, type=type, default=default, help=help, **kwargs)
[docs] def add_flag(self, switch, default=False, **kwargs): #print('[argparse2] add_flag()') action = 'store_false' if default else 'store_true' dest, switch = switch_sanataize(switch) self.add_arg(switch, dest=dest, action=action, default=default, **kwargs)
[docs] def add_int(self, switch, *args, **kwargs): self.add_meta(switch, util_type.fuzzy_int, *args, **kwargs)
[docs] def add_intlist(self, switch, *args, **kwargs): self.add_meta(switch, util_type.fuzzy_int, *args, nargs='*', **kwargs)
add_ints = add_intlist
[docs] def add_strlist(self, switch, *args, **kwargs): self.add_meta(switch, str, *args, nargs='*', **kwargs)
add_strs = add_strlist
[docs] def add_float(self, switch, *args, **kwargs): self.add_meta(switch, float, *args, **kwargs)
[docs] def add_str(self, switch, *args, **kwargs): self.add_meta(switch, str, *args, **kwargs)
[docs] def add_argument_group(self, *args, **kwargs): return ArgumentParser2(self.parser.add_argument_group(*args, **kwargs))
[docs]def autogen_argparse2(dpath_list): r""" FUNCTION IS NOT FULLY IMPLEMENTED CURRENTLY ONLY RETURNS LIST OF FLAGS THAT THE PROGRAM SILENTLY TAKES Example: >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> dpath_list = [ ... ut.truepath('~/code/utool/utool'), ... ut.truepath('~/code/ibeis/ibeis'), ... ut.truepath('~/code/guitool/guitool'), ... ut.truepath('~/code/vtool/vtool'), ... ut.truepath('~/code/plottool/plottool'), ... ] >>> flagtups_list = autogen_argparse2(dpath_list) >>> flagtup_list_ = [ut.regex_replace('[)(\']','',tupstr) for tupstr in ut.flatten(flagtups_list)] >>> flagtup_list = ut.flatten([tupstr.split(',') for tupstr in flagtup_list_]) >>> flagtup_set = set([tupstr.strip() for tupstr in flagtup_list if tupstr.find('=') == -1]) >>> print('\n'.join(flagtup_set)) """ import utool as ut import parse include_patterns = ['*.py'] regex_list = ['get_argflag', 'get_argval'] recursive = True result = ut.grep(regex_list, recursive, dpath_list, include_patterns, verbose=True) (found_filestr_list, found_lines_list, found_lxs_list) = result # TODO: Check to see if in a comment block flagtups_list = [] for found_lines in found_lines_list: flagtups = [] for line in found_lines: line_ = ut.regex_replace('#.*', '', line) argval_parse_list = [ '\'{flag}\' in sys.argv', 'get_argval({flagtup}, type={type}, default={default})', 'get_argval({flagtup}, {type}, default={default})', 'get_argval({flagtup}, {type}, {default})', 'get_argval({flagtup})', ] argflag_parse_list = [ 'get_argflag({flagtup})', ] def parse_pattern_list(parse_list, line): #result_list = [] result = None for pattern in parse_list: result = parse.parse('{_prefix}' + pattern, line_) if result is not None: break #if len(result_list) > 1: # print('warning') #result_list.append(result) return result val_result = parse_pattern_list(argval_parse_list, line) flag_result = parse_pattern_list(argflag_parse_list, line) if flag_result is None and val_result is None: print('warning1') elif flag_result is not None and val_result is not None: print('warning2') else: result = flag_result if val_result is None else val_result flagtups.append(result['flagtup']) flagtups_list.append(flagtups) return flagtups_list
[docs]def make_argparse2(prog='Program', description='', *args, **kwargs): formatter_classes = [ argparse.RawDescriptionHelpFormatter, argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter] parser = argparse.ArgumentParser(prog=prog, description=description, prefix_chars='+-', formatter_class=formatter_classes[2], *args, **kwargs) return ArgumentParser2(parser) # Decorators which control program flow based on sys.argv # the decorated function does not execute without its corresponding # flag
[docs]def get_fpath_args(arglist_=None, pat='*'): import utool if arglist_ is None: arglist_ = sys.argv[1:] input_path_list = [] for input_path in arglist_: input_path = utool.truepath(input_path) if os.path.isdir(input_path): input_path_list.extend(utool.glob(input_path, pat, recursive=False, with_dirs=False)) else: input_path_list.append(input_path) return input_path_list
[docs]def argv_flag_dec(*argin, **kwargs): """ Decorators which control program flow based on sys.argv the decorated function does not execute without its corresponding flag Kwargs: default, quiet, indent, default ReturnKwargs: alias_flags """ kwargs = kwargs.copy() kwargs['default'] = kwargs.get('default', False) from utool import util_decor @util_decor.ignores_exc_tb(outer_wrapper=False) def wrap_argv_flag_dec(func): return __argv_flag_dec(func, **kwargs) assert len(argin) < 2, 'specify 0 or 1 args' if len(argin) == 1 and util_type.is_funclike(argin[0]): func = argin[0] return wrap_argv_flag_dec(func) else: return wrap_argv_flag_dec
[docs]def argv_flag_dec_true(func, **kwargs): return __argv_flag_dec(func, default=True, **kwargs)
def __argv_flag_dec(func, default=False, quiet=QUIET, indent=False): """ Logic for controlling if a function gets called based on command line """ from utool import util_decor flag = meta_util_six.get_funcname(func) if flag.find('no') == 0: flag = flag[2:] flag = '--' + flag.replace('_', '-') @util_decor.ignores_exc_tb(outer_wrapper=False) def GaurdWrapper(*args, **kwargs): from utool import util_print # FIXME: the --print-all is a hack default_ = kwargs.pop('default', default) alias_flags = kwargs.pop('alias_flags', []) is_flagged = (get_argflag(flag, default_) or get_argflag('--print-all') or any([get_argflag(_) for _ in alias_flags])) if is_flagged: func_label = flag.replace('--', '').replace('print-', '') print('') print('\n+ --- ' + func_label + ' ___') use_indent = indent is not False if indent is True: indent_ = '[%s]' % func_label else: indent_ = indent with util_print.Indenter(indent_, enabled=use_indent): ret = func(*args, **kwargs) print('L ___ ' + func_label + '___\n') return ret else: PRINT_DISABLED_FLAGDEC = not get_argflag( '--noinform', help_='does not print disabled flag decorators') if not quiet and PRINT_DISABLED_FLAGDEC: #print('\n~~~ %s ~~~' % flag) print('~~~ %s ~~~' % flag) meta_util_six.set_funcname(GaurdWrapper, meta_util_six.get_funcname(func)) return GaurdWrapper @profile
[docs]def argparse_dict(default_dict_, lbl=None, verbose=None, only_specified=False, force_keys={}, type_hint=None, alias_dict={}): r""" Gets values for a dict based on the command line Args: default_dict_ (?): only_specified (bool): if True only returns keys that are specified on commandline. no defaults. Returns: dict_: dict_ - a dictionary CommandLine: python -m utool.util_arg --test-argparse_dict python -m utool.util_arg --test-argparse_dict --foo=3 python -m utool.util_arg --test-argparse_dict --flag1 python -m utool.util_arg --test-argparse_dict --flag2 python -m utool.util_arg --test-argparse_dict --noflag2 python -m utool.util_arg --test-argparse_dict --thresh=43 python -m utool.util_arg --test-argparse_dict --bins=-10 python -m utool.util_arg --test-argparse_dict --bins=-10 --only-specified --helpx Example: >>> # DISABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> # build test data >>> default_dict_ = { ... 'bins': 8, ... 'foo': None, ... 'flag1': False, ... 'flag2': True, ... 'max': 0.2, ... 'neg': -5, ... 'thresh': -5.333, ... } >>> # execute function >>> only_specified = ut.get_argflag('--only-specified') >>> dict_ = argparse_dict(default_dict_, only_specified=only_specified) >>> # verify results >>> result = ut.dict_str(dict_, sorted_=True) >>> print(result) """ if verbose is None: verbose = VERBOSE_ARGPARSE def make_argstrs(key, prefix_list): for prefix in prefix_list: yield prefix + key yield prefix + key.replace('-', '_') yield prefix + key.replace('_', '-') def get_dictkey_cmdline_val(key, default, type_hint): # see if the user gave a commandline value for this dict key defaulttype_ = None if default is None else type(default) if type_hint is None: type_ = defaulttype_ elif isinstance(type_hint, dict): type_ = type_hint.get(key, defaulttype_) elif isinstance(type_hint, type): type_ = type_hint else: raise NotImplementedError('Unknown type of type_hint=%r' % (type_hint,)) was_specified = False if isinstance(default, bool): val = default if default is True: falsekeys = list(set(make_argstrs(key, ['--no', '--no-']))) notval, was_specified = get_argflag(falsekeys, return_specified=True) val = not notval if not was_specified: truekeys = list(set(make_argstrs(key, ['--']))) val_, was_specified = get_argflag(truekeys, return_specified=True) if was_specified: val = val_ elif default is False: truekeys = list(set(make_argstrs(key, ['--']))) val, was_specified = get_argflag(truekeys, return_specified=True) else: argtup = list(set(make_argstrs(key, ['--']))) #if key == 'species': # import utool as ut # ut.embed() val, was_specified = get_argval(argtup, type_=type_, default=default, return_specified=True) return val, was_specified dict_ = {} num_specified = 0 for key, default in six.iteritems(default_dict_): val, was_specified = get_dictkey_cmdline_val(key, default, type_hint) for alias_key in alias_dict.get(key, []): val, was_specified = get_dictkey_cmdline_val(alias_key, default, type_hint) if was_specified: break if VERBOSE_ARGPARSE: if was_specified: num_specified += 1 print('[argparse_dict] Specified key=%r, val=%r' % (key, val)) #if key == 'foo': # import utool as ut # ut.embed() if not only_specified or was_specified or key in force_keys: dict_[key] = val if VERBOSE_ARGPARSE: print('[argparse_dict] num_specified = %r' % (num_specified,)) print('[argparse_dict] force_keys = %r' % (force_keys,)) #dict_ = {key: get_dictkey_cmdline_val(key, default) for key, default in #six.iteritems(default_dict_)} if verbose: for key in dict_: if dict_[key] != default_dict_[key]: print('[argparse_dict] GOT ARGUMENT: cfgdict[%r] = %r' % (key, dict_[key])) do_helpx = get_argflag('--helpx', help_='Specifies that argparse_dict should print help and quit') if get_argflag(('--help', '--help2')) or do_helpx: import utool as ut print('COMMAND LINE IS ACCEPTING THESE PARAMS WITH DEFAULTS:') if lbl is not None: print(lbl) #print(ut.align(ut.dict_str(dict_, sorted_=True), ':')) print(ut.align(ut.dict_str(default_dict_, sorted_=True), ':')) if do_helpx: sys.exit(1) return dict_
[docs]def get_argv_tail(scriptname, prefer_main=None, argv=sys.argv): r""" gets the rest of the arguments after a script has been invoked hack. accounts for python -m scripts. Args: scriptname (str): CommandLine: python -m utool.util_arg --test-get_argv_tail Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> from os.path import relpath, dirname >>> scriptname = 'utool.util_arg' >>> prefer_main = False >>> argv=['python', '-m', 'utool.util_arg', '--test-get_argv_tail'] >>> tail = get_argv_tail(scriptname, prefer_main, argv) >>> # hack >>> tail[0] = ut.ensure_unixslash(relpath(tail[0], dirname(dirname(ut.__file__)))) >>> result = ut.repr2(tail) >>> print(result) ['utool/util_arg.py', '--test-get_argv_tail'] Example: >>> # ENABLE_DOCTEST >>> from utool.util_arg import * # NOQA >>> import utool as ut >>> from os.path import relpath, dirname >>> scriptname = 'utprof.py' >>> prefer_main = True >>> argv=['utprof.py', '-m', 'utool', '--tf', 'get_argv_tail'] >>> tail = get_argv_tail(scriptname, prefer_main, argv) >>> # hack >>> tail[0] = ut.ensure_unixslash(relpath(tail[0], dirname(dirname(ut.__file__)))) >>> result = ut.repr2(tail) >>> print(result) ['utool/__main__.py', '--tf', 'get_argv_tail'] """ import utool as ut modname = ut.get_argval('-m', help_='specify module name to profile', argv=argv) if modname is not None: # hack to account for -m scripts modpath = ut.get_modpath_from_modname(modname, prefer_main=prefer_main) argvx = argv.index(modname) + 1 argv_tail = [modpath] + argv[argvx:] else: try: argvx = argv.index(scriptname) except ValueError: for argvx, arg in enumerate(argv): # HACK if scriptname in arg: break argv_tail = argv[(argvx + 1):] return argv_tail # alias
parse_dict_from_argv = argparse_dict get_dict_vals_from_commandline = argparse_dict VERBOSE_ARGPARSE = get_argflag( ('--verbose-argparse', '--verb-argparse', '--verb-arg', '--verbarg'), help_='debug util_arg') #if __name__ == '__main__': # """ # CommandLine: # python utool/util_arg.py --test-autogen_argparse2 # """ # from utool import util_tests # util_tests.doctest_funcs([autogen_argparse2]) if __name__ == '__main__': """ CommandLine: python -m utool.util_arg python -m utool.util_arg --allexamples python -m utool.util_arg --allexamples --noface --nosrc """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()