Control formatting of the argparse help argument list?

前端 未结 4 1031
再見小時候
再見小時候 2021-02-05 01:55
import argparse
parser = argparse.ArgumentParser(prog=\'tool\')
args = [(\'-u\', \'--upf\', \'ref. upf\', dict(required=\'True\')),
        (\'-s\', \'--skew\', \'ref. s         


        
相关标签:
4条回答
  • 2021-02-05 02:37

    You could supply formatter_class argument:

    parser = argparse.ArgumentParser(prog='tool',
      formatter_class=lambda prog: argparse.HelpFormatter(prog,max_help_position=27))
    
    args = [('-u', '--upf', 'ref. upf', dict(required='True')),
            ('-s', '--skew', 'ref. skew', {}),
            ('-m', '--model', 'ref. model', {})]
    for args1, args2, desc, options in args:  
         parser.add_argument(args1, args2, help=desc, **options)
    
    parser.print_help()
    

    Note: Implementation of argparse.HelpFormatter is private only the name is public. Therefore the code might stop working in future versions of argparse. File a feature request to provide a public interface for the customization of max_help_position on http://bugs.python.org/

    Output

    usage: tool [-h] -u UPF [-s SKEW] [-m MODEL]
    
    optional arguments:
      -h, --help               show this help message and exit
      -u UPF, --upf UPF        ref. upf
      -s SKEW, --skew SKEW     ref. skew
      -m MODEL, --model MODEL  ref. model
    
    0 讨论(0)
  • 2021-02-05 02:39

    If you are providing a custom formatter_class to your ArgumentParser

    parser = argparse.ArgumentParser(formatter_class=help_formatter)
    

    and then use subparsers, the formatter will only apply to the top-level help message. In order to use the same (or some other) formatter for all subparsers, you need to provide formatter_class argument for each add_parser call:

    subparsers = parser.add_subparsers(metavar="ACTION", dest="action")
    child_parser = subparsers.add_parser(
        action_name, formatter_class=help_formatter
    )
    
    0 讨论(0)
  • 2021-02-05 02:45

    Inspired by @jfs's answer, I have come up with this solution:

    def make_wide(formatter, w=120, h=36):
        """Return a wider HelpFormatter, if possible."""
        try:
            # https://stackoverflow.com/a/5464440
            # beware: "Only the name of this class is considered a public API."
            kwargs = {'width': w, 'max_help_position': h}
            formatter(None, **kwargs)
            return lambda prog: formatter(prog, **kwargs)
        except TypeError:
            warnings.warn("argparse help formatter failed, falling back.")
            return formatter
    

    Having that, you can call it with any HelpFormatter that you like:

    parser = argparse.ArgumentParser(
        formatter_class=make_wide(argparse.ArgumentDefaultsHelpFormatter)
    )
    

    or

    parser = argparse.ArgumentParser(
        formatter_class=make_wide(argparse.HelpFormatter, w=140, h=20)
    )
    

    What this does is make sure that the wider formatter can actually be created using the width and max_help_position arguments. If the private API changes, that is noted by make_wide by a TypeError and the formatter is returned unchanged. That should make the code more reliable for deployed applications.

    I'd welcome any suggestions to make this more pythonic.

    0 讨论(0)
  • 2021-02-05 02:48

    Another approach: hijack sys.argv, check it for --help and -h, if found extract help text using argparse.format_help, massage it, print it, and exit.

    import  sys, re, argparse 
    
    RGX_MID_WS = re.compile(r'(\S)\s{2,}')
    
    def main(argv):
    
    #   note add_help = False
        parser = argparse.ArgumentParser(description = '%(prog)s: testing help mods', formatter_class= argparse.RawTextHelpFormatter, add_help = False)
    
        parser.add_argument('bar', nargs='+', help='two bars that need to be frobbled')
        parser.add_argument('--foo', action='store_true', help='foo the bars before frobbling\nfoo the bars before frobbling')
        parser.add_argument('--xxxxx', nargs=2, help='many xes')
        parser.add_argument('--bacon', help ='a striped food')
        parser.add_argument('--badger', help='in a striped pyjamas')
        parser.add_argument('--animal', dest='animal', choices=('zabra', 'donkey', 'bat') ,help ='could be one of these')
    
    #   may exit
        lArgs = help_manage(parser)
        args = parser.parse_args() # args = lArgs
    
        print('bars are: ', args.bar)
    
    
    def help_manage(parser):
        """
        check for -h, --help, -h in a single-letter cluster;
        if none found, return, otherwise clean up help text and exit
        """
    
        lArgs = sys.argv[1:]
        lArgsNoHelp = [sOpt for sOpt in lArgs if (not sOpt in ('--help', '-h')) and not (sOpt[0] == '-' and sOpt[1] != '-' and 'h' in sOpt)]
    
    #   no change?  then no --help params
        if len(lArgsNoHelp) == len(lArgs): return
    
        sHelp = parser.format_help()
    
    #   to see help as formated by argparse, uncomment: 
    #   print(sHelp)
    #   exit() 
    
        for sLine in sHelp.split('\n'): print(clean_line(sLine))
    
        exit() 
    
    def clean_line(sLine):
        """
        this is just an example, and goes nowhere near covering all possible
        argument properties
        """
    #   avoid messing with usage: lines
        if 'usage' in sLine: return sLine
        if sLine.startswith('  ') and '[' in sLine: return sLine
    
        if sLine.endswith(' arguments:'): return sLine + '\n'
    
        sLine = sLine.lstrip()
    
        sLine = RGX_MID_WS.sub(r'\1\n', sLine)
        if sLine.startswith('-'): sLine = '\n' + sLine
        return sLine.replace('{', '\n(can be: ').replace('}', ')').replace('\n\n', '\n')
    
    if __name__ == '__main__':
    
        bRes =  main(sys.argv[1:])
        sys.exit(bRes)
    

    Help without formatting:

    usage: argparse_fix_min2.py [--foo] [--xxxxx XXXXX XXXXX] [--bacon BACON]
                                    [--badger BADGER] [--animal {zabra,donkey,bat}]
                                    bar [bar ...]
    
        argparse_fix_min2.py: testing help mods
    
        positional arguments:
          bar                   two bars that need to be frobbled
    
        optional arguments:
          --foo                 foo the bars before frobbling
                                foo the bars before frobbling
          --xxxxx XXXXX XXXXX   many xes
          --bacon BACON         a striped food
          --badger BADGER       in a striped pyjamas
          --animal {zabra,donkey,bat}
                                could be one of these
    
    

    with formatting:

    usage: argparse_fix_min2.py [--foo] [--xxxxx XXXXX XXXXX] [--bacon BACON]
                                    [--badger BADGER] [--animal {zabra,donkey,bat}]
                                    bar [bar ...]
    
        argparse_fix_min2.py: testing help mods
    
        positional arguments:
    
        bar
        two bars that need to be frobbled
    
        optional arguments:
    
    
        --foo
        foo the bars before frobbling
        foo the bars before frobbling
    
        --xxxxx XXXXX XXXXX
        many xes
    
        --bacon BACON
        a striped food
    
        --badger BADGER
        in a striped pyjamas
    
        --animal 
        (can be: zabra,donkey,bat)
        could be one of these
    
        """
    
    
    0 讨论(0)
提交回复
热议问题