2014-05-09 4 views
5

Durante la ricerca di metodi più veloci per analizzare gli argomenti della riga di comando nei miei script, mi sono imbattuto nello argh library.Libreria argh di Python: preservare la formattazione della docstring nel messaggio di aiuto

Mi piacciono molto le funzionalità di argh ma ho riscontrato uno svantaggio che mi impedisce di utilizzarlo, e questo ha a che fare con il messaggio di aiuto predefinito che viene visualizzato se sto richiamando l'opzione -help: per l'impostazione predefinita della docstring della funzione viene visualizzata in cima all'elenco degli argomenti. Questo è ottimo, tuttavia la formattazione iniziale è persa. Si veda, ad esempio, il seguente script di esempio

import argh 

def func(foo=1, bar=True): 
    """Sample function. 

     Parameters: 
      foo: float 
       An example argument. 
      bar: bool 
       Another argument. 
    """ 
    print foo, bar 

argh.dispatch_command(func, argv=['-h']) 

che comporterebbe il seguente output

usage: script.py [-h] [-f FOO] [-b] 

Sample function. Parameters: foo: float An example argument. bar: bool Another 
argument. 

optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO 
    -b, --bar 

C'è un (facile) modo per ottenere un output simile al seguente?

usage: script.py [-h] [-f FOO] [-b] 

Sample function. 

    Parameters: 
     foo: float 
      An example argument. 
     bar: bool 
      Another argument. 

optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO 
    -b, --bar 

Preferirei non usare le annotazioni per definire i messaggi tesi di aiuto dal momento che mi richiederebbe di modificare sia docstring della funzione e il testo di aiuto ogni volta che c'è qualcosa per cambiare.

risposta

5

Non ho familiarità con argh, ma a quanto pare è un wrapper per argparse. La mia ipotesi è che sta prendendo la tua funzione __doc__ e rendendola la description di un parser, ad es.

parser = argparse.ArgumentParser(description=func.__doc__) 

https://docs.python.org/2.7/library/argparse.html#argparse.RawDescriptionHelpFormatter

argparse ha una RawDescriptionHelpFormatter che visualizza la descrizione come è.

parser = argparse.ArgumentParser(description=func.__doc__, 
    formatter_class=argparse.RawDescriptionHelpFormatter) 

Quindi la domanda è: esiste un modo di ottenere argh per utilizzare questo formattatore?

Questo script argparse produce l'aiuto che si desidera:

import argparse 

def func(foo=1, bar=True): 
    """Sample function. 

     Parameters: 
      foo: float 
       An example argument. 
      bar: bool 
       Another argument. 
    """ 
    print foo, bar 

parser = argparse.ArgumentParser(prog='script.py', 
    description=func.__doc__, 
    formatter_class=argparse.RawDescriptionHelpFormatter) 
parser.add_argument('-f', '--foo', type=float) 
parser.add_argument('-b', '--bar', action='store_false') 
parser.print_help() 

In argh/dispatching.py

def dispatch_command(function, *args, **kwargs): 
    ... 
    parser = argparse.ArgumentParser(formatter_class=PARSER_FORMATTER) 
    set_default_command(parser, function) 
    dispatch(parser, *args, **kwargs) 

Così si potrebbe entrambi i set:

PARSER_FORMATTER = argparse.RawDescriptionHelpFormatter 

o esprimere il tuo propria funzione:

def raw_dispatch_command(function, *args, **kwargs): 
    ... 
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) 
    set_default_command(parser, function) 
    dispatch(parser, *args, **kwargs) 
+0

Grazie a @hpaulj, questo risolve la mia domanda iniziale (e immedamente ne porta un'altra), perché con la modifica 'PARSER_FORMATTER = argparse.ArgumentDefaultsHelpFormatter' a' PARSER_FORMATTER = argparse.RawDescriptionHelpFormatter' Perdo la possibilità di visualizzare i miei valori predefiniti . C'è un modo per avere entrambi, cioè conservare la formattazione e vedere i valori predefiniti accanto agli argomenti facoltativi? Inoltre, se 'ArgumentDefaultsHelpFormatter' è il valore predefinito di' PARSE_FORMATTER', perché non vedo i valori 'foo = 1' e' bar = True' nel messaggio di aiuto del mio esempio? – nilfisque

+0

In 'constants.py',' PARSER_FORMATTER = argparse.ArgumentDefaultsHelpFormatter'. Questo formattatore include i valori predefiniti nelle linee guida. Quindi con il cambiamento ottieni una caratteristica e ne perdi un'altra. Probabilmente devi costruire la tua classe di formattazione per ottenere entrambe le funzionalità. – hpaulj

+0

Grazie, seguendo il consiglio di [qui] (https://stackoverflow.com/questions/18462610/argumentaparser-epilog-and-description-formatting-in-conjunction-with-argumentdef) si può effettivamente generare una classe che eredita da entrambi i formattatori e dovrebbe risultare in una combinazione di entrambi. Tuttavia, è strano che nessun valore di default venga stampato anche con l'originale 'PARSER_FORMATTER = argparse.ArgumentDefaultsHelpFormatter'. – nilfisque

0

quanto riguarda la questione di ottenere valori di default nelle linee di aiuto, questo script argparse combina le classi 2 formattatore

import argparse 

def func(foo=1, bar=True): 
    ... 
    """ 
    print foo, bar 

class MyFormatter(argparse.RawDescriptionHelpFormatter, 
    argparse.ArgumentDefaultsHelpFormatter): 
    pass 

parser = argparse.ArgumentParser(prog='script.py', 
    description=func.__doc__, 
    formatter_class=MyFormatter) 
parser.add_argument('-f', '--foo', type=float, default=1, help='test') 
parser.add_argument('-b', '--bar', action='store_false', help='test') 
parser.print_help() 

produrre

usage: script.py [-h] [-f FOO] [-b] 

Sample function. 
    ... 
optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO test (default: 1) 
    -b, --bar   test (default: True) 

Per ottenere le impostazioni predefinite del linee guida Devo includere del testo (qui 'test') nella linea di aiuto originale.

In argh, potrebbe essere necessario utilizzare le annotazioni per fornire il testo della guida.

Se si utilizza annotazioni, si dà aiutare linee con $(default)s:

parser = argparse.ArgumentParser(prog='script.py', 
    description=func.__doc__, 
    formatter_class=argparse.RawDescriptionHelpFormatter) 
parser.add_argument('-f', '--foo', type=float, default=1, help='default: %(default)s') 
parser.add_argument('-b', '--bar', action='store_false', help='default: %(default)s') 
+0

Dato che è piuttosto lungo, ho fornito una risposta separata in cui sono riuscito a ottenere il comportamento desiderato. – nilfisque

3

Con l'aiuto di @hpaulj sono finalmente riuscito a ottenere il comportamento desiderato. Per facilitare questo ho definito un decoratore personalizzato simile a argh.arg, con l'obiettivo di non dover scrivere @argh.arg(‘—param’, help=“%(default)s”) per ogni parametro separatamente, ma invece di utilizzare solo una @arg_custom() decoratore sulla mia funzione:

def arg_custom(): 
    from argh.constants import ATTR_ARGS 
    from argh.assembling import _get_args_from_signature, _fix_compat_issue29 

    def wrapper(func): 
     declared_args = getattr(func, ATTR_ARGS, []) 
     for a in list(_get_args_from_signature(func)): 
      declared_args.insert(0, dict(option_strings=a['option_strings'], help="(default: %(default)s)")) 
     setattr(func, ATTR_ARGS, declared_args) 
     _fix_compat_issue29(func) 
     return func 
    return wrapper 

Il punto cruciale ecco che un ciclo for si preoccupa che tutti gli argomenti abbiano un'opzione help=“%(default)s” corrispondente. Insieme cambiando le linee corrispondenti a argh/constants.py

class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter): 
     pass 
PARSER_FORMATTER = CustomFormatter 

possiamo convenientemente utilizzare

@arg_custom() 
def func(foo=1, bar=True): 
    """Sample function. 

     Parameters: 
      foo: float 
       An example argument. 
      bar: bool 
       Another argument. 
    """ 
    print foo, bar 

argh.dispatch_command(func) 

ottiene infine

usage: script.py [-h] [-f FOO] [-b] 

Sample function. 

     Parameters: 
      foo: float 
       An example argument. 
      bar: bool 
       Another argument. 


optional arguments: 
    -h, --help   show this help message and exit 
    -f FOO, --foo FOO (default: 1) 
    -b, --bar   (default: True) 

durante l'esecuzione dello script con l'opzione -h.

0

Grazie per il vostro interesse nella libreria Argh. Le soluzioni discusse qui saranno incorporate nella prossima versione (argh ≥ 0,25). Vedi anche lo issue #64 (già risolto).